package ucar.nc2.station;

import ucar.unidata.geoloc.LatLonRect;
import ucar.unidata.geoloc.LatLonPointImpl;

import java.util.*;
import java.io.IOException;

/**
 * Helper class for StationObsDataset.
 */
public class StationDatasetHelper {
  private StationObsDataset obsDataset;
  private HashMap stationHash;

  public StationDatasetHelper( StationObsDataset obsDataset) {
    this.obsDataset = obsDataset;
  }

  private LatLonRect rect;
  public LatLonRect getBoundingBox() {
    if (rect == null) {
      List stations = null;
      try {
        stations = obsDataset.getStations();
      } catch (IOException e) {
        return null;
      }
      if (stations.size() == 0)
        return null;

      StationObsDataset.Station s =  (StationObsDataset.Station) stations.get(0);
      LatLonPointImpl llpt = new LatLonPointImpl();
      llpt.set( s.getLatitude(), s.getLongitude());
      rect = new LatLonRect(llpt, .001, .001);

      for (int i = 1; i < stations.size(); i++) {
        s =  (StationObsDataset.Station) stations.get(i);
        llpt.set( s.getLatitude(), s.getLongitude());
        rect.extend( llpt);
      }
    }

    return rect;
  }

  /* public LatLonRect getBoundingBox() {
    if (rect == null) {
      List stations = null;
      try {
        stations = obsDataset.getStations();
      } catch (IOException e) {
        e.printStackTrace();
        return null;
      }

      double minlat = 1000, minlon = 1000;
      double maxlat = -1000, maxlon = -1000;
      for (int i = 0; i < stations.size(); i++) {
        StationObsDataset.Station s =  (StationObsDataset.Station) stations.get(i);
        minlat = Math.min( minlat, s.getLatitude());
        maxlat = Math.max( maxlat, s.getLatitude());
        double lon = LatLonPointImpl.range180(s.getLongitude());
        minlon = Math.min( minlon, lon);
        maxlon = Math.max( maxlon, lon);
      }

      rect = new LatLonRect(new LatLonPointImpl(minlat, minlon), new LatLonPointImpl(maxlat, maxlon));
    }

    return rect;
  } */

  public List getStations(LatLonRect boundingBox) throws IOException {
    LatLonPointImpl latlonPt = new LatLonPointImpl();
    ArrayList result = new ArrayList();
    List stations = obsDataset.getStations();
    for (int i = 0; i < stations.size(); i++) {
      StationObsDataset.Station s =  (StationObsDataset.Station) stations.get(i);
      latlonPt.set( s.getLatitude(), s.getLongitude());
      if (boundingBox.contains( latlonPt))
        result.add( s);
    }
    return result;
  }

  public StationObsDataset.Station getStation(String name) {
    if (stationHash == null) {
      List stations = null;
      try {
        stations = obsDataset.getStations();
      } catch (IOException e) {
        return null;
      }

      stationHash = new HashMap( 2*stations.size());
      for (int i = 0; i < stations.size(); i++) {
        StationObsDataset.Station s =  (StationObsDataset.Station) stations.get(i);
        stationHash.put( s.getName(), s);
      }
    }

    return (StationObsDataset.Station) stationHash.get( name);
  }

  public List getStationObs(StationObsDataset.Station s, Date start, Date end) throws IOException {
    ArrayList result = new ArrayList();
    List stationObs = obsDataset.getStationObs( s);
    for (int i = 0; i < stationObs.size(); i++) {
      StationObsDataset.StationObs obs =  (StationObsDataset.StationObs) stationObs.get(i);
      Date obsTime = obs.getTime();
      if (start.before(obsTime) && end.after(obsTime))
        result.add( obs);
    }
    return result;
  }

  public List getStationObs(List stations) throws IOException {
    ArrayList result = new ArrayList();
    for (int i = 0; i < stations.size(); i++) {
      StationObsDataset.Station s = (StationObsDataset.Station) stations.get(i);
      result.addAll( obsDataset.getStationObs( s));
    }
    return result;
  }

  public List getStationObs(List stations, Date start, Date end) throws IOException {
    ArrayList result = new ArrayList();
    for (int i = 0; i < stations.size(); i++) {
      StationObsDataset.Station s = (StationObsDataset.Station) stations.get(i);
      result.addAll( obsDataset.getStationObs( s, start, end));
    }
    return result;
  }

  public List getStationObs(LatLonRect boundingBox) throws IOException {
    List stations = obsDataset.getStations( boundingBox);
    return getStationObs( stations);
  }

  public List getStationObs(LatLonRect boundingBox, Date start, Date end) throws IOException {
    List stations = obsDataset.getStations( boundingBox);
    return getStationObs( stations, start, end);
  }

  public void sortByTime(List stationObs) {
    Collections.sort( stationObs, new StationObsComparator());
  }

  private class StationObsComparator implements Comparator {
    public int compare(Object o1, Object o2) {
      StationObsDataset.StationObs s1 = (StationObsDataset.StationObs) o1;
      StationObsDataset.StationObs s2 = (StationObsDataset.StationObs) o2;
      return s1.getTime().compareTo( s2.getTime());
    }
  }

}
