/*
 * 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.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;
import ilog.views.util.IlvResourceUtil;

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.JApplet;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.tree.DefaultMutableTreeNode;

/**
 * A demo that present shape file loading with load on demand and reprojection. 
 */
public class ShapeDemo extends JApplet {

  static {
    // This applet is designed to run only with default resource bundle
    // and various selected other resource bundles.
    // Setting the available resource suffixes avoids that the applet
    // tries to load resource bundles for other locales over the net,
    // even if the current locale of the browser is different.
    if (IlvResourceUtil.isInApplet())
      IlvResourceUtil.setAvailableResourceSuffixes("", "_ja");  //$NON-NLS-1$//$NON-NLS-2$
  }

  {
    // This sample uses JViews Maps features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Rogue Wave 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() { 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() {
      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((float)IlvUtil.degreesToRadians(-5), 
                               (float)IlvUtil.degreesToRadians(41),
     (float)IlvUtil.degreesToRadians(13),
                               (float)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() {
        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 JApplet applet = new ShapeDemo();
          frame.getContentPane().add(applet);
          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());
          }
        }
      }
    }
  }
  //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(); 
  } 

}