// $Id: StationObsViewer.java,v 1.7 2004/12/14 15:41:02 caron Exp $
/*
 * Copyright 1997-2004 Unidata Program Center/University Corporation for
 * Atmospheric Research, P.O. Box 3000, Boulder, CO 80307,
 * support@unidata.ucar.edu.
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

package ucar.nc2.ui;

import ucar.nc2.*;
import ucar.nc2.station.*;

import ucar.util.prefs.*;
import ucar.util.prefs.ui.*;
import ucar.unidata.geoloc.ProjectionRect;
import ucar.unidata.geoloc.LatLonRect;
import thredds.ui.*;
import thredds.datatype.DateRange;
import thredds.datatype.DateType;
import thredds.datatype.TimeDuration;
import thredds.viewer.ui.station.StationIF;

import java.awt.BorderLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.io.*;
import java.util.*;
import java.beans.PropertyChangeListener;
import java.text.ParseException;

import javax.swing.*;
import javax.swing.event.*;

/**
 * A Swing widget to view the contents of a ucar.nc2.station.StationObsDataset.
 *
 * The available Stations are shown in a BeanTable.
 * The obs are shown in a StructureTabel.
 *
 * @author John Caron
 * @version $Id: StationObsViewer.java,v 1.7 2004/12/14 15:41:02 caron Exp $
 */

public class StationObsViewer extends JPanel {
  private PreferencesExt prefs;

  private StationObsDataset ds;
  private ArrayList stationBeans;

  private thredds.viewer.ui.station.StationRegionChooser mapChooser;
  private thredds.ui.RangeDateSelector dateSelector;
  private IndependentWindow dateWindow;
  private BeanTableSorted stnTable;
  private StructureTable obsTable;
  private JSplitPane splitH = null, splitV = null;
  private TextHistoryPane infoTA;
  private IndependentWindow infoWindow;

  private boolean eventsOK = true;
  private boolean debugStationReginSelect = false, debugDateSelect = false, debugQuery = false;

  public StationObsViewer(PreferencesExt prefs) {
    this.prefs = prefs;

    mapChooser = new thredds.viewer.ui.station.StationRegionChooser();
    mapChooser.addPropertyChangeListener( new PropertyChangeListener() {
      public void propertyChange(java.beans.PropertyChangeEvent e) {
        if (e.getPropertyName().equals("Station")) {
          StationBean selectedStation = (StationBean) e.getNewValue();
          if (debugStationReginSelect) System.out.println("selectedStation= "+selectedStation.getName());
          eventsOK = false;
          stnTable.setSelectedBean( selectedStation);
          eventsOK = true;
        }
        else if (e.getPropertyName().equals("GeoRegion")) {
          ProjectionRect geoRegion = (ProjectionRect) e.getNewValue();
          if (debugStationReginSelect) System.out.println("geoRegion= "+geoRegion);
        }
      }
    });

    // date selection
    DateRange range = null;
    try {
      range = new DateRange( null, new DateType( false, new Date()), new TimeDuration("3 days"), new TimeDuration("15 min"));
    } catch (ParseException e) {
      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
    dateSelector = new RangeDateSelector(null, range, false, null, false);
    dateWindow = new IndependentWindow("Date Selection", BAMutil.getImage( "netcdfUI"), dateSelector);
    AbstractAction dateAction = new AbstractAction() {
      public void actionPerformed(ActionEvent e) {
        dateWindow.show();
      }
    };
    BAMutil.setActionProperties( dateAction, "selectDate", "select date range", false, 'D', -1);
    mapChooser.addToolbarAction( dateAction);

    // do the query
    AbstractAction queryAction = new AbstractAction() {
      public void actionPerformed(ActionEvent e) {
        if (ds == null) return;

        // is the date window showing ?
        Date startDate = null, endDate = null;
        boolean useDate = dateWindow.isShowing();
        if (useDate) {
          DateRange dateRange = dateSelector.getSelectedDateRange();
          startDate = dateRange.getStart().getDate();
          endDate = dateRange.getEnd().getDate();
          if (debugQuery) System.out.println("date range="+dateRange);
        }

        // is the geoRegion mode true ?
        LatLonRect geoRegion = null;
        StationObsDataset.Station selectedStation = null;
        boolean useRegion = mapChooser.getGeoSelectionMode();
        if (useRegion) {
          geoRegion = mapChooser.getGeoSelectionLL();
          StationIF sbean = mapChooser.getSelectedStation();
          if (sbean != null)
            selectedStation = ((StationBean) sbean).station;
          if (debugQuery) System.out.println("geoRegion="+geoRegion);
        }

        if ((selectedStation == null) && !useRegion) return;

        // fetch the requested dobs
        try {
          List obsList = null;
          if (useRegion)
            obsList = useDate ? ds.getStationObs(geoRegion, startDate, endDate) : ds.getStationObs(geoRegion);
          else
            obsList = useDate ? ds.getStationObs(selectedStation, startDate, endDate) : ds.getStationObs(selectedStation);

          if (debugQuery)System.out.println("obsList="+obsList.size());
          setObservations( obsList);

        } catch (IOException e1) {
          e1.printStackTrace();
        }
      }
    };
    BAMutil.setActionProperties( queryAction, "query", "query for data", false, 'Q', -1);
    mapChooser.addToolbarAction( queryAction);

    // station table
    stnTable = new BeanTableSorted(StationBean.class, (PreferencesExt) prefs.node("StationBeans"), false);
    stnTable.addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        StationBean sb = (StationBean) stnTable.getSelectedBean();
        setStation( sb);
        if (debugStationReginSelect) System.out.println("stnTable selected= "+sb.getName());
        if (eventsOK) mapChooser.setSelectedStation( sb.getName());
      }
    });

    // the obs table
    obsTable = new StructureTable( (PreferencesExt) prefs.node("ObsBean"));

    // the info window
    infoTA = new TextHistoryPane();
    infoWindow = new IndependentWindow("Station Information", BAMutil.getImage( "netcdfUI"), infoTA);
    infoWindow.setBounds( (Rectangle) prefs.getBean("InfoWindowBounds", new Rectangle( 300, 300, 500, 300)));

    // layout
    splitH = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, false, stnTable, mapChooser);
    splitH.setDividerLocation(prefs.getInt("splitPosH", 400));

    splitV = new JSplitPane(JSplitPane.VERTICAL_SPLIT, false, splitH, obsTable);
    splitV.setDividerLocation(prefs.getInt("splitPos", 500));

    setLayout(new BorderLayout());
    add(splitV, BorderLayout.CENTER);
  }

  public void addMapBean( thredds.viewer.gis.MapBean mb) {
    mapChooser.addMapBean( mb);
  }

  public void setDataset(StationObsDataset stationDataset) {
    this.ds = stationDataset;
    Date startDate = ds.getStartDate();
    Date endDate = ds.getEndDate();
    if ((startDate != null) && (endDate != null))
      dateSelector.setDateRange( new DateRange( startDate, endDate));

    stationBeans = new ArrayList();

    try {
      List stations = ds.getStations();
      if (stations == null) return;

      for (int i = 0; i < stations.size(); i++) {
        stationBeans.add( new StationBean((StationObsDataset.Station) stations.get(i)));
      }

    } catch (IOException ioe) {
      ioe.printStackTrace();
      return;
    }
    
    stnTable.setBeans( stationBeans);
    mapChooser.setStations( stationBeans);
    mapChooser.redraw();
  }

  public void setStation(StationBean sb) {
    try {
      List obsList = ds.getStationObs(sb.station);
      sb.setCount( obsList.size());
      stnTable.getJTable().repaint();

      setObservations( obsList);

    } catch (IOException e) {
      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
  }

  /**
   * Set the list of Obs to show in the obs table
   * @param obsList list of type StationObsDataset.StationObs
   */
  public void setObservations(List obsList) throws IOException {
      if (obsList.size() == 0) {
        obsTable.clear();
        return;
      }

      ArrayList stationData = new ArrayList();
      Structure struct = null;
      for (int i = 0; i < obsList.size(); i++) {
        StationObsDataset.StationObs obs = (StationObsDataset.StationObs) obsList.get(i);
        stationData.add( obs.getData());
        if (i == 0) struct = obs.getData().getStructure();
      }
      obsTable.setStructureData( struct, stationData);
  }

  public PreferencesExt getPrefs() { return prefs; }

  public void save() {
   stnTable.saveState(false);
   prefs.putBeanObject("InfoWindowBounds", infoWindow.getBounds());
   prefs.putInt("splitPos", splitV.getDividerLocation());
   prefs.putInt("splitPosH", splitH.getDividerLocation());
   obsTable.saveState();
  }

  public class StationBean implements thredds.viewer.ui.station.StationIF {
    // static public String editableProperties() { return "title include logging freq"; }
    //static public String hiddenProperties() { return "recordNum"; }

    private StationObsDataset.Station station;
    private int count;

    // no-arg constructor
    public StationBean() {}

    public StationBean( StationObsDataset.Station s) {
      this.station = s;
      count = ds.getStationObsCount(s);
    }


    //public String getID() { return station.getName(); }
    public String getName() { return station.getName(); }

    public String getDescription() { return station.getDescription(); }

    public double getLatitude() { return station.getLatitude(); }
    public double getLongitude() { return station.getLongitude(); }
    public double getElevation() { return station.getElevation(); }
    public int getCount() { return count; }
    public void setCount( int count) { this.count = count; }
   }

  public class StationObsBean {
    private StationObsDataset.StationObs obs;
    private Date timeObs;

    public StationObsBean( StationObsDataset.StationObs obs) {
      this.obs = obs;
      setTime( obs.getTime());
    }

    public Date getTime() { return timeObs; }
    public void setTime( Date timeObs) { this.timeObs = timeObs; }

    public String getStation() { return obs.getStation().getName(); }
  }

}

/* Change History:
   $Log: StationObsViewer.java,v $
   Revision 1.7  2004/12/14 15:41:02  caron
   *** empty log message ***

   Revision 1.6  2004/11/16 23:35:38  caron
   no message

   Revision 1.5  2004/09/30 00:33:42  caron
   *** empty log message ***

   Revision 1.4  2004/09/28 21:37:19  caron
   *** empty log message ***

   Revision 1.3  2004/09/22 13:46:39  caron
   *** empty log message ***

   Revision 1.2  2004/09/09 22:47:41  caron
   station updates

   Revision 1.1  2004/08/26 17:55:09  caron
   no message

   Revision 1.3  2004/08/17 19:20:07  caron
   2.2 alpha (2)

   Revision 1.2  2004/07/12 23:40:19  caron
   2.2 alpha 1.0 checkin

   Revision 1.1  2004/07/06 19:28:13  caron
   pre-alpha checkin

   Revision 1.3  2003/10/28 23:57:21  caron
   minor

   Revision 1.2  2003/10/02 20:33:56  caron
   move SimpleUnit to dataset; add <units> tag; add projections to CF

   Revision 1.1  2003/06/09 15:23:17  caron
   add nc2.ui

   Revision 1.1  2003/04/08 18:19:11  john
   nc2.ui

 */