/*
 * 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.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.maps.IlvAreaOfInterest;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.beans.IlvJAreaOfInterestPanel;
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.graphic.style.IlvPolylineStyle;
import ilog.views.maps.label.IlvMapLabelStyle;
import ilog.views.maps.label.IlvMapLabeler;
import ilog.views.maps.label.IlvMapLabelerProperty;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvProjectedCoordinateSystem;
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 LabelDemo 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);
  }

  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 JTabbedPane tabPane;
  private IlvMapLayer shpLayer;
  private IlvAreaOfInterest areaOfInterest;
  private IlvJAreaOfInterestPanel areaPanel;
  private IlvMapLabeler labeler;

  /**
   * Constructs a Label Demo.
   */
  public LabelDemo() {
    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
        // 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();

        // 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(1f / 1000f, (float) (1 / 1E5));
        limiter.setView(view);
        // setup coordinate system panel to change projection.
        csPanel.setCoordinateSystem(IlvCoordinateSystemProperty.GetCoordinateSystem(view.getManager()));
        // Add a listener on the coordinate system panel.
        // When the coordinate system changes, set the coordinate system
        // property
        // of the manager accordingly, remove all objects in the manager,
        // restart the data source and starts a new labeling.
        csPanel.addCoordinateSystemChangeListener(new PropertyChangeListener() {
          Override
          public void propertyChange(PropertyChangeEvent evt) {
            IlvCoordinateSystem system = (IlvCoordinateSystem) evt.getNewValue();

            if (system instanceof IlvProjectedCoordinateSystem) {// JV-4401 and
                                                                 // JV-4510 -
                                                                 // change
                                                                 // center of
                                                                 // projection
                                                                 // to the
                                                                 // correct area
              IlvProjectedCoordinateSystem pcs = (IlvProjectedCoordinateSystem) system;
              boolean change = false;
              if (pcs.getProjection().getCentralMeridian() == 0) {
                pcs.getProjection().setCentralMeridian(Math.toRadians(-122));
                change = true;
              }
              if (pcs.getProjection().getCentralParallel() == 0) {
                pcs.getProjection().setCentralParallel(Math.toRadians(37));
                change = true;
              }
              if (change) {
                csPanel.setCoordinateSystem(pcs);
                return;
              }
            }
            // change coordinate system of the map according to panel's
            // selection
            getView().getManager().setNamedProperty(new IlvCoordinateSystemProperty(system));
            // erase existing data in manager, and reload sources.
            removeAllObjects();
            try {
              fit();
              reloadData();
            } catch (Exception e) {
              e.printStackTrace();
            }
            performLabeling();
          }
        });

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

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

        tabPane = new JTabbedPane();
        csPanel.setAdvancedPanelsVisible(false);
        tabPane.addTab("Map Layers", layerTreePanel); //$NON-NLS-1$ // should
                                                      // be I18N
        tabPane.addTab("Coordinate System", csPanel);//$NON-NLS-1$ // should be
                                                     // I18N

        areaPanel = new IlvJAreaOfInterestPanel(getView(), true, true, true);
        tabPane.addTab("Areas", new JScrollPane(areaPanel));//$NON-NLS-1$ //
                                                            // should be I18N

        splitPane.setLeftComponent(tabPane);

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

        IlvRect sf = new IlvRect(-2.137448f, 0.6585128f, 0.0009102f, 0.00039473f);
        areaOfInterest = new IlvAreaOfInterest("SF", sf, 0, null);//$NON-NLS-1$ //
                                                                  // should be
                                                                  // I18N
        loadData();
        shpLayer.getStyle().setLabelAttribute(shpLayer.getStyle().getAttributeInfo().getAttributeName(0));
        layerTreePanel.getLayerTree().setAllowDelete(false);
      }
    });
  }

  IlvManagerView getView() {
    return view;
  }

  /**
   * Reloads the data after a coordinate system change. The data sources are
   * reset and reloaded.
   * 
   * @throws Exception
   */
  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());
          }
        }
      }
    }
  }

  /**
   * Creates a map. All map creation steps are performed here.
   */
  void loadData() {
    String file = "data/roads.shp";//$NON-NLS-1$
    URL shpFile = LabelDemo.class.getResource(file);
    // file = new File(file).getAbsolutePath();
    try {
      // create a data source for the shape file
      IlvShapeDataSource shpDataSource = new IlvShapeDataSource(shpFile, true);
      shpDataSource.setCoordinateSystem(IlvGeographicCoordinateSystem.WGS84);
      shpDataSource.setManager(view.getManager());

      // 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
      shpLayer = shpDataSource.getInsertionLayer();
      shpLayer.setName("Shape Layer (roads.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);
      // setup the shape layer style
      shpLayer.getStyle().setAttribute(IlvPolylineStyle.FOREGROUND, Color.blue);
      getLabeler().addLayer(shpLayer);

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

  void performLabeling() {
    getLabeler().performLabeling();
  }

  IlvMapLabeler getLabeler() {
    if (labeler == null) {
      labeler = IlvMapLabelerProperty.GetMapLabeler(getView().getManager());
      labeler.setView(getView());
    }
    return labeler;
  }

  IlvMapLabelStyle getLabelStyle() {
    return (IlvMapLabelStyle) getLabeler().getLabelLayer(null).getStyle();
  }

  void fit() {
    areaOfInterest.zoomTo(getView());
  }

  /**
   * 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("Label sample");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        LabelDemo demo = new LabelDemo();
        frame.getContentPane().add(demo);
        frame.pack();
        frame.setVisible(true);
      }
    });
  }

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

}