/*
 * Licensed Materials - Property of Rogue Wave Software, Inc. 
 * © Copyright Rogue Wave Software, Inc. 2014, 2015 
 * © Copyright IBM Corp. 2009, 2014
 * © Copyright ILOG 1996, 2009
 * All Rights Reserved.
 *
 * Note to U.S. Government Users Restricted Rights:
 * The Software and Documentation were developed at private expense and
 * are "Commercial Items" as that term is defined at 48 CFR 2.101,
 * consisting of "Commercial Computer Software" and
 * "Commercial Computer Software Documentation", as such terms are
 * used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
 * as applicable.
 */


import ilog.views.IlvManager;
import ilog.views.IlvManagerLayer;
import ilog.views.IlvManagerView;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.beans.IlvMapLayer;
import ilog.views.maps.beans.IlvMapLayerTreeModel;
import ilog.views.maps.datasource.DataSourceEvent;
import ilog.views.maps.datasource.DataSourceListener;
import ilog.views.maps.datasource.IlvMapDataSource;
import ilog.views.maps.datasource.IlvMapDataSourceModel;
import ilog.views.maps.datasource.IlvMapDataSourceNode;
import ilog.views.maps.datasource.IlvMapDataSourceProperty;
import ilog.views.maps.defense.format.cadrg.IlvCADRGCoverageList;
import ilog.views.maps.defense.format.cadrg.IlvRasterCADRGReader;
import ilog.views.maps.format.cadrg.IlvCADRGCoverage;
import ilog.views.maps.format.cadrg.IlvCADRGTocReader;
import ilog.views.maps.graphic.style.IlvMapCompositeStyle;
import ilog.views.maps.raster.IlvRasterSubsamplingLoader;
import ilog.views.maps.raster.datasource.IlvRasterDataSourceFactory;
import ilog.views.maps.raster.datasource.IlvThreadMonitoringData;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.maps.theme.IlvMapStyleController;
import ilog.views.maps.theme.IlvMapStyleControllerProperty;
import ilog.views.swing.IlvThreadedActivityMonitor;
import ilog.views.swing.IlvThreadedActivityMonitorProperty;
import ilog.views.tiling.IlvThreadedTileLoader;
import ilog.views.tiling.IlvTileLoader;
import ilog.views.tiling.IlvTiledLayer;
import ilog.views.util.IlvProductUtil;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.net.URL;
import java.util.Enumeration;

import javax.swing.JApplet;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.filechooser.FileFilter;

/**
 * This class shows how to read and display CADRG images
 * with Rogue Wave JViews.
 */
public class CADRGViewer extends JApplet {
  {
    // This sample uses JViews Maps for Defense features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Rogue Wave JViews Maps for Defense Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(
        IlvProductUtil.JViews_Maps_for_Defense_Deployment);
  }

  private IlvManager manager;
  private IlvManagerView mgrview;
  private IlvCADRGTocReader tocReader = null;
  private boolean _withMenuBar; // is this viewer with a menu bar ?
  // ----------------------------------------------
  // The following objects are used for the AWT GUI
  // ----------------------------------------------
  // The frame for the main window.

  private MyPanel panel = null;
  private boolean isApplet;
  
  private final class FitViewWhenDataSourceLoaded implements DataSourceListener {
    public void dataSourceLoaded(DataSourceEvent event) {
        final IlvMapDataSource src=event.getDataSource();
        mgrview.fitTransformerToContent();             
        IlvMapStyleController themeController = IlvMapStyleControllerProperty.GetMapStyleController(mgrview.getManager());
        themeController.setView(mgrview);
        themeController.updateCurrentTheme();
        mgrview.repaint();
        src.removeDataSourceListener(this);
    }
  }

  private static final class CADRGTocFilter extends FileFilter {
    /**
     * @see javax.swing.filechooser.FileFilter#accept(java.io.File)
     */
    public boolean accept(File f) {
      return f.isDirectory() || f.getName().equalsIgnoreCase("a.toc"); //$NON-NLS-1$
    }
    /**
     * @see javax.swing.filechooser.FileFilter#getDescription()
     */
    public String getDescription() {
      return "CADRG Table of content (*.toc file)"; // should be translated //$NON-NLS-1$
    }
  }
  
  class MyPanel extends ViewerPanel {
    /**
     * Creates a viewer panel using CADRG file filter.
     */
    public MyPanel() {
      super(isApplet, true, null);
      if (!_withMenuBar)
        getMenuBar().getParent().remove(getMenuBar());
    }
    
    /**
     * Calls {@link CADRGViewer#loadFromFile(String)}
     * @see ViewerPanel#openFile()
     */
    public String openFile() {
      JFileChooser fs = getFileChooser();
      if(fs != null) {
       fs.resetChoosableFileFilters();
       fs.setSelectedFile(new File("A.TOC")); //$NON-NLS-1$
       fs.setFileFilter(new CADRGTocFilter());
      }
      String name = super.openFile();
      if (name != null)
        CADRGViewer.this.loadFromFile(name);
      return name;
    }
  }
  
  /**
   * Creates a CADRG viewer for an applet with a menu bar.
   */
  public CADRGViewer() {
    this(true, true);
  }
  
  /**
   * Creates an instance of <code>CADRGViewer</code>.
   * @param withMenuBar true to display the menu bar.
   * @param isApplet true if we are running an applet.
   */
  public CADRGViewer(boolean withMenuBar, boolean isApplet) {
    _withMenuBar = withMenuBar;
    this.isApplet = isApplet;
    // Make sure the swing construction is called in Swing event thread.
    ilog.views.util.swing.IlvSwingUtil.invokeAndWait(new Runnable() { public void run() {
    panel = new MyPanel();
    getContentPane().add(panel);
    mgrview = panel.getManagerView();
    // limit the zoom to correct scales.
    IlvMapScaleLimiter limiter = new IlvMapScaleLimiter(1f/1000f, (float) (1 / 1E9));
    limiter.setView(mgrview);
    manager = mgrview.getManager();
    clearManager();
    // Initialize view parameters.
    mgrview.setKeepingAspectRatio(true);
    manager.reDraw();
    }}); // event thread runnable
  }

  /** Returns  true if the viewer should have a menu bar.
    * @return  true if the viewer should have a menu bar.
   */
  protected boolean hasMenuBar() {
    return _withMenuBar;
  }
  
  double screenMeter = (100 / 2.54) * Toolkit.getDefaultToolkit().getScreenResolution();
  /**
   * Performs the loading of specified products.
   * @param coverages CADRG coverages to load.
   * @param lowerResolution true if those coverages are the lower resolution ones.
   * @param higherResolution true if those coverages are the higher resolution ones.
   */
  public void loadCoverages(IlvCADRGCoverage coverages[],boolean lowerResolution,boolean higherResolution) {
    String name=coverages[0].getScaleDescription().trim();
    final int scale = (int) (screenMeter * coverages[0].getVerticalResolution());
   
    IlvMapLayerTreeModel ltm = IlvMapLayerTreeProperty.GetMapLayerTreeModel(manager);
    IlvMapLayer groupLayer=new IlvMapLayer();
    groupLayer.setName(name);
    IlvMapCompositeStyle groupStyle=new IlvMapCompositeStyle();
    groupLayer.setStyle(groupStyle);
    ltm.addChild(null, groupLayer);
    // subsample images exactly as they should be:
    IlvRasterSubsamplingLoader.setImageSubsamplingFactor(1);
    // Small scale layer.
    IlvThreadedActivityMonitor mon = IlvThreadedActivityMonitorProperty.GetThreadedActivityMonitor(manager);
    for (int i = 0; i < coverages.length; i++) {
      IlvRasterCADRGReader frameReader = new IlvRasterCADRGReader();
      frameReader.addCADRGCoverage(coverages[i]);
      IlvThreadMonitoringData data = new IlvThreadMonitoringData(mon, coverages[i], "Loading CADRG "+ coverages[i].getName(), 0, 100);// should be translated //$NON-NLS-1$
      IlvMapDataSource ds = IlvRasterDataSourceFactory.buildTiledImageDataSource(manager, frameReader, false, true, data);
      String tocName=coverages[i].getTocPathName();
      ds.getInsertionLayer().setName(coverages[i].getName().substring(tocName.length()));    
     IlvMapStyleController themeControl=IlvMapStyleControllerProperty.GetMapStyleController(manager);
     float tscale=scale*4;
     if(!lowerResolution) {
      themeControl.addTheme(1f/tscale,ds.getInsertionLayer(),"Invisible");// should be translated //$NON-NLS-1$
      themeControl.getStyle(ds.getInsertionLayer(),1f/tscale).setVisibleInView(false);
     }
     tscale=scale/4;
     themeControl.addTheme(1f/tscale,ds.getInsertionLayer(),"Visible");// should be translated //$NON-NLS-1$
     themeControl.getStyle(ds.getInsertionLayer(),1f/tscale).setVisibleInView(true);
     if(!higherResolution){
       themeControl.getStyle(ds.getInsertionLayer(),1).setVisibleInView(false);
     }
     addDataSource(groupLayer,ds);
  }
  }
  
  /**
   * @param source
   */
  private void addDataSource(IlvMapLayer parent,IlvMapDataSource source) {
    // insert it in the manager's data source tree 
    IlvMapDataSourceModel dataSourceModel = IlvMapDataSourceProperty.GetMapDataSourceModel(manager);
    dataSourceModel.insert(source);
    // get the maplayer used to display that data source
    IlvMapLayer layer = source.getInsertionLayer();
    // insert it on the manager's map layer tree
    IlvMapLayerTreeModel ltm = IlvMapLayerTreeProperty.GetMapLayerTreeModel(manager);
    ltm.addChild(parent, layer);
  }
  
  /**
   * Displays a message when the file to load is not a CADRG TOC.
   */
  public void warning() {
    Object[] options = { "OK" };// should be translated //$NON-NLS-1$
    JOptionPane.showOptionDialog(this, "Not a CADRG file !", "Error", JOptionPane.OK_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]);// should be translated //$NON-NLS-1$ //$NON-NLS-2$
  }
  /**
   * Loads coverages from specified toc file.
   * Toc file is opened and a dialog allowing the selection of coverages to be
   * read is opened.
   * @param fileName TOC File to read.
   */
  public void loadFromFile(String fileName) {
    clearManager();
    // Create a toc reader
    try {
      tocReader = new IlvCADRGTocReader(fileName);
      // Get all coverage info
      IlvCADRGCoverageList list = new IlvCADRGCoverageList();
      list.addCoverages(fileName, tocReader.getCoverages());
      Integer scales[] = list.getOrderedScaleList();
      String scaleDesc[] = list.getOrderedScaleDescription();
      JPanel pane = new JPanel(new GridLayout(0, 1));
      JCheckBox box[] = new JCheckBox[scaleDesc.length];
      for (int i = 0; i < scaleDesc.length; i++) {
        box[i] = new JCheckBox(scaleDesc[i]);
        pane.add(box[i],0);
      }
      // Display a coverage chooser
      int ans = JOptionPane.showConfirmDialog(mgrview, pane, "Select coverage scales", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null);// should be translated //$NON-NLS-1$
      if (ans == JOptionPane.OK_OPTION) {
        int lowerResolution=-1;
        int higherResolution=-1;
        // compute lower resolution
        for (int i = 0; i< scaleDesc.length; i++) {
          if (box[i].isSelected()) {
            lowerResolution=i;
          }  
          if (box[i].isSelected() && higherResolution==-1) {
            higherResolution=i;
          }  
        }
        for (int i = scaleDesc.length - 1; i >= 0; i--) {// higher scales deeper
          if (box[i].isSelected()) {
            loadCoverages(list.getCoverageList(scales[i]),(i==lowerResolution),(i==higherResolution));
          }
        }
        // start reading (recusively start all data sources of this model)
        IlvMapDataSourceModel dataSourceModel = IlvMapDataSourceProperty.GetMapDataSourceModel(manager);
        dataSourceModel.start();
        // add a listener to fit and repaint the view when data source is loaded.
        Enumeration e = dataSourceModel.getEnumeration();
        while(e.hasMoreElements()) {
          IlvMapDataSourceNode node = (IlvMapDataSourceNode)e.nextElement();
          Object data=node.getUserObject();
          if(data instanceof IlvMapDataSource){
            IlvMapDataSource ds=(IlvMapDataSource)data;
            ds.addDataSourceListener(new FitViewWhenDataSourceLoaded());
            break;
          }
        }


        mgrview.setBackgroundPatternLocation(null);
      }
    } catch (Exception e) {
      warning();
    }
  }
  /**
   * Removes all layers from a manager and clear the associated model
   */
  private void clearManager() {
    IlvMapLayerTreeModel model = IlvMapLayerTreeProperty.GetMapLayerTreeModel(manager);
    model.clearAllObjects();
    while (manager.getLayersCount() > 0) {
      IlvManagerLayer layer = manager.getManagerLayer(0);
      if (layer instanceof IlvTiledLayer) {
        IlvTileLoader loader = ((IlvTiledLayer) layer).getTileLoader();
        if (loader instanceof IlvThreadedTileLoader) {
          ((IlvThreadedTileLoader) loader).dispose();
        }
      }
      manager.removeLayer(0, false);
    }
    manager.removeNamedProperty(IlvMapLayerTreeProperty.NAME);
    manager.removeNamedProperty(IlvMapDataSourceProperty.NAME);
    try {
      URL patternUrl = CADRGViewer.class.getResource("data/nodata.jpg"); //$NON-NLS-1$
      mgrview.setBackgroundPatternLocation(patternUrl);
    } catch (Exception e) {
      e.printStackTrace();
    }
    // georeference manager
    manager.setNamedProperty(new IlvCoordinateSystemProperty(IlvGeographicCoordinateSystem.WGS84));
  }

  /**
   * The main function of the sample.
   * @param args ignored argument.
   */
  public static void main(final String[] args) {
    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    javax.swing.SwingUtilities.invokeLater(
      new Runnable() {
        public void run() {
          final JFrame frame = new JFrame("Rogue Wave JViews CADRG Viewer");// should be translated //$NON-NLS-1$
          final CADRGViewer viewer = new CADRGViewer(true, false);
          frame.getContentPane().add(viewer);
          frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
              if (viewer.hasMenuBar())
                System.exit(0);
              else {
                viewer.clearManager();
                frame.setVisible(false);
              }
            }
          });
      
          frame.pack();
          frame.setVisible(true);
          // Read table of contents of CADRG.
          if (args.length >= 1)
            viewer.loadFromFile(args[0]);
         }
      }
      );
  }
  //JV-3814
  Override
  public void destroy() { 
    super.destroy(); 
    // This method is intended to workaround memory management issues 
    // in the Sun JRE. Please refer to the method documentation for more 
    // details and a description of the known issues. 
    ilog.views.util.swing.IlvSwingUtil.cleanupApplet(); 
  } 


}