/*
 * 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.Cursor;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.net.URL;
import java.util.Enumeration;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRootPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.Timer;

import ilog.views.IlvPoint;
import ilog.views.diagrammer.IlvDiagrammer;
import ilog.views.diagrammer.project.IlvDiagrammerProject;
import ilog.views.maps.IlvCoordinateSystemProperty;
import ilog.views.maps.IlvMapScaleLimiter;
import ilog.views.maps.beans.IlvJAreaOfInterestPanel;
import ilog.views.maps.beans.IlvJMapsManagerViewControlBar;
import ilog.views.maps.beans.IlvJMouseCoordinateViewer;
import ilog.views.maps.beans.IlvMapLegend;
import ilog.views.maps.projection.IlvProjectionUtil;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.sdm.IlvSDMModel;
import ilog.views.sdm.model.IlvSDMNode;
import ilog.views.util.IlvProductUtil;

/**
 * This sample is a very simple mapping application that displays a diagram
 * stored in an IDPR file, built using the "Designer".
 * 
 * @since JViews 7.0
 */
public class LoadDiagDemo extends JRootPane {
  private static final long serialVersionUID = -2357347615976357890L;

  private static final class SymbolMouseListener extends MouseAdapter implements MouseMotionListener {
    private IlvDiagrammer diagrammer;
    private Cursor defaultCursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
    private Cursor handCursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);

    SymbolMouseListener(IlvDiagrammer diagrammer) {
      this.diagrammer = diagrammer;
    }

    // display a dialog.
    Override
    public void mouseClicked(MouseEvent e) {
      if (e.getClickCount() >= 2) {
        Object target = diagrammer.getEngine().getObject(new IlvPoint(e.getX(), e.getY()), diagrammer.getView());
        if (target instanceof IlvSDMNode) {
          IlvSDMNode node = (IlvSDMNode) target;
          String properties[] = node.getPropertyNames();
          Object columnNames[] = { "Property", "Value" }; //$NON-NLS-1$ //$NON-NLS-2$
          Object rowData[][] = new Object[properties.length][2];
          for (int i = 0; i < rowData.length; i++) {
            rowData[i][0] = properties[i];
            rowData[i][1] = node.getProperty(properties[i]);
          }
          JTable sheet = new JTable(rowData, columnNames);
          sheet.setEnabled(false);
          sheet.setPreferredScrollableViewportSize(sheet.getPreferredSize());
          JScrollPane pane = new JScrollPane(sheet);
          JOptionPane.showMessageDialog(diagrammer, pane, "Symbol information", //$NON-NLS-1$
              JOptionPane.INFORMATION_MESSAGE);
        }
      }
    }

    Override
    public void mouseDragged(MouseEvent e) {
      // ignore
    }

    Override
    public void mouseMoved(MouseEvent e) {
      // change the cursor if mouse moves over a node
      Object target = diagrammer.getEngine().getObject(new IlvPoint(e.getX(), e.getY()), diagrammer.getView());
      if (target instanceof IlvSDMNode) {
        if (diagrammer.getView().getCursor() != handCursor) {
          defaultCursor = diagrammer.getView().getCursor();
          diagrammer.getView().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
        }
      } else if (diagrammer.getView().getCursor() == handCursor) {
        diagrammer.getView().setCursor(defaultCursor);
      }
    }
  }

  {
    // This sample uses JViews Maps features. When deploying an
    // application that includes this code, you need to be in possession
    // of a JViews Maps Deployment license.
    IlvProductUtil.DeploymentLicenseRequired(IlvProductUtil.JViews_Maps_Deployment);
  }
  // mouse coordinate information bean
  IlvJMouseCoordinateViewer locator = new IlvJMouseCoordinateViewer();
  // Map legend bean
  IlvMapLegend legend = new IlvMapLegend();
  IlvDiagrammer diagrammer = new IlvDiagrammer();
  // zoom & selection toolbar
  IlvJMapsManagerViewControlBar viewToolbar = new IlvJMapsManagerViewControlBar();
  IlvJAreaOfInterestPanel aoipanel;
  int step = 0;// animation count

  /**
   * Creates a frame containing the different map beans.
   */
  public LoadDiagDemo() {
    super();
    // Make sure the swing construction is called in Swing event thread.
    ilog.views.util.swing.IlvSwingUtil.invokeAndWait(new Runnable() {
      Override
      public void run() {
        // Setup the beans
        locator.setView(diagrammer.getView());
        legend.setView(diagrammer.getView());
        viewToolbar.setView(diagrammer.getView());
        aoipanel = new IlvJAreaOfInterestPanel(diagrammer.getView(), true, true, true);
        diagrammer.getView().setSize(new Dimension(900, 450));
        // geo reference the view
        diagrammer.getEngine().getGrapher()
            .setNamedProperty(new IlvCoordinateSystemProperty(IlvGeographicCoordinateSystem.WGS84));
        // limit the zoom to correct scales.
        IlvMapScaleLimiter limiter = new IlvMapScaleLimiter((float) (1 / 1E5), (float) (1 / 1E8));
        limiter.setView(diagrammer.getView());
        // arrange the main window
        getContentPane().add(viewToolbar, BorderLayout.NORTH);
        getContentPane().add(diagrammer, BorderLayout.CENTER);
        JPanel status = new JPanel(new BorderLayout());
        status.add(locator, BorderLayout.LINE_START);
        getContentPane().add(status, BorderLayout.SOUTH);
        getContentPane().add(legend, BorderLayout.LINE_END);
        getContentPane().add(aoipanel, BorderLayout.LINE_START);
        /* to load the initial file */
        loadFile("data/world.idpr"); //$NON-NLS-1$
        /* --- End of Load diag GUI --- */
        // timer to change the model every 2 second.
        Timer timer = new Timer(2000, new ActionListener() {
          Override
          public void actionPerformed(ActionEvent e) {
            IlvSDMModel model = diagrammer.getEngine().getModel();
            Enumeration<?> objs = diagrammer.getEngine().getAllObjects();
            while (objs.hasMoreElements()) {
              Object obj = objs.nextElement();
              if (true) {
                // retrieve (and possibly store in the model)
                // the center point of the animation.
                Object olat = model.getObjectProperty(obj, "latitude0"); //$NON-NLS-1$
                if (olat == null) {
                  olat = model.getObjectProperty(obj, "latitude"); //$NON-NLS-1$
                  model.setObjectProperty(obj, "latitude0", olat); //$NON-NLS-1$
                }
                Object olon = model.getObjectProperty(obj, "longitude0"); //$NON-NLS-1$
                if (olon == null) {
                  olon = model.getObjectProperty(obj, "longitude"); //$NON-NLS-1$
                  model.setObjectProperty(obj, "longitude0", olon); //$NON-NLS-1$
                }
                // store some fake speed if it does not exist in
                // model
                Object ospeed = model.getObjectProperty(obj, "speed"); //$NON-NLS-1$
                double speed;
                if (ospeed == null) {
                  speed = Math.random() * Math.PI / 10;
                  model.setObjectProperty(obj, "speed", "" + speed); //$NON-NLS-1$ //$NON-NLS-2$
                } else {
                  speed = Double.parseDouble(ospeed.toString());
                }
                double range = Math.toRadians(0.5);// roaming
                // range for
                // objects.
                Object otype = model.getObjectProperty(obj, "type"); //$NON-NLS-1$
                // improvement JV-1508
                if (otype != null) {
                  int t = Integer.parseInt(otype.toString());
                  switch (t) {
                  case 1:// plane
                    break;
                  case 2: // bus
                  case 3: // car
                    range = range / 10.0;// smaller range
                    break;
                  case 4: // boat
                    range = range / 5.0;// smaller range
                    break;
                  }
                }
                try {
                  double lat0 = IlvProjectionUtil.DMSToRadian(olat.toString());
                  double lon0 = IlvProjectionUtil.DMSToRadian(olon.toString());
                  double lon = lon0 + range * Math.cos(step * speed);
                  double lat = lat0 + range * Math.sin(step * speed);
                  model.setObjectProperty(obj, "latitude", //$NON-NLS-1$
                      "" + IlvProjectionUtil.RadianToDMS(lat, true)); //$NON-NLS-1$
                  model.setObjectProperty(obj, "longitude", //$NON-NLS-1$
                      "" + IlvProjectionUtil.RadianToDMS(lon, false)); //$NON-NLS-1$
                } catch (Exception ex) {
                  // badly formed lat/lon - ignore that.
                }
              }
            }
            step++;
          }
        });
        timer.start();
        // add a listener to display an information dialog on double
        // click.
        SymbolMouseListener listener = new SymbolMouseListener(diagrammer);
        diagrammer.getView().addMouseListener(listener);
        diagrammer.getView().addMouseMotionListener(listener);
      }
    });
  }

  /**
   * Load a file into the view's manager.
   * 
   * @param idprFile
   *          prebuilt file to read.
   */
  public void loadFile(final String idprFile) {
    try {
      /*
       * if the palette is not in the classpath, here is the code to load the
       * palette, in a non pure applet context: try { IlvPaletteManager
       * paletteManager=new IlvPaletteManager();
       * paletteManager.load(findURL("data/transportationServices.jar"));
       * //$NON-NLS-1$ paletteManager.attach(diagrammer.getEngine()); } catch
       * (Throwable t){ System.out.println("Cannot load the palette, expecting
       * it to be in the CLASSPATH "); //$NON-NLS-1$ t.printStackTrace(); //
       * ignore; }
       */
      // Load the idpr file
      IlvDiagrammerProject project = new IlvDiagrammerProject(findURL(idprFile));
      diagrammer.setProject(project);
      diagrammer.fitToContents();
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private static URL findURL(String resource) {
    URL rtnURL = null;
    boolean exists;
    try {
      exists = new File(resource).exists();
    } catch (SecurityException e) {
      // applet
      exists = false;
    }
    if (exists) {
      try {
        rtnURL = new File(resource).toURI().toURL();
      } catch (Exception e) {
        e.printStackTrace();
      }
    } else {
      rtnURL = LoadDiagDemo.class.getResource(resource);
      if (rtnURL == null) {
        rtnURL = LoadDiagDemo.class.getResource("/" + resource); //$NON-NLS-1$
      }
    }
    return rtnURL;
  }

  /**
   * 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();
        // Make sure the application will exit when we close its window.
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        LoadDiagDemo app = new LoadDiagDemo();
        frame.getContentPane().add(app);
        frame.setTitle("Diagrammer Project Loading Demo"); //$NON-NLS-1$
        // This could be externalized in a resources/messages.properties
        // file using
        // IlvMapUtil.getString call.
        frame.pack();
        frame.setVisible(true);
      }
    });
  }

}