/*
 * Licensed Materials - Property of Perforce Software, Inc. 
 * © Copyright Perforce Software, Inc. 2014, 2021 
 * © 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.IlvGrapher;
import ilog.views.IlvManager;
import ilog.views.IlvManagerView;
import ilog.views.IlvTransformer;
import ilog.views.maps.IlvAreasOfInterestProperty;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.beans.IlvJAutomaticScaleBar;
import ilog.views.maps.beans.IlvJMapsManagerViewControlBar;
import ilog.views.maps.beans.IlvJMouseCoordinateViewer;
import ilog.views.maps.beans.IlvLayerTreePanel;
import ilog.views.maps.beans.IlvMapLayer;
import ilog.views.maps.beans.IlvMapLayerTreeModel;
import ilog.views.maps.datasource.IlvMapDataSource;
import ilog.views.maps.datasource.IlvMapDataSourceModel;
import ilog.views.maps.datasource.IlvMapDataSourceProperty;
import ilog.views.maps.format.dted.IlvRasterDTEDReader;
import ilog.views.maps.graphic.style.IlvMapStyleBeanInfo;
import ilog.views.maps.raster.datasource.IlvRasterDataSourceFactory;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.swing.IlvJScrollManagerView;
import ilog.views.tiling.IlvFreeTile;
import ilog.views.tiling.IlvTileController;
import ilog.views.tiling.IlvTiledLayer;
import ilog.views.util.IlvProductUtil;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.net.URL;
import java.util.Iterator;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JSplitPane;
import javax.swing.filechooser.FileFilter;

/**
 * Demo that shows the loading of DTED files using JVIews Maps API.
 */
SuppressWarnings("serial")
public class DtedDemo extends JRootPane {

  static 
  {
    // This sample uses JViews Maps features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Perforce JViews Maps Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(
        IlvProductUtil.JViews_Maps_Deployment);
  }

  IlvManagerView view;// map view
  IlvJScrollManagerView viewScroll;// scroll around the map view
  IlvJMapsManagerViewControlBar viewToolbar; // zoom & selection toolbar
  IlvLayerTreePanel layerTreePanel = new IlvLayerTreePanel(); // layer visibility and props. control
  IlvJMouseCoordinateViewer locator;// coordinate information
  JFileChooser fileChooser; // file chooser to open DTED files
  JCheckBox lodCheckBox;

  /**
   * Creates a new <code>DtedDemo</code>.
   */
  public DtedDemo() {
    super();
    // Make sure the swing construction is called in Swing event thread.
    ilog.views.util.swing.IlvSwingUtil.invokeAndWait(new Runnable() { Override
    public void run() {
    // Set raster bean info in advanced mode -> shows color model ....
    IlvMapStyleBeanInfo.setAdvancedMode(true);
    // create the main components
    view = new IlvManagerView();
    view.setManager(new IlvGrapher());
    viewScroll = new IlvJScrollManagerView(view);
    viewToolbar = new IlvJMapsManagerViewControlBar();
    // Setup the components
    viewToolbar.setView(view);
    locator = new IlvJMouseCoordinateViewer();
    locator.setView(view);
    view.setKeepingAspectRatio(true);
    view.setBackground(new Color(80, 180, 240));
    view.setAntialiasing(false);
    view.setSize(new Dimension(450, 450));
    viewScroll.setPreferredSize(new Dimension(view.getWidth() + 22, view.getHeight() + 22));
    layerTreePanel.setView(view);
    viewToolbar.addSeparator();
    try {
      fileChooser = new JFileChooser(new File(".")); //$NON-NLS-1$
      lodCheckBox = new JCheckBox("Load on demand", true); //$NON-NLS-1$ // should be I18N
      fileChooser.setAccessory(lodCheckBox);
      JButton openDTEDFilesButton = new JButton("Open DTED"); //$NON-NLS-1$ // should be I18N
      openDTEDFilesButton.addActionListener(new ActionListener() {
        Override
        public void actionPerformed(ActionEvent e) {
          openFiles();
        }
      });
      viewToolbar.add(openDTEDFilesButton);
      JButton clearManagerButton = new JButton("Clear map"); //$NON-NLS-1$ // should be I18N
      clearManagerButton.addActionListener(new ActionListener() {
        Override
        public void actionPerformed(ActionEvent e) {
          clearManager();
          // JV-2862 - reset transformer.
          view.setTransformer(new IlvTransformer());
          view.repaint();
        }
      });
      viewToolbar.add(clearManagerButton);

    } catch (SecurityException e) {
    }
    // coordinate panel (coordinates display + scale bar)
    JPanel coordPanel = new JPanel(new BorderLayout());
    IlvJAutomaticScaleBar scaleBar = new IlvJAutomaticScaleBar();
    scaleBar.setView(view);
    coordPanel.add(scaleBar, BorderLayout.EAST);
    coordPanel.add(locator, BorderLayout.CENTER);
    // geo reference the view
    view.getManager().setNamedProperty(new IlvCoordinateSystemProperty(IlvGeographicCoordinateSystem.WGS84));
    // limit the zoom to correct scales.
    IlvMapScaleLimiter limiter = new IlvMapScaleLimiter(1f / 1000f, (float) (1 / 1E9));
    limiter.setView(view);
    // build map
    URL dtedFile = DtedDemo.class.getResource("data/n48.dt0"); //$NON-NLS-1$
    //    loadFiles(new String[] { dtedFile.getPath()}, false);
    loadFiles(new URL[] { dtedFile }, false);
    // select the layer.
    layerTreePanel.getLayerTree().setSelectionRow(0);
    // setup file chooser
    // configure the main window
    getContentPane().add(viewToolbar, BorderLayout.NORTH);
    JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, layerTreePanel, viewScroll);
    getContentPane().add(split, BorderLayout.CENTER);
    getContentPane().add(coordPanel, BorderLayout.SOUTH);
    }});// event thread runnable
  }

  /**
   * Pops-up a file choosing dialog to select DTED files
   */
  public void openFiles() {
    // open file chooser dialog
    fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
    fileChooser.setMultiSelectionEnabled(true);
    fileChooser.setFileFilter(new DTEDFileFilter());
    int choice = fileChooser.showOpenDialog(this);
    if (choice != JFileChooser.APPROVE_OPTION) {
      // file choice was cancelled
      return;
    }
    // get selected files (files AND Directories)
    File[] selectedFiles = fileChooser.getSelectedFiles();
    // recurse to list all DTED files within subdirectories
    Vector<String> fileList = new Vector<String>();
    for (int i = 0; i < selectedFiles.length; i++) {
      listDTEDFiles(selectedFiles[i], fileList);
    }
    final String[] filenames = fileList.toArray(new String[0]);
    // eventually load these files
    final boolean loadOnDemand = lodCheckBox.isSelected();
    loadFiles(filenames, loadOnDemand);
  }

  /**
   * Recursive method to list dted files in subdirectories
   */
  private void listDTEDFiles(File f, Vector<String> fileList) {
    if (f.isDirectory()) {
      File[] sub = f.listFiles();
      for (int i = 0; i < sub.length; i++) {
        listDTEDFiles(sub[i], fileList);
      }
    } else if (fileChooser == null || fileChooser.getFileFilter().accept(f)) {
      fileList.add(f.getPath());
    }
  }

  /**
   * Creates a DTED datasource from the specified filenames.
   */
  private void loadFiles(String[] filenames, boolean loadOnDemand) {
    if (filenames.length == 0) {
      // no files to load            
      return;
    }
    try {
      // create a raster reader for the dted file (necessary to create a datasource below)
      IlvRasterDTEDReader DTEDReader = new IlvRasterDTEDReader();
      // add dted files to the DTED reader
      for (int i = 0; i < filenames.length; i++) {
        DTEDReader.addMap(filenames[i]);
      }
      String layerContent;
      if (filenames.length == 1) {
        layerContent = new File(filenames[0]).getName();
      } else {
        layerContent = new File(filenames[0]).getName() + "~" + new File(filenames[filenames.length - 1]).getName(); //$NON-NLS-1$
      }
      doLoadFiles(DTEDReader, loadOnDemand, layerContent);
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }

  /**
   * Creates a DTED datasource from the specified filenames.
   */
  private void loadFiles(URL[] urls, boolean loadOnDemand) {
    if (urls.length == 0) {
      // no files to load            
      return;
    }
    try {
      // create a raster reader for the dted file (necessary to create a datasource below)
      IlvRasterDTEDReader DTEDReader = new IlvRasterDTEDReader();
      // add dted files to the DTED reader
      for (int i = 0; i < urls.length; i++) {
        DTEDReader.addMap(urls[i]);
      }
      String layerContent;
      if (urls.length == 1) {
        layerContent = urls[0].toExternalForm();
      } else {
        layerContent = urls[0].toExternalForm() + "~" + urls[urls.length - 1].toExternalForm(); //$NON-NLS-1$
      }
      doLoadFiles(DTEDReader, loadOnDemand, layerContent);
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }

  void doLoadFiles(IlvRasterDTEDReader DTEDReader, boolean loadOnDemand, String layerContent)
      throws InterruptedException {
    // create a datasource for the dted reader.
    IlvMapDataSource DTEDDataSource = IlvRasterDataSourceFactory.buildTiledImageDataSource(view.getManager(),
        DTEDReader, loadOnDemand, loadOnDemand, null);
    // insert it in the manager's data source tree 
    final IlvMapDataSourceModel dataSourceModel = IlvMapDataSourceProperty.GetMapDataSourceModel(view.getManager());
    dataSourceModel.insert(DTEDDataSource);
    // start reading (recusively start all data sources of this model)
    Thread loader = new Thread() {
      Override
      public void run() {
        dataSourceModel.start();
      }
    };
    loader.start();
    loader.join();
    // get the DTED  maplayer used to display that data source
    IlvMapLayer DTEDLayer = DTEDDataSource.getInsertionLayer();
    DTEDLayer.setName("DTED layer (" + layerContent + ")"); //$NON-NLS-1$//$NON-NLS-2$ // should be I18N
    // insert it on the manager's map layer tree
    IlvMapLayerTreeModel ltm = IlvMapLayerTreeProperty.GetMapLayerTreeModel(view.getManager());
    ltm.addChild(null, DTEDLayer);
    // in load on demand, ensure that only the first tile is visible            
    if (loadOnDemand) {
      final IlvTiledLayer tiledLayer = (IlvTiledLayer) DTEDLayer.getManagerLayer();
      final IlvTileController tileController = tiledLayer.getTileController();
      Iterator<?> tiles = tileController.getTiles().iterator();
      if (tiles.hasNext()) {
        IlvFreeTile firstTile = (IlvFreeTile) tiles.next();
        tiledLayer.fitTransformerToTile(view, firstTile);
      }
      
    }
    if (!loadOnDemand) {
      // not in load on demand, we can zoom on the whole data.
      view.fitTransformerToContent();
      view.repaint();
    }
  }

  /**
   * Main method
   * @param args ignored parameter.
   */
  public static void main(String[] args) {
    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        DtedDemo demo = new DtedDemo();
        frame.getContentPane().add(demo);
        frame.setTitle("DTED demo");//$NON-NLS-1$ // should be I18N
        frame.pack();
        frame.setVisible(true);
      }
    });
  }

  /**
   * Removes all layers from a manager and clear the associated model
   */
  private void clearManager() {
    IlvManager manager = view.getManager();
    IlvMapLayerTreeModel model = IlvMapLayerTreeProperty.GetMapLayerTreeModel(manager);
    model.clearAllObjects();
    while (manager.getLayersCount() > 0) {
      manager.removeLayer(0, false);
    }
    manager.removeNamedProperty(IlvMapLayerTreeProperty.NAME);
    manager.removeNamedProperty(IlvMapDataSourceProperty.NAME);
    manager.removeNamedProperty(IlvAreasOfInterestProperty.NAME);
  }
  /**
   * Simple DTED filefilter
   * @author eaullas
   *
   */
  private static class DTEDFileFilter extends FileFilter {
    /**
     * Implementation of accept method of class FileFilter. Accept only DTED files
     * @see javax.swing.filechooser.FileFilter#accept(java.io.File)
     */
    Override
    public boolean accept(File f) {
      String filename = f.getName();
      boolean accept = f.isDirectory() || filename.endsWith(".dt0") //$NON-NLS-1$
          || filename.endsWith(".dt1") //$NON-NLS-1$
          || filename.endsWith(".dt2") //$NON-NLS-1$
          || filename.endsWith(".dt3"); //$NON-NLS-1$
      return accept;
    }

    /**
     * Return the description of files accepted by this filter
     * @see javax.swing.filechooser.FileFilter#getDescription()
     */
    Override
    public String getDescription() {
      return "DTED file (*.dt0,*.dt1,*.dt2,*.dt3)"; //$NON-NLS-1$// should be I18N
    }
  }
}