package nxm.sys.libg;

import java.util.Stack;

/**
 *  A Region is the group of points contained within a certain latitude longitude range.
 *  A Region is effectively a "bin" holding references to the point objects.
 *  This is designed to be the smallest of the containers, with multiple regions
 *  forming a region group.
 *  The region information can be used to form and draw region circles on a map or to
 *  supply information needed to determine how many visible points there are in a latitude
 *  longitude region.
 *
 *  @see RegionGroup
 *
 *  @author Kevin Esterheld / Jeanette McCall
 *  @since NeXtMidas 3.9.4 for NXM-3542
 */
public class Region {

  Point3D[] points = new Point3D[50]; // What is a good starting point for the array size?
  private Stack<Integer> pointsRemoved = new Stack<>(); // keep track of removed points
  private int numPointsInRegion = 0; // keep track of how many points are added - not necessarily valid points - they could be nulls from deleting points.
  double minX = Double.MAX_VALUE;
  double maxX = -Double.MAX_VALUE;
  double minY = Double.MAX_VALUE;
  double maxY = -Double.MAX_VALUE;

  /** default constructor */
  public Region () {}

  /** Add a point to this Region Group
   *
   *  @param point Point3D to add
   *  @return      index of the point within this Region
   */
  public int addPoint (Point3D point) {
    // Get min and max y set here
    if (point.getPosLon()>maxX) {
      maxX = point.getPosLon();
    }
    if (point.getPosLon()>minX) {
      minX = point.getPosLon();
    }
    if (point.getPosLat()>maxY) {
      maxY = point.getPosLat();
    }
    if (point.getPosLat()>minY) {
      minY = point.getPosLat();
    }


    int index = numPointsInRegion;
    boolean grabbedIndexFromPointsRemoved = false; // 3.9.4
    if (points.length <= numPointsInRegion) {
      if (pointsRemoved.size()>0) {
        index = pointsRemoved.pop();
        grabbedIndexFromPointsRemoved = true;
      }
      else {
        Point3D[] tmp = new Point3D[2*points.length];
        System.arraycopy(points,0,tmp,0,points.length);
        points = tmp;
      }
    }

    points[index] = point;
    if (!grabbedIndexFromPointsRemoved) numPointsInRegion++;
    return index;
  }

  /** Remove a point from this Region
   *
   *  @param index index of the point to remove
   */
  public void removePoint (int index) {
    if (index>=points.length) return; // can't remove index that does not exist
    if (points[index]==null)  return; // already nulled
    points[index] = null;
    pointsRemoved.add(index);
  }

  /** Get current point count
   *
   *  @return Number of points within this Region
   */
  public int getNumPtsInRegion () {
    return getNumPointsInRegion();
  }

  /** Count the points in a given range
   *  <br><b>Note:</b> The coordinates have to be in the right order x1 &lt; x2 and y1 &lt; y2
   *  @param x1 first x value (-180 to 180)
   *  @param x2 second x value (-180 to 180)
   *  @param y1 first y value (-90 to 90)
   *  @param y2 second y value (-90 to 90)
   *  @return the point count in the given range
   *  @since NeXtMidas 3.9.3
   */
  int countPointsInRange (double x1, double x2, double y1, double y2) {
    int pointCount = 0;
    for (int i = 0; i < numPointsInRegion; i++) {
      Point3D point = points[i];
      if (point==null) continue;
      if (x1 <= point.getPosLon() && x2 >= point.getPosLon() && y1 <= point.getPosLat() && y2 >= point.getPosLat()) {
        pointCount ++;
      }
    }

    return pointCount;
  }

  /** Get the number of points in this "region" (i.e. geographic region)
   *  @return the number of points in this region
   */
  public int getNumPointsInRegion () {
    return numPointsInRegion - pointsRemoved.size();
  }

  /** This will draw all the points in the region
   *  @param lin The line that provides graphical information to be passed to the draw point method
   */
  void drawAllPoints (Line lin) {
    for (int k = 0; k<numPointsInRegion; k++) {
      if (points[k]!=null) {
        points[k].layer.drawPoint(lin, points[k], null, MColor.OPAQUE);
      }
    }
  }

}
