/*
 * 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.IlvGraphic;
import ilog.views.IlvManagerLayer;
import ilog.views.IlvManagerView;
import ilog.views.IlvPoint;
import ilog.views.interactor.IlvSelectInteractor;
import ilog.views.maps.IlvAttributeProperty;
import ilog.views.maps.IlvMapInputStream;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.attribute.IlvDoubleAttribute;
import ilog.views.maps.beans.IlvLayerTree;
import ilog.views.maps.beans.IlvMapLayer;
import ilog.views.maps.beans.IlvScaleBar;
import ilog.views.maps.graphic.style.IlvMapStyle;
import ilog.views.maps.label.IlvMapLabelFactory;
import ilog.views.maps.label.IlvMapLabeler;
import ilog.views.maps.label.IlvMapLabelerProperty;
import ilog.views.maps.label.IlvMapLabelingLabel;
import ilog.views.util.IlvImageUtil;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Formatter;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

import shared.BaseDemo;
import shared.MapBuilder;
import shared.ui.AdvancedTabbedPane;

/**
 * This example shows how to extend or restrict the map builder
 * 
 * @since JViews 7.5
 */
public class ExtensionDemo extends MapBuilder {

  /**
   * Specific labelling factory to show both the currently selected labelling property and "POP" if it exists.
   * @since JViews 8.1
   */
  static class MyLabelFactory implements IlvMapLabelFactory {
    private final IlvMapLabeler labeler;

    private MyLabelFactory(IlvMapLabeler labeler) {
      this.labeler = labeler;
    }

    public IlvMapLabelingLabel[] getGisLabel(IlvGraphic comp) {
      IlvManagerView pview = labeler.getView();
      if (pview == null)
        return null;
      IlvAttributeProperty properties = (IlvAttributeProperty) comp.getNamedProperty(IlvAttributeProperty.NAME);
      // find the selected "labeling" attribute
      IlvManagerLayer layer = pview.getManager().getManagerLayer(comp);
      IlvMapLayer mLayer = (layer !=null) ? IlvMapLayer.get(layer) : null;
      IlvMapStyle style = (mLayer != null) ? mLayer.getStyle() : null;
      String attributeName = (style != null) ? style.getLabelAttribute() : null;
      String message=""; //$NON-NLS-1$
      if (properties != null) {
        Object o = null;
        if (attributeName != null && !attributeName.equals("POP")) {//$NON-NLS-1$
          try {
            o = properties.getValue(attributeName);
          } catch (IllegalArgumentException e) {
            // Attribute not found
          }
          if (o != null)
            message += o.toString();
        }
        try {
          o = properties.getValue("POP");//$NON-NLS-1$
        } catch (IllegalArgumentException e) {
          // Attribute not found
        }
        // show and format population
        if (o instanceof IlvDoubleAttribute) {
          Object s=new Formatter().format(" [Pop %,.0f]",new Double(((IlvDoubleAttribute)o).getValue()));//$NON-NLS-1$
          message += s;
        }
      }
      if (message.length() != 0) {
        return labeler.createLabels(comp, message);
      }
      return null;
    }
  }
  /* Specific extension view */
  JPanel myView;
  /* sample additional menu */
  JMenu myMenu;
  /* sample additional menu item */
  JMenuItem myAction;
  /* sample additional popup menu item */
  JMenuItem myPopupAction;
  /* sample additional menu on the layer tree */
  JMenuItem myLayerMenu;
  /* sample additional tabbed pane on the right */
  AdvancedTabbedPane myTabbedPane;
  /** default constructor
   */
  public ExtensionDemo() {
    this(true);
  }
  /** Overridden method to change the menu buttons available to the user 
   * @param isApplet
   */
  public ExtensionDemo(boolean isApplet) {
    super(isApplet);
    // Make sure the swing construction is called in Swing event thread.
    ilog.views.util.swing.IlvSwingUtil.invokeAndWait(new Runnable() { public void run() {
    try {
    /*
     * MapBuilder defines the following option menu buttons: 
     * tripleBuffered 
     * antiAliased 
     * showToolTips 
     * showGUIToolTips 
     * advancedProperties 
     * selectSystem 
     * additionalViews
     * 
     * MapBuilder defines the following file menu buttons: 
     * importBtn 
     * lastFilesMenu 
     * loadBtn saveBtn 
     * clearBtn 
     * exportBtn 
     * exitBtn
     */
    // hide some buttons
    lastFilesMenu.setVisible(false);
    loadBtn.setVisible(false);
    saveBtn.setVisible(false);
    clearBtn.setVisible(false);
    exportBtn.setVisible(false);
    tripleBuffered.setVisible(false);
    
    // hide the option menu.
    optionMenu.setVisible(false);
    
    // add a specific menu.
    myMenu = new JMenu("More"); //$NON-NLS-1$ should be externalized, but lets keep code simple.
    myAction = new JMenuItem("My Action...");//$NON-NLS-1$ should be externalized, but lets keep code simple.
    myMenu.add(myAction);
    myAction.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(view, "My Action executed");//$NON-NLS-1$ should be externalized, but lets keep code simple.
      }     
    });
    getJMenuBar().add(myMenu);
    IlvMapScaleLimiter limiter = new IlvMapScaleLimiter((float) (1 / 1E2), (float) (1 / 1E9));
    limiter.setView(view);
    // Add a listener on the view to see which graphical object is clicked 
    view.addMouseListener(new MouseAdapter() {
      public void mouseReleased(MouseEvent event) {
        if(event.isPopupTrigger()){
          return;
        }
        if (getView().getInteractor() == null || getView().getInteractor() instanceof IlvSelectInteractor) {
          Point pt = event.getPoint();
          // Find component located at point pt
          IlvGraphic graphic = getView().getManager().getObject(new IlvPoint(pt.x, pt.y), getView());
          if (graphic != null) {
            JOptionPane.showMessageDialog(getView(), "Clicked on " + graphic);//$NON-NLS-1$ should be externalized, but lets keep code simple.
          }
        }
      }
    });
    myPopupAction = new JMenuItem("My Popup action...");//$NON-NLS-1$ should be externalized, but lets keep code simple.
    // add a menu to the popup menu.
    viewPopupMenu.add(myPopupAction);
    myPopupAction.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        JOptionPane.showMessageDialog(view, "My Popup action executed");//$NON-NLS-1$ should be externalized, but lets keep code simple.
      }     
    });
    // set up the layer tree.
    setupLayerTree();
    
    // remove buttons from the toolbar
    int maxBtns = 8;
    while (toolbar.getComponentCount() > maxBtns) {
      toolbar.remove(toolbar.getComponent(maxBtns));
    }
    
    /* MapBuilder defines the following status bar components:
     * graphicScale 
     * scaleControl 
     * coordViewer 
     * monitorPanel   
     */
    // remove some components from the status bar
    scaleControl.setVisible(false);
    monitorPanel.setVisible(false);
    
    // customize the coord viewer and graphic scale
    coordViewer.setHtmlTableProperties(""); //$NON-NLS-1$
    coordViewer.setOpaque(false);
    coordViewer.setShowingAltitudes(false);
    // prevent resizing of the toolbar whenever the width becomes too small.
    // JV-3323
    coordViewer.setMinimumSize(new java.awt.Dimension(200,coordViewer.getHeight()));
    graphicScale.setScaleStyle(IlvScaleBar.SIMPLE_SCALE_BOTTOM);
    
    // customize the bottomleft panel
    getTabbedPane("BottomLeft").setTabPlacement(SwingConstants.BOTTOM); //$NON-NLS-1$
    
    // move the coord viewer and graphic scale on the toolbar
    toolbar.add(graphicScale.getParent());
    toolbar.add(coordViewer);
    
    // create a new split to place the right pane
    JSplitPane anotherSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainSplit, myTabbedPane);
    anotherSplit.setOneTouchExpandable(true);
    anotherSplit.setResizeWeight(1);
    getContentPane().add(anotherSplit, BorderLayout.CENTER);
    
    // change the view background
    view.setBackground(Color.white);
    overview.setBackground(Color.white);
    } catch (Throwable t) {
      t.printStackTrace();
    }
    }});// event thread runnable
  }
  /**
   * Set up the layer tree popup menu.
   */
  void setupLayerTree() {
    myLayerMenu = new JMenuItem("My layer action...");//$NON-NLS-1$ should be externalized, but lets keep code simple.
    // disallow any change
    final IlvLayerTree tree=layerTreePanel.getLayerTree();
    tree.setShowAllLayersMenu(false);
    tree.setShowNewLayerMenu(false);
    tree.setShowHideLayerMenu(false);
    tree.setShowDeleteLayerMenu(false);
    tree.setAllowDrag(false);
    tree.setAllowDelete(false);
    tree.setAllowRename(false);
    
    // add a new menu invoked in the map layer tree
    tree.getPopupMenu().add(myLayerMenu);
    myLayerMenu.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        // find the selected layer
        TreePath selection = tree.getSelectionPath();
        if (selection != null) {
          DefaultMutableTreeNode node = (DefaultMutableTreeNode) selection.getLastPathComponent();
          IlvMapLayer layer = (IlvMapLayer) node.getUserObject();
          
          // display some message
          JOptionPane.showMessageDialog(getView(), "Show some information on " + layer.getName());//$NON-NLS-1$ should be externalized, but lets keep code simple.
        }
      }
    });
  }
  /** Overridden method to change the views available to the user */
  protected void initViews() {
    super.initViews();
    
    // create the sample view and panel
    myView = new JPanel();
    myView.add(new JLabel("[Custom]"));//$NON-NLS-1$ should be externalized, but lets keep code simple.
    myView.setName("my View");//$NON-NLS-1$ should be externalized, but lets keep code simple.
    myTabbedPane=new AdvancedTabbedPane();
    myTabbedPane.setName("Right"); //$NON-NLS-1$
    addTabbedPane(myTabbedPane);
    /*
     * MapBuilder defines the following views: 
     * layerTreePanel
     * advancedPanel
     * managerLayersLegend
     * mapLayersLegend
     * dataSourcePanel 
     * printPanel
     * gridPanel
     * prefsPanel
     * csPanel
     * simpleSymbologyPanel
     * overviewAndZoomPanel
     * areaPanel
     */
    
    //set the list of views to manage.
    views = new JComponent[] { myView, layerTreePanel, mapLayersLegend, overviewAndZoomPanel, areaPanel };
  }
  /** Overridden method to change the way views are organized by default */
  protected void loadPreferences() {
    /* MapBuilder defines the following panels, accessible through the getTabbedPane(String) method: 
     * "BottomLeft" 
     * "AdditionalViews" 
     * "BottomRight" 
     * "TopLeft" 
     */
    
    // put "myView" by default (if no preference file exists) in the "right" panel we created above.
    getTabbedPane("Right").addView(myView.getName(), myView, false); //$NON-NLS-1$
    super.loadPreferences();
  }
  /**
   * Overridden method to change the preference file name.
   * @return the name of the preference file.
   */
  protected String getPreferenceFileName() {
    return "Extension.settings"; //$NON-NLS-1$
  }
  /**
   * Overridden method to change formats available in the import menu.
   * @see shared.MapBuilder#getImportActionClassNames()
   */
  protected ArrayList getImportActionClassNames() {
    ArrayList list = super.getImportActionClassNames();
    
    // Remove some useless import formats
    list.remove("plugins.VMAPLoadAction"); //$NON-NLS-1$
    list.remove("plugins.DTEDAvgLoadAction"); //$NON-NLS-1$
    list.remove("plugins.DTEDMinLoadAction"); //$NON-NLS-1$
    list.remove("plugins.DTEDMaxLoadAction"); //$NON-NLS-1$
    list.remove("plugins.SDOLoadAction"); //$NON-NLS-1$
    // add my import format
    list.add("MyLoadAction");//$NON-NLS-1$
    return list;
  }
  /** Overridden method to load a different initial data */
  protected void loadInitialData() {
    // load a saved map.
    // Note: because we do not provide the initial shape files in this demo,
    // reprojection will not be possible.
    URL mapFile = findURL("data/Conus.ivl"); //$NON-NLS-1$
    try {
      // open a stream
      InputStream stream = new BufferedInputStream(mapFile.openStream());
      // Create a map input stream
      IlvMapInputStream mapInput = new IlvMapInputStream(stream, (String)null);
      // Clear current manager
      view.getManager().deleteAll(false);
      // Load the map
      mapInput.read(view.getManager());
      // close the stream
      stream.close();
      // fit the view to its new content
      view.fitTransformerToContent();
    } catch (Exception e1) {
      e1.printStackTrace();
    }
    // we indicate the map builder that it is not necessary to ask for saving this data.
    setModified(false);
    // change the label factory to show more than one attribute
    IlvMapLabeler labeler = IlvMapLabelerProperty.GetMapLabeler(view.getManager());
    labeler.getLabelManager().setLabelFactory(new MyLabelFactory(labeler));
  }
  /**
   * Main method: creates an ExtensionDemo in a JFrame.
   * @param args
   *          (ignored)
   */
  public static void main(String[] args) {
    BaseDemo.showSplashScreen();
    // 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();
          final ExtensionDemo applet = new ExtensionDemo(false);
          frame.getContentPane().add(applet);
          
          // change the frame title
          frame.setTitle("Extension Demo");//$NON-NLS-1$ should be externalized, but lets keep code simple.
          // Change the frame icon
          try {
            frame.setIconImage(IlvImageUtil.getImageFromFile(BaseDemo.class, "/icons/default_frame_icon.gif"));//$NON-NLS-1$
          } catch (IOException e1) {
            // ignore
          }
          // Manage application exit when we close its window.
          frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
          frame.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
              applet.exitApplication();
            }
          });
          frame.pack();
          frame.setVisible(true);
              }
      }
      );
  }
}