package ca.ualberta.stothard.cgview;

import java.util.*;

/**
 * This class is used to encapsulate Cgview map information when a series of images is linked
 * together.
 *
 * @author Paul Stothard
 */
public class SeriesImage implements CgviewConstants {

  int zoomValue;
  int zoomCenter;

  /**
   * Constructs a SeriesImage object.
   *
   * @param zoomValue the zoom value of the Cgview map.
   * @param zoomCenter the zoom center value of the Cgview map.
   */
  public SeriesImage(int zoomValue, int zoomCenter) {
    this.zoomValue = zoomValue;
    this.zoomCenter = zoomCenter;
  }

  /**
   * Returns the zoom value of this SeriesImage.
   *
   * @return the zoom value.
   */
  public int getZoomValue() {
    return zoomValue;
  }

  /**
   * Returns the zoom center value of this SeriesImage.
   *
   * @return the zoom center value.
   */
  public int getZoomCenter() {
    return zoomCenter;
  }

  /**
   * Compares a SeriesImage object to this SeriesImage and returns true if they are equal.
   *
   * @param seriesImage the SeriesImage to compare with this SeriesImage.
   * @return whether or not the SeriesImage objects are equal.
   */
  public boolean isEqual(SeriesImage seriesImage) {
    if ((seriesImage.getZoomValue() == zoomValue) && (seriesImage.getZoomCenter() == zoomCenter)) {
      return true;
    } else {
      return false;
    }
  }

  /**
   * Examines the ArrayList of LabelBounds objects of type {@link CgviewConstants#BOUNDS_RULER} and
   * determines which is the middle one. A string intended to serve as part of a file name is
   * constructed from the middle item's zoom value and zoom center value.
   *
   * @param labelBounds the collection of LabelBounds objects to examine.
   * @param nextZoomValue the zoom value of the next zoomed Cgview map.
   * @return a file name prefix consisting of the next zoom value and the zoom center value from the
   *     middle LabelBounds entry of type {@link CgviewConstants#BOUNDS_RULER}.
   */
  protected String getZoomInFilePrefix(ArrayList labelBounds, int nextZoomValue) {

    if (labelBounds.size() == 0) {
      return null;
    } else {
      // if seriesImage is centered on base 1, it should zoom to the next base 1 image
      if (this.zoomCenter == 1) {
        return Integer.toString(nextZoomValue) + "_" + Integer.toString(1);
      }

      // need to determine middle RULER_BOUNDS entry
      ArrayList rulerBounds = new ArrayList();
      LabelBounds currentLabelBounds;
      for (int k = 0; k < labelBounds.size(); k++) {
        currentLabelBounds = (LabelBounds) labelBounds.get(k);
        if (currentLabelBounds.getType() == BOUNDS_RULER) {
          rulerBounds.add(currentLabelBounds);
        }
      }
      if (rulerBounds.size() == 0) {
        return null;
      } else {
        // go through each rulerBounds and find one with closest base value to this.
        int closestDistance =
            Math.abs(((LabelBounds) rulerBounds.get(0)).getBase() - this.zoomCenter);
        int closestBase = ((LabelBounds) rulerBounds.get(0)).getBase();

        for (int k = 0; k < rulerBounds.size(); k++) {
          currentLabelBounds = (LabelBounds) rulerBounds.get(k);
          if (Math.abs(currentLabelBounds.getBase() - this.zoomCenter) < closestDistance) {
            closestDistance = Math.abs(currentLabelBounds.getBase() - this.zoomCenter);
            closestBase = currentLabelBounds.getBase();
          }
        }
        return Integer.toString(nextZoomValue) + "_" + Integer.toString(closestBase);
      }
    }
  }

  /**
   * Determines which SeriesImage should be linked to this SeriesImage using a zoom out button.
   *
   * @param previousSeriesImages a collection of SeriesImage objects.
   * @param previousZoom the zoom value used for the previous set of Cgview images.
   * @return a file name prefix to be used for linking purposes.
   */
  protected String getZoomOutFilePrefix(ArrayList previousSeriesImages, int previousZoom) {

    int bestDistance = 0;
    int bestDistanceZoomCenter = 0;

    SeriesImage currentSeriesImage;

    if (previousSeriesImages.size() == 0) {
      return null;
    } else {
      // if seriesImage is centered on base 1, it should zoom out to the previous base 1 image
      if (this.zoomCenter == 1) {
        return Integer.toString(previousZoom) + "_" + Integer.toString(1);
      }

      // find previous SeriesImage with zoomCenter closest to this one.
      for (int k = 0; k < previousSeriesImages.size(); k++) {
        currentSeriesImage = (SeriesImage) previousSeriesImages.get(k);
        if (k == 0) {
          bestDistance = Math.abs(currentSeriesImage.getZoomCenter() - this.getZoomCenter());
          bestDistanceZoomCenter = currentSeriesImage.getZoomCenter();
          previousZoom = currentSeriesImage.getZoomValue();
        } else {
          if (Math.abs(currentSeriesImage.getZoomCenter() - this.getZoomCenter()) < bestDistance) {
            bestDistance = Math.abs(currentSeriesImage.getZoomCenter() - this.getZoomCenter());
            bestDistanceZoomCenter = currentSeriesImage.getZoomCenter();
          }
        }
      }
    }
    return Integer.toString(previousZoom) + "_" + Integer.toString(bestDistanceZoomCenter);
  }

  /**
   * Determines which SeriesImage is adjacent to this SeriesImage in the clockwise direction.
   *
   * @param toDrawCurrentZoom a collection of SeriesImages drawn at the same zoom level as this
   *     SeriesImage.
   * @return a file name prefix to be used for linking purposes.
   */
  public String getClockwiseFilePrefix(ArrayList toDrawCurrentZoom) {
    if (toDrawCurrentZoom.size() <= 1) {
      return Integer.toString(this.zoomValue) + "_" + Integer.toString(this.zoomCenter);
    } else {
      // get the index of this object
      int index = toDrawCurrentZoom.indexOf(this);
      SeriesImage imageToLink;
      if (index == toDrawCurrentZoom.size() - 1) {
        imageToLink = (SeriesImage) toDrawCurrentZoom.get(0);
      } else {
        imageToLink = (SeriesImage) toDrawCurrentZoom.get(index + 1);
      }

      return Integer.toString(imageToLink.getZoomValue())
          + "_"
          + Integer.toString(imageToLink.getZoomCenter());
    }
  }

  /**
   * Determines which SeriesImage is adjacent to this SeriesImage in the counterclockwise direction.
   *
   * @param toDrawCurrentZoom a collection of SeriesImages drawn at the same zoom level as this
   *     SeriesImage.
   * @return a file name prefix to be used for linking purposes.
   */
  public String getCounterclockwiseFilePrefix(ArrayList toDrawCurrentZoom) {
    if (toDrawCurrentZoom.size() <= 1) {
      return Integer.toString(this.zoomValue) + "_" + Integer.toString(this.zoomCenter);
    } else {
      // get the index of this object
      int index = toDrawCurrentZoom.indexOf(this);
      SeriesImage imageToLink;
      if (index == 0) {
        imageToLink = (SeriesImage) toDrawCurrentZoom.get(toDrawCurrentZoom.size() - 1);
      } else {
        imageToLink = (SeriesImage) toDrawCurrentZoom.get(index - 1);
      }

      return Integer.toString(imageToLink.getZoomValue())
          + "_"
          + Integer.toString(imageToLink.getZoomCenter());
    }
  }
}
