/*
 * 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.
 */
package simulation;

//import ilog.views.maps.defense.symbology.app6a.IlvApp6aSymbol;
import ilog.views.IlvPoint;
import ilog.views.graphic.IlvPolyPoints;
import ilog.views.maps.IlvGeodeticComputation;
import ilog.views.maps.projection.IlvEllipsoid;
import ilog.views.sdm.IlvSDMEngine;

/**
 * Class for enemy unit being targets of missiles.
 * 
 * @see Mobile
 * 
 */
public class PathConstrainedMobile extends Mobile {
  private IlvPolyPoints path;
  private int segmentIndex;
  private double distance;
  private double distanceToSegment;

  /**
   * Creates a target with a different symboloc tag.
   * 
   * @param tag
   * 
   * @param sym
   *          symbology.
   * @param road
   * @param randomLocation
   */
  protected PathConstrainedMobile(String tag, IlvSDMEngine sym, IlvPolyPoints road, boolean randomLocation) {
    super(tag, sym);
    this.path = road;
    int index = 0;
    if (randomLocation) {
      index = (int) (SimulationContext.random() * (road.getPointsCardinal() - 1));
    }
    double lon0 = road.getPointAt(index, null).getX();
    double lat0 = road.getPointAt(index, null).getY();
    segmentIndex = index;
    distance = 0;
    for (int i = 0; i < segmentIndex; i++) {
      IlvPoint current = path.getPointAt(i, null);
      IlvPoint next = path.getPointAt(i + 1, null);
      double dy = next.getY() - current.getY();
      double dx = next.getX() - current.getX();
      double segmentLength = Math.sqrt(dx * dx + dy * dy);
      distance += segmentLength;
    }
    distanceToSegment = distance;
    setLocation(symbol, null, lon0, lat0);
    updateLocation();
  }

  private IlvPoint computeCoordinatesFromDistance(double dist) {
    IlvPoint result = null;
    int segmentCount = path.getPointsCardinal() - 1;
    double remainingDistance = -1;
    for (int i = segmentIndex; i < segmentCount; i++) {
      remainingDistance = dist - distanceToSegment;
      IlvPoint current = path.getPointAt(i, null);
      IlvPoint next = path.getPointAt(i + 1, null);
      double dy = next.getY() - current.getY();
      double dx = next.getX() - current.getX();
      double segmentLength = Math.sqrt(dx * dx + dy * dy);
      if (remainingDistance < segmentLength) {
        // interpolate
        double alpha = remainingDistance / segmentLength;
        double x = current.getX() + alpha * dx;
        double y = current.getY() + alpha * dy;
        result = new IlvPoint(x, y);
        break;
      }
      distanceToSegment += segmentLength;
      segmentIndex++;
    }
    return result;
  }

  Override
  public void updateLocation() {
    if (isWrecked()) {
      return;
    }
    double olon = getLongitude(symbol);
    double olat = getLatitude(symbol);
    long updateTime = System.currentTimeMillis();
    double dt;
    if (!paused) {
      if (lastUpdateTime == 0) {
        dt = 0;
      } else {
        dt = (updateTime - lastUpdateTime) / 1000.0;
      }
      dt *= SimulationContext.getTimeAcceleration();
      // distance ran.
      double speed = getHorizontalSpeed();
      double distMeter = dt * speed;
      // approximate distance
      IlvGeodeticComputation gc = new IlvGeodeticComputation(IlvEllipsoid.SPHERE);
      gc.setLatitude1(olat);
      gc.setLongitude1(olon);
      gc.setDistance(distMeter);
      gc.setForwardAzimuth(getDirection());
      gc.computeGeodeticForward();
      double newLon = gc.getLongitude2();
      double newLat = gc.getLatitude2();
      double dLat = newLat - olat;
      double dLon = newLon - olon;
      double distLonLat = Math.sqrt(dLat * dLat + dLon * dLon);
      distance += distLonLat;
      // compute new coordinates on the path
      IlvPoint p = computeCoordinatesFromDistance(distance);
      if (p == null) {
        wreck();
        return;
      }
      // set direction
      IlvPoint current = path.getPointAt(segmentIndex, null);
      IlvPoint next = path.getPointAt(segmentIndex + 1, null);
      double dir = Math.atan2(next.getX() - current.getX(), next.getY() - current.getY());
      setDirection(dir);
      setSymbolProperty(MODIFIER_DIRECTION_OF_MOVEMENT_INDICATOR, "" + Math.toDegrees(getDirection() - Math.PI / 2), //$NON-NLS-1$
          false);
      lastUpdateTime = updateTime;
      // update location
      boolean ia = symbology.getModel().isAdjusting();
      if (!ia)
        symbology.getModel().setAdjusting(true);
      setLocation(symbol, symbology, p.getX(), p.getY());
      if (!ia)
        symbology.getModel().setAdjusting(false);
    }
    lastUpdateTime = updateTime;
    updateStatus();
  }
}