/*
 * 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 java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URL;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.tree.DefaultMutableTreeNode;

import ilog.views.IlvGrapher;
import ilog.views.IlvManagerView;
import ilog.views.IlvRect;
import ilog.views.maps.IlvAreaOfInterest;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.beans.IlvJCoordinateSystemEditorPanel;
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.datasource.IlvShapeDataSource;
import ilog.views.maps.format.image.IlvRasterBasicImageReader;
import ilog.views.maps.graphic.IlvMapSelectionFactory;
import ilog.views.maps.graphic.style.IlvMapStyleBeanInfo;
import ilog.views.maps.graphic.style.IlvPolylineStyle;
import ilog.views.maps.raster.datasource.IlvRasterDataSourceFactory;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.swing.IlvJScrollManagerView;
import ilog.views.util.IlvProductUtil;

/**
 * Code sample showing how to build a Map using the API.
 */
SuppressWarnings("serial")
public class BuildMapDemo extends JRootPane {

  {
    // 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 arond the map view
  IlvJMapsManagerViewControlBar viewToolbar; // zoom & selection toolbar
  IlvLayerTreePanel layerTreePanel = new IlvLayerTreePanel(); // layer
                                                              // visibility and
                                                              // props. control
  IlvJCoordinateSystemEditorPanel csPanel;// coordinate system choice.
  IlvJMouseCoordinateViewer locator;// coordinate information

  /**
   * Constructs a BuildMapDemo
   * 
   */
  public BuildMapDemo() {
    super();
    // Make sure the swing construction is called in Swing event thread.
    ilog.views.util.swing.IlvSwingUtil.invokeAndWait(new Runnable() { Override
    public void run() {
    // create the main components
    view = new IlvManagerView();
    view.setManager(new IlvGrapher());
    viewScroll = new IlvJScrollManagerView(view);
    viewToolbar = new IlvJMapsManagerViewControlBar();
    csPanel = new IlvJCoordinateSystemEditorPanel();
    csPanel.setAdvancedPanelsVisible(false);
    // Setup the components
    viewToolbar.setView(view);
    locator = new IlvJMouseCoordinateViewer();
    locator.setView(view);
    viewToolbar.add(locator);
    view.setKeepingAspectRatio(true);
    view.setBackground(new Color(80, 180, 240));
    view.setAntialiasing(false);
    view.setSize(new Dimension(900, 450));
    viewScroll.setPreferredSize(view.getSize());
    layerTreePanel.setView(view);
    // limit the zoom to correct scales.
    IlvMapScaleLimiter limiter = new IlvMapScaleLimiter((float) (1 / 1E7), (float) (1 / 1E9));
    limiter.setView(view);
    IlvMapStyleBeanInfo.setAdvancedMode(true);
    JPanel panel = new JPanel();
    panel.setLayout(new BorderLayout());
    // configure the main window
    panel.add(viewToolbar, BorderLayout.NORTH);
    panel.add(viewScroll, BorderLayout.CENTER);
    JTabbedPane tabPane = new JTabbedPane();
    tabPane.addTab("Map layers", layerTreePanel); //$NON-NLS-1$
    tabPane.addTab("Coordinate System", csPanel); //$NON-NLS-1$
    panel.add(tabPane, BorderLayout.LINE_START);
    panel.add(locator, BorderLayout.SOUTH);
    getContentPane().add(panel, BorderLayout.CENTER);
    // JV-2852: prevent editing/moving around map assets
    view.getManager().setSelectionFactory(new IlvMapSelectionFactory());
    // geo reference the view
    view.getManager().setNamedProperty(new IlvCoordinateSystemProperty(IlvGeographicCoordinateSystem.WGS84));
    // setup coordinate system panel to change projection.
    csPanel.setCoordinateSystem(IlvCoordinateSystemProperty.GetCoordinateSystem(view.getManager()));
    csPanel.addCoordinateSystemChangeListener(new PropertyChangeListener() {
      Override
      public void propertyChange(PropertyChangeEvent evt) {
        IlvCoordinateSystem system = (IlvCoordinateSystem) evt.getNewValue();
        // change coordinate system of the map according to panel's selection
        view.getManager().setNamedProperty(new IlvCoordinateSystemProperty(system));
        // and reload sources.
        try {
          reloadData();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
      private void reloadData() throws Exception {
        IlvMapDataSourceModel dsm = IlvMapDataSourceProperty.GetMapDataSourceModel(view.getManager());
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) dsm.getRoot();
        int count = root.getChildCount();
        for (int i = 0; i < count; i++) {
          DefaultMutableTreeNode node = (DefaultMutableTreeNode) root.getChildAt(i);
          IlvMapDataSource source = (IlvMapDataSource) node.getUserObject();
          source.reset();
          source.start();
        }
        // if projection change, show the whole world.
        IlvAreaOfInterest worldArea = new IlvAreaOfInterest("World",new IlvRect(-Math.PI,-Math.PI/2,2*Math.PI,Math.PI),0,null); //$NON-NLS-1$
        worldArea.zoomTo(view);
      }
    });
    // build map.
    loadData();
    }});// event thread runnable
  }

  /**
   * Creates a map. All map creation steps are performed here.
   */
  private void loadData() {
    URL shpFile = BuildMapDemo.class.getResource("data/World_Countries.shp"); //$NON-NLS-1$
    URL gifFile = BuildMapDemo.class.getResource("data/World.gif"); //$NON-NLS-1$
    try {
      // create a data source for the shape file
      IlvShapeDataSource shpDataSource = new IlvShapeDataSource(shpFile, true);
      shpDataSource.setCoordinateSystem(IlvGeographicCoordinateSystem.WGS84);
      // create a raster reader for the gif file (necessary to create a
      // datasource below)
      IlvRasterBasicImageReader imageReader = new IlvRasterBasicImageReader();
      imageReader.addMap(gifFile);
      // georeference this image (it covers the whole earth)
      imageReader.setImageBounds(0, -Math.PI, Math.PI / 2, Math.PI, -Math.PI / 2);
      // create a datasource for the gif file.
      IlvMapDataSource imageDataSource = IlvRasterDataSourceFactory.buildTiledImageDataSource(view.getManager(), imageReader, true, true, null);
      // insert it in the manager's data source tree
      IlvMapDataSourceModel dataSourceModel = IlvMapDataSourceProperty.GetMapDataSourceModel(view.getManager());
      dataSourceModel.insert(shpDataSource);
      dataSourceModel.insert(imageDataSource);
      // start reading (recusively start all data sources of this model)
      dataSourceModel.start();
      // get the shape maplayer used to display that data source
      IlvMapLayer shpLayer = shpDataSource.getInsertionLayer();
      shpLayer.setName("ESRI layer (world.shp)"); //$NON-NLS-1$
      IlvMapLayer imageLayer = imageDataSource.getInsertionLayer();
      // insert it on the manager's map layer tree
      IlvMapLayerTreeModel ltm = IlvMapLayerTreeProperty.GetMapLayerTreeModel(view.getManager());
      ltm.addChild(null, shpLayer);
      ltm.addChild(null, imageLayer);
      // setup the shape layer style
      shpLayer.getStyle().setAttribute(IlvPolylineStyle.FOREGROUND, Color.black);
      shpLayer.getStyle().setAttribute(IlvPolylineStyle.BACKGROUND, new Color(1, 1, 1, 0.25f));
      imageLayer.setName("Image layer (world.gif)"); //$NON-NLS-1$
    } catch (Exception e1) {
      e1.printStackTrace();
    }
    // fit the view
    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);
          BuildMapDemo app = new BuildMapDemo();
          frame.getContentPane().add(app);
          frame.setTitle("Simple Map Building Demo"); //$NON-NLS-1$
          frame.pack();
          frame.setVisible(true);
        }
      }
      );
  }
}