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

import javax.swing.JFrame;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.tree.DefaultMutableTreeNode;

import ilog.views.IlvGrapher;
import ilog.views.IlvManager;
import ilog.views.IlvManagerLayer;
import ilog.views.IlvManagerView;
import ilog.views.IlvRect;
import ilog.views.IlvTransformer;
import ilog.views.IlvUtil;
import ilog.views.interactor.IlvManagerMagViewInteractor;
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.IlvTiledShapeDataSource;
import ilog.views.maps.graphic.style.IlvGraphicPathStyle;
import ilog.views.maps.graphic.style.IlvMapStyle;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.swing.IlvJScrollManagerView;
import ilog.views.tiling.IlvTiledLayer;
import ilog.views.util.IlvProductUtil;

/**
 * A demo that present shape file loading with load on demand and reprojection.
 */
SuppressWarnings("serial")
public class ShapeDemo 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);
  }

  private IlvManagerView view;// map view
  private IlvJScrollManagerView viewScroll;// scroll arond the map view
  private IlvJMapsManagerViewControlBar viewToolbar; // zoom & selection toolbar
  private IlvLayerTreePanel layerTreePanel = new IlvLayerTreePanel(); // layer
                                                                      // visibility
                                                                      // and
                                                                      // props.
                                                                      // control
  private IlvJCoordinateSystemEditorPanel csPanel;// coordinate system choice.
  private IlvJMouseCoordinateViewer locator;// coordinate information
  private IlvManagerView debugView; // A debug view to see tile
                                    // loading/unloading.
  private IlvMapStyle style;

  /**
   * Constructs a Shape Demo.
   */
  public ShapeDemo() {
    super();

    // create the main components
    // Make sure the swing construction is called in Swing event thread.
    ilog.views.util.swing.IlvSwingUtil.invokeAndWait(new Runnable() {
      Override
      public void run() {

        // The view to display the maps.
        view = new IlvManagerView();
        view.setManager(new IlvGrapher());
        viewScroll = new IlvJScrollManagerView(view);
        // A control bar with commonly used interactors.
        viewToolbar = new IlvJMapsManagerViewControlBar();
        // A coordinate system editor panel to reproject the map.
        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);

        // geo reference the view
        view.getManager().setNamedProperty(new IlvCoordinateSystemProperty(IlvGeographicCoordinateSystem.WGS84));
        // limit the zoom to correct scales.
        IlvMapScaleLimiter limiter = new IlvMapScaleLimiter((float) (1 / 1E6), (float) (1 / 1E9));
        limiter.setView(view);

        // 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
            getView().getManager().setNamedProperty(new IlvCoordinateSystemProperty(system));
            try {
              reloadData();
              fit();
            } catch (Exception e) {
              e.printStackTrace();
            }
          }
        });

        // build map.
        loadData();
        JSplitPane splitPane = new JSplitPane();
        Container contentPane = getContentPane();

        // configure the main window
        contentPane.add(viewToolbar, BorderLayout.NORTH);

        JTabbedPane tabPane = new JTabbedPane();
        tabPane.addTab("Map Layers", layerTreePanel);//$NON-NLS-1$ // should be
                                                     // I18N
        tabPane.addTab("Coordinate System", csPanel);//$NON-NLS-1$ // should be
                                                     // I18N
        JScrollPane debug = new JScrollPane(getDebugView());
        tabPane.addTab("Debug View", debug);//$NON-NLS-1$ // should be I18N
        tabPane.setSelectedComponent(debug);
        splitPane.setLeftComponent(tabPane);

        splitPane.setRightComponent(viewScroll);
        contentPane.add(splitPane, BorderLayout.CENTER);

        contentPane.add(locator, BorderLayout.SOUTH);
      }
    });// event thread runnable
  }

  IlvManagerView getDebugView() {
    if (debugView == null) {
      debugView = new IlvManagerView();
      debugView.setManager(view.getManager());
      debugView.setKeepingAspectRatio(true);
      debugView.setBackground(Color.pink);
      IlvManagerMagViewInteractor interactor = new IlvManagerMagViewInteractor(view, true);
      interactor.setAutoTranslating(true);
      interactor.setDrawingStyle(IlvManagerMagViewInteractor.Wire);
      interactor.setAutoZooming(false);
      debugView.setAutoFitToContents(true);
      debugView.setInteractor(interactor);
    }
    return debugView;
  }

  /**
   * Creates a map. All map creation steps are performed here.
   * 
   * @throws MalformedURLException
   */
  private void loadData() {
    String file = "data/World.shp"; //$NON-NLS-1$
    URL shpFile = ShapeDemo.class.getResource(file);
    try {
      // create a data source for the shape file
      IlvTiledShapeDataSource shpDataSource = new IlvTiledShapeDataSource(shpFile, false);
      shpDataSource.setCoordinateSystem(IlvGeographicCoordinateSystem.WGS84);
      shpDataSource.setManager(view.getManager());
      IlvTiledLayer tiledLayer = (IlvTiledLayer) shpDataSource.getInsertionLayer().getManagerLayer();
      tiledLayer.getTileController().ignoreView(getDebugView(), true);
      tiledLayer.setDebugView(getDebugView());

      // insert it in the manager's data source tree
      IlvMapDataSourceModel dataSourceModel = IlvMapDataSourceProperty.GetMapDataSourceModel(view.getManager());
      dataSourceModel.insert(shpDataSource);

      // 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("Shape Layer (world.shp)");//$NON-NLS-1$ // should be
                                                  // I18N

      // insert it on the manager's map layer tree
      IlvMapLayerTreeModel ltm = IlvMapLayerTreeProperty.GetMapLayerTreeModel(view.getManager());
      ltm.addChild(null, shpLayer);

      if (style == null) {
        IlvGraphicPathStyle ps = new IlvGraphicPathStyle();
        ps.setForeground(Color.black);
        ps.setPaint(new Color(1, 1, 1, 0.25f));
        style = ps;
      }
      // setup the shape layer style
      shpLayer.setStyle(style);

      fit();
    } catch (Exception e1) {
      e1.printStackTrace();
    }
    // fit the view
    // view.fitTransformerToContent();
    view.repaint();
  }

  IlvManagerView getView() {
    return view;
  }

  void fit() {
    IlvRect europe = new IlvRect(IlvUtil.degreesToRadians(-5), IlvUtil.degreesToRadians(41),
        IlvUtil.degreesToRadians(13), IlvUtil.degreesToRadians(14));
    IlvAreaOfInterest a = new IlvAreaOfInterest("Europe", europe, 0, null);//$NON-NLS-1$ //
                                                                           // should
                                                                           // be
                                                                           // I18N
    a.zoomTo(getView());
    // reset debug view transformer. JV-3393
    getDebugView().setTransformer(new IlvTransformer());
    getDebugView().fitTransformerToContent();
  }

  /**
   * 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.setTitle("Shape on demand demo");//$NON-NLS-1$ // should be I18N
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        final ShapeDemo app = new ShapeDemo();
        frame.getContentPane().add(app);
        frame.pack();
        frame.setVisible(true);
      }
    });
  }

  void removeAllObjects() {
    IlvMapLayerTreeModel model = IlvMapLayerTreeProperty.GetMapLayerTreeModel(getView().getManager());
    model.clearAllObjects();
  }

  void reloadData() throws Exception {
    IlvManager manager = getView().getManager();
    IlvMapDataSourceModel dsm = IlvMapDataSourceProperty.GetMapDataSourceModel(manager);
    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();
      IlvMapLayer layer = source.getInsertionLayer();
      if (layer.getManager() == manager) { // need bug fix in framework for that
                                           // to work
        source.reset();
        source.start();
        IlvManagerLayer layers[] = layer.getManagerLayers();
        for (int l = 0; l < layers.length; l++) {
          if (layers[l] instanceof IlvTiledLayer) {
            ((IlvTiledLayer) layers[l]).getTileController().updateView(getView());
          }
        }
      }
    }
  }

}