/*
 * 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.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JTabbedPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.tree.DefaultMutableTreeNode;

import ilog.views.IlvGrapher;
import ilog.views.IlvGraphic;
import ilog.views.IlvManager;
import ilog.views.IlvManagerLayer;
import ilog.views.IlvManagerView;
import ilog.views.IlvManagerViewInteractor;
import ilog.views.IlvPoint;
import ilog.views.IlvRect;
import ilog.views.IlvSelection;
import ilog.views.IlvUnresizeableDrawSelection;
import ilog.views.event.InteractorChangedEvent;
import ilog.views.event.InteractorListener;
import ilog.views.graphic.IlvArrowLine;
import ilog.views.graphic.IlvHalfZoomingGraphic;
import ilog.views.graphic.IlvMarker;
import ilog.views.maps.IlvAreaOfInterest;
import ilog.views.maps.IlvAreaOfInterestVector;
import ilog.views.maps.IlvAreasOfInterestProperty;
import ilog.views.maps.IlvCoordinate;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvDMSCoordinateFormatter;
import ilog.views.maps.IlvDisplayPreferencesProperty;
import ilog.views.maps.IlvMagnifySymbolsInteractor;
import ilog.views.maps.IlvMapInputStream;
import ilog.views.maps.IlvMapLayerTreeProperty;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.IlvUTMCoordinateFormatter;
import ilog.views.maps.beans.IlvJAreaOfInterestPanel;
import ilog.views.maps.beans.IlvJCompass;
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.beans.editor.IlvCoordinatePanelFactory;
import ilog.views.maps.defense.symbology.app6a.IlvApp6aGraphic;
import ilog.views.maps.defense.symbology.app6a.IlvApp6aSymbol;
import ilog.views.maps.defense.symbology.app6a.IlvApp6aSymbologyTreeViewActions;
import ilog.views.maps.format.IlvDefaultDataPathResolver;
import ilog.views.maps.format.IlvMapDataPathManager;
import ilog.views.maps.graphic.IlvMapSelectionFactory;
import ilog.views.maps.graphic.style.IlvMapStyle;
import ilog.views.maps.grids.IlvAbstractBaseGrid;
import ilog.views.maps.grids.IlvLatLonGrid;
import ilog.views.maps.grids.IlvMGRSGrid;
import ilog.views.maps.grids.IlvMGRSGridZone;
import ilog.views.maps.projection.IlvProjectionUtil;
import ilog.views.maps.raster.datasource.IlvRasterStyle;
import ilog.views.maps.srs.coordsys.IlvCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvProjectedCoordinateSystem;
import ilog.views.maps.srs.coordtrans.IlvCoordinateTransformation;
import ilog.views.maps.srs.coordtrans.IlvCoordinateTransformationException;
import ilog.views.maps.symbology.swing.IlvSymbologyTreeView;
import ilog.views.maps.theme.IlvMapStyleController;
import ilog.views.maps.theme.IlvMapStyleControllerProperty;
import ilog.views.sdm.IlvSDMEngine;
import ilog.views.sdm.IlvSDMException;
import ilog.views.sdm.renderer.IlvRendererUtil;
import ilog.views.sdm.renderer.IlvStyleSheetRenderer;
import ilog.views.sdm.renderer.maps.IlvMapStyleSheetRenderer;
import ilog.views.swing.IlvJManagerViewControlBar;
import ilog.views.swing.IlvJManagerViewPanel;
import ilog.views.swing.IlvToolTipManager;
import ilog.views.util.IlvImageUtil;
import ilog.views.util.IlvProductUtil;
import ilog.views.util.swing.layout.IlvBetterFlowLayout;
import simulation.SimulationContext;
import simulation.SimulationController;

/**
 * This demo creates a simple map and overlays it with APP6a symbols, giving the
 * possibility to the user to start a symbol simulation.
 */
SuppressWarnings("serial")
public class App6aDemo extends JRootPane {
  static {
    // replace the stylesheet renderer with map class.
    IlvRendererUtil.addRendererAlias(IlvRendererUtil.getRendererAlias(IlvStyleSheetRenderer.class.getName()),
        IlvMapStyleSheetRenderer.class.getName());
  }

  /**
   * subclass of IlvSymbologyTreeView to provide edition of the symbol on a
   * double-click
   */
  static class MySymbologyTreeView extends IlvSymbologyTreeView {
    /**
     * Creates a new <code>MySymbologyTreeView</code>.
     * 
     * @param engine
     *          The symbology engine that displays the symbol model.
     */
    public MySymbologyTreeView(IlvSDMEngine engine) {
      super(engine);
    }

    /**
     * Performs the edition of the currently selected symbol.
     */
    public void editSelectedSymbol() {
      performEdit();
    }
  }

  {
    // This sample uses JViews Maps for Defense features. When deploying an
    // application that includes this code, you need to be in possession
    // of a Perforce JViews Maps for Defense Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(IlvProductUtil.JViews_Maps_for_Defense_Deployment);
  }
  IlvManagerView view;// map view
  IlvJManagerViewPanel viewScroll;// scroll arond the map view
  JPanel symbologyPanel = new JPanel(new BorderLayout());
  MySymbologyTreeView symbPanel; // symbol tree
  IlvJCompass compass = new IlvJCompass();
  IlvJManagerViewControlBar viewToolbar; // zoom & selection toolbar
  IlvJAreaOfInterestPanel areaOfInterestPanel;// panel for areas of interest.
  IlvJCoordinateSystemEditorPanel csPanel;// coordinate system choice.
  IlvLayerTreePanel layerTreePanel;
  IlvJMouseCoordinateViewer locator;// coordinate information
  IlvSDMEngine symbology;
  int frames;
  long lastTime;
  private JButton brightnessUpButton;
  private JButton brightnessDownButton;
  private JButton contrastUpButton;
  private JButton contrastDownButton;
  private JButton saturationUpButton;
  private JButton saturationDownButton;
  private JButton transparencyUpButton;
  private JButton transparencyDownButton;
  private JComboBox<String> gridCombo;
  private IlvManagerLayer gridLayer;

  /**
   * Constructor. creates and sets up the GUI.
   */
  public App6aDemo() {
    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() {
          Override
          public void paint(Graphics g) {
            super.paint(g);
            frames++;
          }
        };
        view.setManager(new IlvGrapher(0));
        IlvToolTipManager.registerView(view);
        viewScroll = new IlvJManagerViewPanel(view) {
          Override
          public String getToolTipText(MouseEvent event) {
            Point pt = SwingUtilities.convertPoint(this, event.getPoint(), view);
            // Find component located at point pt
            IlvGraphic o = view.getManager().getObject(new IlvPoint(pt.x, pt.y), view);
            if (o instanceof IlvHalfZoomingGraphic) {
              return getToolTip(o);
            }
            return null;
          }
        };
        viewToolbar = new IlvJMapsManagerViewControlBar();
        viewToolbar.setFloatable(false);
        IlvMagnifySymbolsInteractor magInteractor = new IlvMagnifySymbolsInteractor();
        // limit the number of iteration of the layout to increase speed.
        magInteractor.getAnnealingLabelLayout().setAllowedNumberOfIterations(1);
        IlvArrowLine lineTemplate = new IlvArrowLine();
        // setup a specific line
        lineTemplate.setForeground(Color.red);
        lineTemplate.setLineStyle(new float[] { 4, 4 });
        lineTemplate.setLineWidth(2);
        lineTemplate.setArrowPosition(1);
        // to set up a specific marker:
        IlvMarker markerTemplate = new IlvMarker();
        markerTemplate.setType(IlvMarker.IlvMarkerFilledCircle);
        markerTemplate.setForeground(Color.orange);
        markerTemplate.setSize(2);
        magInteractor.setTargetMarkerTemplate(markerTemplate);
        magInteractor.setConnectingLineTemplate(lineTemplate);
        installInteractorButton("Unclutter the symbols around the area clicked", // should//$NON-NLS-1$
                                                                                 // be
                                                                                 // translated,but
                                                                                 // for
                                                                                 // easier
                                                                                 // code,
                                                                                 // marked
                                                                                 // as
            "magnify_symbols_action_icon.gif", magInteractor); //$NON-NLS-1$
        areaOfInterestPanel = new IlvJAreaOfInterestPanel(view, true, false, false);
        csPanel = new IlvJCoordinateSystemEditorPanel();
        // Setup the components
        viewToolbar.setView(view);
        locator = new IlvJMouseCoordinateViewer();
        locator.setView(view);
        view.setKeepingAspectRatio(true);
        view.setBackground(new Color(80, 180, 240));
        view.setAntialiasing(true);
        view.setSize(new Dimension(600, 600));
        viewScroll.setPreferredSize(view.getSize());
        // create and setup a symbology
        symbology = new IlvSDMEngine();
        URL symbolCss = findURL("data/app6.css");//$NON-NLS-1$
        symbology.setReferenceView(view);
        symbology.setGrapher((IlvGrapher) view.getManager());
        try {
          symbology.setStyleSheets(new String[] { symbolCss.toString() });
        } catch (IlvSDMException e) {
          e.printStackTrace();
        }
        // view.getManager().setSelectionFactory(new IlvMapSelectionFactory());
        // provide feedback when symbols are selected.
        view.getManager().setSelectionFactory(new IlvMapSelectionFactory() {
          Override
          public IlvSelection makeSelection(IlvGraphic g) {
            if (g instanceof IlvHalfZoomingGraphic || g instanceof IlvApp6aGraphic) {// symbols
                                                                                     // may
                                                                                     // be
                                                                                     // encapsulated.
              return new IlvUnresizeableDrawSelection(g);
            }
            return super.makeSelection(g);
          }
        });
        // geo reference the view
        view.getManager().setNamedProperty(new IlvCoordinateSystemProperty(IlvGeographicCoordinateSystem.WGS84));
        // setup coordinate system panel to reload symbols.
        csPanel.setCoordinateSystem(IlvCoordinateSystemProperty.GetCoordinateSystem(view.getManager()));
        csPanel.addCoordinateSystemChangeListener(new PropertyChangeListener() {
          Override
          public void propertyChange(PropertyChangeEvent evt) {
            IlvCoordinateSystem system = (IlvCoordinateSystem) evt.getNewValue();
            if (system instanceof IlvProjectedCoordinateSystem) {// JV-4401 -
                                                                 // change
                                                                 // center of
                                                                 // projection
                                                                 // to the
                                                                 // correct area
              IlvProjectedCoordinateSystem pcs = (IlvProjectedCoordinateSystem) system;
              boolean change = false;
              if (pcs.getProjection().getCentralMeridian() == 0) {
                pcs.getProjection().setCentralMeridian(SimulationContext.getCentralMeridian());
                change = true;
              }
              if (pcs.getProjection().getCentralParallel() == 0) {
                pcs.getProjection().setCentralParallel(SimulationContext.getCentralParallel());
                change = true;
              }
              if (change) {
                csPanel.setCoordinateSystem(pcs);
                return;
              }
            }
            view.getManager().setNamedProperty(new IlvCoordinateSystemProperty(system));
            symbology.loadData();
            IlvAreaOfInterest aoe = (IlvAreaOfInterest) areaOfInterestPanel.getList().getSelectedValue();
            if (aoe != null) {
              aoe.zoomTo(view);
            } else {
              SwingUtilities.invokeLater(new Runnable() {
                Override
                public void run() {
                  view.fitTransformerToContent();
                }
              });
            }
          }
        });
        /* show this symbology on the GUI */
        // add layer tree panel
        layerTreePanel = new IlvLayerTreePanel();
        layerTreePanel.setView(view);
        JToolBar imageToolbar = new JToolBar();
        imageToolbar.setFloatable(false);
        ActionListener BSCListener = new ActionListener() {
          Override
          public void actionPerformed(ActionEvent e) {
            JButton source = (JButton) e.getSource();
            applyImageBCS(source, 1.1f);
          }
        };
        try {
          brightnessUpButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "more_brightness.gif"))); //$NON-NLS-1$
          brightnessUpButton.setToolTipText("Increase overall brightness"); // should//$NON-NLS-1$
                                                                            // be
                                                                            // translated,but
                                                                            // for
                                                                            // easier
                                                                            // code,
                                                                            // marked
                                                                            // as
          brightnessUpButton.addActionListener(BSCListener);
          brightnessDownButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "less_brightness.gif"))); //$NON-NLS-1$
          brightnessDownButton.setToolTipText("Decrease overall brightness"); // should//$NON-NLS-1$
                                                                              // be
                                                                              // translated,but
                                                                              // for
                                                                              // easier
                                                                              // code,
                                                                              // marked
                                                                              // as
          brightnessDownButton.addActionListener(BSCListener);
          contrastUpButton = new JButton(new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "more_contrast.gif"))); //$NON-NLS-1$
          contrastUpButton.setToolTipText("Increase overall contrast"); // should//$NON-NLS-1$
                                                                        // be
                                                                        // translated,but
                                                                        // for
                                                                        // easier
                                                                        // code,
                                                                        // marked
                                                                        // as
          contrastUpButton.addActionListener(BSCListener);
          contrastDownButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "less_contrast.gif"))); //$NON-NLS-1$
          contrastDownButton.setToolTipText("Decrease overall contrast");// should //$NON-NLS-1$
                                                                         // be
                                                                         // translated,but
                                                                         // for
                                                                         // easier
                                                                         // code,
                                                                         // marked
                                                                         // as
          contrastDownButton.addActionListener(BSCListener);
          saturationUpButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "more_saturation.gif"))); //$NON-NLS-1$
          saturationUpButton.setToolTipText("Increase overall saturation"); // should//$NON-NLS-1$
                                                                            // be
                                                                            // translated,but
                                                                            // for
                                                                            // easier
                                                                            // code,
                                                                            // marked
                                                                            // as
          saturationUpButton.addActionListener(BSCListener);
          saturationDownButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "less_saturation.gif"))); //$NON-NLS-1$
          saturationDownButton.setToolTipText("Decrease overall saturation"); // should//$NON-NLS-1$
                                                                              // be
                                                                              // translated,but
                                                                              // for
                                                                              // easier
                                                                              // code,
                                                                              // marked
                                                                              // as
          saturationDownButton.addActionListener(BSCListener);
          transparencyUpButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "more_transparency.gif"))); //$NON-NLS-1$
          transparencyUpButton.setToolTipText("Increase overall transparency"); // should//$NON-NLS-1$
                                                                                // be
                                                                                // translated,but
                                                                                // for
                                                                                // easier
                                                                                // code,
                                                                                // marked
                                                                                // as
          transparencyUpButton.addActionListener(BSCListener);
          transparencyDownButton = new JButton(
              new ImageIcon(IlvImageUtil.getImageFromFile(getClass(), "less_transparency.gif"))); //$NON-NLS-1$
          transparencyDownButton.setToolTipText("Decrease overall transparency"); // should//$NON-NLS-1$
                                                                                  // be
                                                                                  // translated,but
                                                                                  // for
                                                                                  // easier
                                                                                  // code,
                                                                                  // marked
                                                                                  // as
          transparencyDownButton.addActionListener(BSCListener);
          Dimension buttonDim = new Dimension(26, 26);
          configureComponentSize(brightnessUpButton, buttonDim);
          configureComponentSize(brightnessDownButton, buttonDim);
          configureComponentSize(contrastUpButton, buttonDim);
          configureComponentSize(contrastDownButton, buttonDim);
          configureComponentSize(saturationUpButton, buttonDim);
          configureComponentSize(saturationDownButton, buttonDim);
          configureComponentSize(transparencyUpButton, buttonDim);
          configureComponentSize(transparencyDownButton, buttonDim);
          imageToolbar.add(brightnessUpButton);
          imageToolbar.add(brightnessDownButton);
          imageToolbar.add(contrastUpButton);
          imageToolbar.add(contrastDownButton);
          imageToolbar.add(saturationUpButton);
          imageToolbar.add(saturationDownButton);
          imageToolbar.add(transparencyUpButton);
          imageToolbar.add(transparencyDownButton);
        } catch (IOException e) {
          //
        }
        imageToolbar.addSeparator();
        JLabel gridLabel = new JLabel("Contextual grid ");// should //$NON-NLS-1$
                                                          // be translated,but
                                                          // for easier code,
                                                          // marked as
        gridCombo = new JComboBox<String>(new String[] { "None", "Lat/Lon", "MGRS" });// should //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                                                                              // be
                                                                              // translated,but
                                                                              // for
                                                                              // easier
                                                                              // code,
                                                                              // marked
                                                                              // as
        gridCombo.setToolTipText("Choose the Grid type"); // should//$NON-NLS-1$
                                                          // be translated,but
                                                          // for easier code,
                                                          // marked as
        Dimension comboDim = new Dimension(70, 22);
        gridCombo.setPreferredSize(comboDim);
        gridCombo.setMinimumSize(comboDim);
        gridCombo.setMaximumSize(comboDim);
        imageToolbar.add(gridLabel);
        imageToolbar.add(gridCombo);
        gridCombo.addActionListener(new ActionListener() {
          Override
          public void actionPerformed(ActionEvent e) {
            int selectedIndex = gridCombo.getSelectedIndex();
            if (gridLayer != null) {
              view.getManager().removeLayer(gridLayer.getIndex(), false);
              gridLayer = null;
            }
            IlvAbstractBaseGrid grid;
            switch (selectedIndex) {
            case 1:
              grid = new IlvLatLonGrid();
              grid.setGridColor(Color.red);
              gridLayer = grid;
              view.getManager().addLayer(gridLayer, -1);
              view.setLayerCached(view.getManager().getLayersCount() - 1, true);
              break;
            case 2:
              grid = new IlvMGRSGrid();
              grid.setGridColor(Color.red);
              IlvMGRSGridZone.addAllZones((IlvMGRSGrid) grid);
              gridLayer = grid;
              view.getManager().addLayer(gridLayer, -1);
              view.setLayerCached(view.getManager().getLayersCount() - 1, true);
            }
            view.setOptimizedTranslation(selectedIndex == 0);
            view.repaint();
          }
        });
        // create the simulation controller GUI
        SimulationController simToolbar = new SimulationController(symbology);
        simToolbar.setFloatable(false);
        // load the initial map file.
        loadInitialData();
        // limit the zoom to correct scales.
        IlvMapScaleLimiter limiter = new IlvMapScaleLimiter(1f / 1000f, (float) (1 / 1E9));
        limiter.setView(view);
        // use the first Area of interest as the bouds where targets will be
        // created.
        IlvAreaOfInterestVector aoe = IlvAreasOfInterestProperty.GetAreasOfInterest(view.getManager());
        if (aoe != null && aoe.size() > 0) {
          IlvRect bounds = aoe.getArea(0).getRectangle();
          SimulationContext.setBounds(bounds.getMinX(), bounds.getMinY(), bounds.getMaxX(), bounds.getMaxY());
        }
        // connect the dynamic theme controller to use the view scale as its
        // reference
        IlvMapStyleController themeControl = IlvMapStyleControllerProperty.GetMapStyleController(view.getManager());
        themeControl.setView(view);
        themeControl.updateCurrentTheme();
        IlvBetterFlowLayout layout = new IlvBetterFlowLayout(FlowLayout.LEADING);
        JPanel toolbarContainer = new JPanel(layout);
        // configure the main window
        getContentPane().add(toolbarContainer, BorderLayout.NORTH);
        toolbarContainer.add(viewToolbar);
        compass.setView(view);
        getContentPane().add(viewScroll, BorderLayout.CENTER);
        final JTabbedPane tabPane = new JTabbedPane();
        tabPane.addTab("Map layers", layerTreePanel);// should be //$NON-NLS-1$
                                                     // translated,but for
                                                     // easier code, marked as
        tabPane.addTab("Areas of Interest", areaOfInterestPanel); // should //$NON-NLS-1$
                                                                  // be
                                                                  // translated,but
                                                                  // for easier
                                                                  // code,
                                                                  // marked as
        tabPane.addTab("Coordinate System", csPanel); // should be //$NON-NLS-1$
                                                      // translated,but for
                                                      // easier code, marked as
        tabPane.addTab("Symbols", symbologyPanel);// should be //$NON-NLS-1$
                                                  // translated,but for easier
                                                  // code, marked as
        // lazy creation of the symbol tree because it listens to symbol changes
        // and may slow down simulation.
        tabPane.getModel().addChangeListener(new ChangeListener() {
          Override
          public void stateChanged(ChangeEvent e) {
            if (tabPane.getSelectedComponent() == symbologyPanel && symbPanel == null) {
              symbPanel = new MySymbologyTreeView(symbology);
              IlvApp6aSymbologyTreeViewActions app6Actions = new IlvApp6aSymbologyTreeViewActions();
              app6Actions.setLatLonPicker(new IlvCoordinatePanelFactory.CoordPointInputPanel(view,
                  IlvDisplayPreferencesProperty.GetDisplayPreferences(view.getManager()).getCoordinateFormatter()));
              symbPanel.setSymbologyTreeViewActions(app6Actions);
              symbologyPanel.add(symbPanel, BorderLayout.CENTER);
            }
          }
        });
        JPanel tabPanel = new JPanel(new BorderLayout());
        JPanel southPanel = new JPanel();
        southPanel.add(compass);
        southPanel.add(locator);
        tabPanel.add(tabPane, BorderLayout.CENTER);
        tabPanel.add(southPanel, BorderLayout.SOUTH);
        getContentPane().add(tabPanel, BorderLayout.LINE_START);
        final JLabel fpsLabel = new JLabel("FPS:100"); // should //$NON-NLS-1$
                                                       // be translated,but for
                                                       // easier code, marked as
        simToolbar.addSeparator(new Dimension(10, 0));
        Dimension d = fpsLabel.getPreferredSize();
        fpsLabel.setMaximumSize(d);
        fpsLabel.setMinimumSize(d);
        simToolbar.add(fpsLabel);
        toolbarContainer.add(simToolbar);
        toolbarContainer.add(imageToolbar);
        // Add a timer to compute and display the number of Frames(refresh) per
        // second.
        Timer t = new Timer(true);
        t.schedule(new TimerTask() {
          Override
          public void run() {
            long time = System.currentTimeMillis();
            final double fps = (1000 * frames) / (time - lastTime);
            frames = 0;
            lastTime = time;
            SwingUtilities.invokeLater(new Runnable() {
              Override
              public void run() {
                fpsLabel.setText("FPS:" + (int) fps);// should be //$NON-NLS-1$
                                                     // translated,but for
                                                     // easier code, marked as
              }
            });
          }
        }, 1000, 1000);
        lastTime = System.currentTimeMillis();
      }
    });// event thread runnable
  }

  private void applyImageBCS(JButton source, float multiplier) {
    IlvMapLayerTreeModel ltm = IlvMapLayerTreeProperty.GetMapLayerTreeModel(view.getManager());
    Enumeration<?> e = ltm.getEnumeration();
    while (e.hasMoreElements()) {
      DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
      Object o = node.getUserObject();
      if (o instanceof IlvMapLayer) {
        IlvMapLayer layer = (IlvMapLayer) o;
        IlvMapStyle style = layer.getStyle();
        if (layer.getName().contains("Symbol")) { //$NON-NLS-1$
          // skip symbol layer
          continue;
        }
        if (style != null) {
          if (source == transparencyUpButton) {
            style.setAlpha(style.getAlpha() / multiplier);
          } else if (source == transparencyDownButton) {
            style.setAlpha(Math.min(style.getAlpha() * multiplier, 1.0f));
          } else {
            if (style instanceof IlvRasterStyle) {
              IlvRasterStyle rasterStyle = (IlvRasterStyle) style;
              if (source == brightnessUpButton) {
                rasterStyle
                    .setBrightness(Double.valueOf(Math.min(rasterStyle.getBrightness().doubleValue() * multiplier, 2.0)));
              } else if (source == brightnessDownButton) {
                rasterStyle.setBrightness(Double.valueOf(rasterStyle.getBrightness().doubleValue() / multiplier));
              } else if (source == contrastUpButton) {
                rasterStyle
                    .setContrast(Double.valueOf(Math.min(rasterStyle.getContrast().doubleValue() * multiplier, 2.0)));
              } else if (source == contrastDownButton) {
                rasterStyle.setContrast(Double.valueOf(rasterStyle.getContrast().doubleValue() / multiplier));
              } else if (source == saturationUpButton) {
                rasterStyle
                    .setSaturation(Double.valueOf(Math.min(rasterStyle.getSaturation().doubleValue() * multiplier, 2.0)));
              } else if (source == saturationDownButton) {
                rasterStyle.setSaturation(Double.valueOf(rasterStyle.getSaturation().doubleValue() / multiplier));
              }
            }
          }
        }
      }
    }
    view.invalidateTripleBuffer(false);
    view.repaint();
  }

  /**
   * Loads a shape file.
   */
  private void loadInitialData() {
    URL mapFile = findURL("data/nellis.ivl"); //$NON-NLS-1$
    try {
      IlvDefaultDataPathResolver dpr = new IlvDefaultDataPathResolver(findURL("data").toExternalForm()); //$NON-NLS-1$
      IlvMapDataPathManager.AddDataPathResolver(dpr);
      InputStream stream = new BufferedInputStream(mapFile.openStream());
      // Create map input stream
      IlvMapInputStream mapInput = new IlvMapInputStream(stream, (String) null);
      // Clear current manager
      IlvManager manager = view.getManager();
      // Load the map
      mapInput.read(manager);
      // close the stream
      stream.close();
      // fit the view to its new content
      IlvAreaOfInterestVector vector = IlvAreasOfInterestProperty.GetAreasOfInterest(manager);
      ((IlvAreaOfInterest) vector.get(0)).zoomTo(view);
    } catch (Exception e1) {
      e1.printStackTrace();
    }
  }

  /**
   * Main method
   * 
   * @param args
   *          (ignored)
   */
  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);
        App6aDemo demo = new App6aDemo();
        frame.getContentPane().add(demo);
        frame.setTitle("Defense mission monitoring"); //$NON-NLS-1$
        try {
          frame.setIconImage(IlvImageUtil.getImageFromFile(getClass(), "globe.gif")); //$NON-NLS-1$
        } catch (IOException e) {
          // do nothing
        }
        frame.pack();
        frame.setVisible(true);
      }
    });
  }

  private static URL findURL(String resource) {
    return App6aDemo.class.getResource(resource);
  }

  /**
   * Add an interactor on the toolbar.
   * 
   * @param tooltip
   *          button tooltip.
   * @param imageURL
   *          url of button icon.
   * @param interactor
   *          interactor to install on button press.
   */
  protected void installInteractorButton(String tooltip, String imageURL, final IlvManagerViewInteractor interactor) {
    Image image = null;
    try {
      image = IlvImageUtil.getImageFromFile(App6aDemo.class, imageURL);
    } catch (IOException e1) {
      e1.printStackTrace();
    }
    final JToggleButton button = new JToggleButton(new ImageIcon(image));
    button.setMargin(new Insets(2, 2, 2, 2));
    if (tooltip != null)
      button.setToolTipText(tooltip);
    viewToolbar.add(button);
    button.addActionListener(new ActionListener() {
      Override
      public void actionPerformed(ActionEvent e) {
        if (button.isSelected()) {
          view.setInteractor(interactor);
          view.requestFocus();
        } else if (view.getInteractor() == interactor) {
          view.popInteractor();
        }
      }
    });
    InteractorListener interactorListener = new InteractorListener() {
      Override
      public void interactorChanged(InteractorChangedEvent event) {
        boolean isMyInteractor = (event.getNewValue() == interactor);
        if (button.isSelected() != isMyInteractor) {
          button.setSelected(isMyInteractor);
        }
      }
    };
    view.addInteractorListener(interactorListener);
  }

  /**
   * Returns a tooltip associated to a graphical object by making an HTML table
   * from its IlvAttributeProperty.
   * 
   * @param graphic
   *          Graphical object
   * @return the string to display as a tooltip.
   */
  protected String getToolTip(IlvGraphic graphic) {
    IlvApp6aSymbol symbol = (IlvApp6aSymbol) graphic.getProperty("IlvSDMObject"); //$NON-NLS-1$
    String speed = (String) symbol.getProperty("SPEED"); //$NON-NLS-1$
    String tooltip;
    String extraInfo = "";//$NON-NLS-1$
    // add location DMS & MGRS properties
    IlvDMSCoordinateFormatter DMSFormatter = new IlvDMSCoordinateFormatter();
    IlvUTMCoordinateFormatter UTMFormatter = new IlvUTMCoordinateFormatter();
    double olon = symbol.getLongitude();
    double olat = symbol.getLatitude();
    DMSFormatter.setLonLat(olon, olat);
    UTMFormatter.setLonLat(olon, olat);
    String lodms = DMSFormatter.getLongitudeString();
    String ladms = DMSFormatter.getLatitudeString();
    String utm = UTMFormatter.toString();

    if (speed != null) {
      extraInfo = "</TD></TR><TR><TD>SPEED</TD><TD>" + symbol.getProperty("SPEED") + //$NON-NLS-1$//$NON-NLS-2$
          "</TD></TR><TR><TD>HEADING</TD><TD>" + symbol.getProperty("DIRECTION_OF_MOVEMENT_INDICATOR") + //$NON-NLS-1$//$NON-NLS-2$
          "</TD></TR><TR><TD>ALTITUDE</TD><TD>" + symbol.getProperty("ALTITUDE_OR_DEPTH"); //$NON-NLS-1$//$NON-NLS-2$

    }
    tooltip = "<HTML><TABLE><TR><TD>LONGITUDE</TD><TD>" + lodms + //$NON-NLS-1$
        "</TD></TR><TR><TD>LATITUDE</TD><TD>" + ladms + //$NON-NLS-1$
        "</TD></TR><TR><TD>UTM COORD.</TD><TD>" + utm + //$NON-NLS-1$
        extraInfo + "</TD></TR></TABLE></HTML>"; //$NON-NLS-1$
    return tooltip;
  }

  /**
   * Computes the lat/lon of the point on the map.
   * 
   * @param point
   *          location of the mouse on the view.
   * @return the lat/lon coordinates in radians, or null.
   */
  protected IlvCoordinate computeCoordinates(Point point) {
    IlvCoordinate coord;
    IlvPoint pt = new IlvPoint(point.x, point.y);
    view.getTransformer().inverse(pt);
    IlvProjectionUtil.invertY(pt);
    try {
      IlvCoordinateSystem cs = IlvCoordinateSystemProperty.GetCoordinateSystem(view.getManager());
      IlvCoordinateTransformation ct = IlvCoordinateTransformation.CreateTransformation(cs,
          IlvGeographicCoordinateSystem.KERNEL);
      coord = new IlvCoordinate(pt.x, pt.y);
      ct.transform(coord, coord);
    } catch (IlvCoordinateTransformationException e) {
      coord = null;
    }
    return coord;
  }

  private void configureComponentSize(JComponent comp, Dimension buttonDim) {
    comp.setPreferredSize(buttonDim);
    comp.setMinimumSize(buttonDim);
    comp.setMaximumSize(buttonDim);
  }
}