/*
 * 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.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;

import ilog.views.IlvGraphic;
import ilog.views.IlvManager;
import ilog.views.IlvManagerView;
import ilog.views.IlvPoint;
import ilog.views.IlvTransformer;
import ilog.views.event.ManagerSelectionChangedEvent;
import ilog.views.event.ManagerSelectionListener;
import ilog.views.graphic.IlvMarker;
import ilog.views.interactor.IlvSelectInteractor;
import ilog.views.maps.IlvAngularUnit;
import ilog.views.maps.IlvCoordinate;
import ilog.views.maps.projection.IlvEllipsoid;
import ilog.views.maps.projection.IlvHorizontalShiftDatum;
import ilog.views.maps.projection.IlvLambertAzimuthalEqualAreaProjection;
import ilog.views.maps.projection.IlvProjection;
import ilog.views.maps.projection.IlvProjectionUtil;
import ilog.views.maps.srs.coordsys.IlvGeographicCoordinateSystem;
import ilog.views.maps.srs.coordsys.IlvMeridian;
import ilog.views.maps.srs.coordsys.IlvProjectedCoordinateSystem;
import ilog.views.maps.srs.coordtrans.IlvCoordinateTransformation;
import ilog.views.maps.srs.coordtrans.IlvCoordinateTransformationException;
import ilog.views.swing.IlvJScrollManagerView;
import ilog.views.util.IlvProductUtil;

/**
 * A sample application creating a map and displaying cities at their right
 * location.
 */
class Sample2 extends JFrame {
  private IlvManager manager;
  private IlvManagerView mgrview;

  // The transformation from geographic CS to projected CS
  private IlvCoordinateTransformation geo2projCT;
  // The inverse transformation
  private IlvCoordinateTransformation proj2geoCT;

  private JTextField llField;
  private JTextField cityField;

  /**
   * Constructor
   */
  public Sample2(String filename) {
    super("Integrating SRS and graphics");
    createUI();

    // loading a map of the USA
    try {
      manager.read(filename);
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(0);
    }

    createTransformations();
    addCities();
    setViewInteractor();
  }

  /**
   * Creates the UI for this application
   */
  private void createUI() {
    // Creation of the manager and the view
    manager = new IlvManager();
    mgrview = new IlvManagerView(manager);
    mgrview.setKeepingAspectRatio(true);

    IlvJScrollManagerView panel = new IlvJScrollManagerView(mgrview);
    getContentPane().setLayout(new BorderLayout());
    getContentPane().add("Center", panel);

    // Creation of the text fields to display info
    JPanel southPanel = new JPanel();
    southPanel.setLayout(new GridLayout(1, 0));
    llField = new JTextField();
    llField.setEditable(false);
    southPanel.add(llField);
    cityField = new JTextField();
    cityField.setEditable(false);
    southPanel.add(cityField);
    getContentPane().add("South", southPanel);

    // A window listener
    addWindowListener(new WindowAdapter() {
      Override
      public void windowClosing(WindowEvent evt) {
        System.exit(0);
      }

      Override
      public void windowOpened(WindowEvent evt) {
        mgrview.fitTransformerToContent();
      }
    });
  }

  /**
   * This function creates the projection to be used with the file usa.ivl
   */
  private void createTransformations() {
    // Create the projection
    IlvProjection projection1 = new IlvLambertAzimuthalEqualAreaProjection();
    projection1.setEllipsoid(IlvEllipsoid.SPHERE);
    try {
      double centralMeridian = IlvAngularUnit.RADIAN.fromDMS("100DW");
      double centralParallel = IlvAngularUnit.RADIAN.fromDMS("40DN");
      projection1.setCentralMeridian(centralMeridian);
      projection1.setCentralParallel(centralParallel);
    } catch (IllegalArgumentException e) {
      System.out.println("wrong string passed to " + "IlvAngularUnit.RADIAN.fromDMS");
      System.out.println("unable to create the projection for the file" + "usa.ivl");
      System.exit(0);
    }
    // Create the projected coordinate system
    IlvProjectedCoordinateSystem projectedCS = new IlvProjectedCoordinateSystem("Lambert Azimutal Equal Area",
        projection1);

    // Create the geographic coordinate system
    IlvGeographicCoordinateSystem geoCS = new IlvGeographicCoordinateSystem(IlvHorizontalShiftDatum.SPHERE_WGS84,
        IlvMeridian.GREENWICH);

    // A coordinate transform
    geo2projCT = IlvCoordinateTransformation.CreateTransformation(geoCS, projectedCS);
    // The inverse transform
    proj2geoCT = geo2projCT.getInverse();
  }

  /**
   * This function adds some cities on top of the map of the USA.
   */
  private void addCities() {
    addCity("Washington", "39D11'N", "76D51W");
    addCity("New York", "40D59'N", "73D39'W");
    addCity("Miami", "25D58'N", "80D02'W");
    addCity("San Francisco", "37D44'N", "122D20'W");
    addCity("Seattle", "47D51'N", "122D01'W");
    addCity("Denvers", "39D50'N", "104D53'W");
  }

  /**
   * Add a city to the map.
   * 
   * @param cityName
   *          The name of the city
   * @param lat
   *          A string representing the city latitude, in DMS format.
   * @param lon
   *          A string representing the city longitude, in DMS format.
   */
  private void addCity(String cityName, String lat, String lon) {
    try {
      double latitude = IlvAngularUnit.DEGREE.fromDMS(lat);
      double longitude = IlvAngularUnit.DEGREE.fromDMS(lon);
      IlvCoordinate coordinate = new IlvCoordinate(longitude, latitude);

      geo2projCT.transform(coordinate, coordinate);

      IlvPoint p = new IlvPoint(coordinate.x, coordinate.y);
      IlvProjectionUtil.invertY(p);

      IlvMarker marker = new IlvMarker(p, IlvMarker.IlvMarkerFilledDiamond);
      marker.setSize(4);
      marker.setForeground(Color.red);
      manager.addObject(marker, 1, false);
      marker.setName(cityName);
    } catch (IlvCoordinateTransformationException e) {
      e.printStackTrace();
    }
  }

  private void setViewInteractor() {
    IlvSelectInteractor interactor = new IlvSelectInteractor();
    interactor.setDragAllowed(false);
    interactor.setEditionAllowed(false);
    interactor.setMoveAllowed(false);
    interactor.setMultipleSelectionMode(false);
    manager.setSelectable(0, false);
    mgrview.pushInteractor(interactor);

    // display the position of the mouse
    interactor.addMouseMotionListener(new MouseMotionAdapter() {
      Override
      public void mouseMoved(MouseEvent e) {
        // get the point in manager coordinates
        IlvTransformer t = mgrview.getTransformer();
        IlvPoint p = new IlvPoint(e.getX(), e.getY());
        t.inverse(p);
        IlvProjectionUtil.invertY(p);
        // Display the mouse position
        try {
          IlvCoordinate c = new IlvCoordinate(p.x, p.y);
          proj2geoCT.transform(c, c);
          llField.setText(IlvAngularUnit.DEGREE.toDMS(c.x, false) + " " + IlvAngularUnit.DEGREE.toDMS(c.x, true));
        } catch (IlvCoordinateTransformationException ex) {
          System.out.println("Unable to inverse this point " + ex.getMessage());
        }
      }
    });

    // display the name of the city when a city is selected
    manager.addManagerSelectionListener(new ManagerSelectionListener() {
      Override
      public void selectionChanged(ManagerSelectionChangedEvent e) {
        IlvGraphic g = e.getGraphic();
        if (g == null)
          return;
        String name = g.getName();
        if (name != null)
          cityField.setText(name);
      }
    });
  }

  static public void main(final String args[]) {
    // 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);

    // Sun recommends that to put the entire GUI initialization into the
    // AWT thread
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      Override
      public void run() {
        Sample2 s = new Sample2(args[0]);
        s.setSize(400, 300);
        s.setVisible(true);
      }
    });
  }
}