/*=========================================================================

  Program:   Orbit Visualization Tool
  Source:    $Source: /stor/devel/ovt2g/ovt/object/TimeSettings.java,v $
  Date:      $Date: 2001/04/19 17:58:40 $
  Version:   $Revision: 1.29 $


Copyright (c) 2000 OVT Team (Kristof Stasiewicz, Mykola Khotyaintsev, 
Yuri Khotyaintsev)
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification is permitted provided that the following conditions are met:

 * No part of the software can be included in any commercial package without
written consent from the OVT team.

 * Redistributions of the source or binary code must retain the above
copyright notice, this list of conditions and the following disclaimer.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT OR
INDIRECT DAMAGES  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE.

OVT Team (http://ovt.irfu.se)   K. Stasiewicz, M. Khotyaintsev, Y.
Khotyaintsev

=========================================================================*/

/*
 * TimeSettings.java
 *
 * Created on February 28, 2000, 11:00 AM
 */
 
package ovt.object;

import ovt.*;
import ovt.gui.*;
import ovt.util.*;
import ovt.beans.*;
import ovt.event.*;
import ovt.datatype.*;
import ovt.interfaces.*;
import ovt.object.editor.*;

import java.beans.*;

import java.awt.event.*;
import java.util.*;
import java.lang.reflect.*;

/** 
 *
 * @author  mykola
 * @version 
 */
public class TimeSettings extends BasicObject 
        implements ovt.interfaces.TimeSetSource, FireChangeMethodSource { // implements java.io.Serializable 

  /** Holds value of property customizerVisible. */
  private boolean customizerVisible = false;
    
  public static final String PROP_TIME = "time";
  public static final String PROP_CURRENT_MJD = "currentMjd";

//  private OVTPropertyChangeSupport propertySupport = new OVTPropertyChangeSupport ( this );

  private TimeChangeSupport timeChangeSupport = new TimeChangeSupport(this);
  /** Holds value of property startMjd. */
  private double startMjd = Time.getMjd("2000-01-01 00:00:00");
  /** Holds value of property intervalMjd. */
  private double intervalMjd = 1;
  /** Holds value of property stepMjd. */
  private double stepMjd = MinutesAndSeconds.getInDays("20:00");
  /** Holds value of property currentMjd. */
  private double currentMjd = startMjd;
  
  private TimeSet timeSet = new TimeSet(startMjd, intervalMjd, stepMjd, currentMjd);
  
  private TimeSettingsCustomizer customizer;
  
  /** Creates new TimeSettings */
  public TimeSettings(OVTCore core) {
    super(core, "TimeSettings");
    showInTree(false);
    //addVetoableChangeListener(this);
    
    try {
        Descriptors descriptors = new Descriptors();
        // startMjd
        BasicPropertyDescriptor pd = new BasicPropertyDescriptor("startMjd", this);
        pd.setDisplayName("Start Time");
        pd.setLabel("Start");
        
        GUIPropertyEditor editor = new MjdEditor(pd);
        pd.setPropertyEditor(editor);
        addPropertyChangeListener("startMjd", editor);
        descriptors.put(pd);
        
        // intervalMjd
        pd = new BasicPropertyDescriptor("intervalMjd", this);
        pd.setDisplayName("Interval Time");
        pd.setLabel("Interval");
        
        editor = new IntervalEditor(pd);
        pd.setPropertyEditor(editor);
        addPropertyChangeListener("intervalMjd", editor);
        descriptors.put(pd);
        
        // stepMjd
        pd = new BasicPropertyDescriptor("stepMjd", this);
        pd.setDisplayName("Step");
        pd.setLabel("Step");
        //pd.setTextOnlyAccessible();
        
        editor = new IntervalEditor(pd);
        pd.setPropertyEditor(editor);
        addPropertyChangeListener("stepMjd", editor);
        descriptors.put(pd);
        
        // currentMjd
        pd = new BasicPropertyDescriptor("currentMjd", this);
        pd.setDisplayName("Current Time");
        pd.setLabel("Current Time");
        
        editor = new CurrentMjdEditor(pd);
        // Render each time user changes time by means of gui
        editor.addGUIPropertyEditorListener(new GUIPropertyEditorListener() {
          public void editingFinished(GUIPropertyEditorEvent evt) {
            timeChangeSupport.fireTimeChange(PROP_CURRENT_MJD, null, timeSet);
            Render();
          }
        });
        
        addPropertyChangeListener("currentMjd", editor);
        addPropertyChangeListener("time", editor);
        
        pd.setPropertyEditor(editor);
        descriptors.put(pd);
        
        setDescriptors(descriptors);
    } catch (IntrospectionException e2) {
        System.out.println(getClass().getName() + " -> " + e2.toString());
        System.exit(0);
    }
    
    if (!OVTCore.isServer()) customizer = new TimeSettingsCustomizer(this);
    
  }

  public void addTimeChangeListener (TimeChangeListener listener) {
    timeChangeSupport.addTimeChangeListener (listener);
  }

  public void removeTimeChangeListener (TimeChangeListener listener) {
    timeChangeSupport.removeTimeChangeListener (listener);
  }

  public void fireTimeChange() {
    timeSet.setStartMjd(startMjd);
    timeSet.setIntervalMjd(intervalMjd);
    timeSet.setStepMjd(stepMjd);
    //Log.log("before adjustment"+timeSet, 0);
    timeSet.adjustInterval(); // adjust interval
    setIntervalMjd(intervalMjd); 
    //timeSet.setCurrentMjd(timeSet.getClosestFor(getCurrentMjd()));
    //Log.log("after adjustment"+timeSet+"\n", 10);
    
    //Log.log("Optimal currentMjd is " + new Time(timeSet.getClosestFor(getCurrentMjd())), 0);
    
    setIntervalMjd(timeSet.getIntervalMjd());
    timeSet.setCurrentMjd(timeSet.getClosestFor(getCurrentMjd()));
    this.currentMjd = timeSet.getCurrentMjd();
    
    timeChangeSupport.fireTimeChange(new TimeEvent(this, "time", null, timeSet));
    firePropertyChange("time", null, null);
  }
  
  /** Should be used instead of get*Mjd methods. 
   * @return actual TimeSet of OVT including currentMjd 
   */
  public TimeSet getTimeSet() { 
      return timeSet; 
  }
  
  /** Getter for property startMjd.
   * @return Value of property startMjd.
   */
  public double getStartMjd() {
    return startMjd;
  }
  /** Setter for property startMjd.
   * @param startMjd New value of property startMjd.
   *
   * @throws PropertyVetoException
   */
  public void setStartMjd(double startMjd) throws IllegalArgumentException {
      double oldStartMjd = this.startMjd;
      double oldStopMjd = getStopMjd();
      if (startMjd == oldStartMjd) return;
      if (startMjd < Time.Y1970) throw new IllegalArgumentException("Start time could not be earlier then 1970");
      this.startMjd = startMjd;
      //this.currentMjd = getTimeSet().getClosestFor(currentMjd);
      firePropertyChange("startMjd", new Double(oldStartMjd), new Double(startMjd));
      firePropertyChange("stopMjd", new Double(oldStopMjd), new Double(getStopMjd()));
  }
  
  public double getIntervalMjd() {
    return intervalMjd;
  }
  
  public void setIntervalMjd(double intervalMjd) throws IllegalArgumentException {
      double oldIntervalMjd = this.intervalMjd;
      if (intervalMjd == oldIntervalMjd) return;
      //System.out.println("setIntervalMjd: "+new Interval(intervalMjd));
      if (intervalMjd <= 0) throw new IllegalArgumentException("Interval "+intervalMjd+" <= 0");
      this.intervalMjd = intervalMjd;
      //this.currentMjd = getTimeSet().getClosestFor(currentMjd);
      firePropertyChange("intervalMjd", new Double(oldIntervalMjd), new Double(intervalMjd));
  }
  
  /** Getter for property stopMjd.
   * @return Value of property stopMjd.
   */
  public double getStopMjd() {
    return startMjd + intervalMjd;
  }
  /** Setter for property stopMjd.
   * @param stopMjd New value of property stopMjd.
   *
   * @throws PropertyVetoException
   */
  public void setStopMjd(double stopMjd) throws IllegalArgumentException {
        setIntervalMjd(stopMjd - startMjd);
  }
  
  /** Getter for property stepMjd.
   * @return Value of property stepMjd.
   */
  public double getStepMjd() {
    return stepMjd;
  }
  /** Setter for property stepMjd.
   * @param stepMjd New value of property stepMjd.
   *
   * @throws PropertyVetoException
   */
  public void setStepMjd(double stepMjd) throws IllegalArgumentException {
      double oldStepMjd = this.stepMjd;
      if ( intervalMjd / stepMjd < 1) throw new IllegalArgumentException("Number of steps is less then 1");
      // check number of points
      if ( intervalMjd / stepMjd > 400) getCore().sendWarningMessage("Warning", "Number of steps exceeds 400");
      this.stepMjd = stepMjd;
      firePropertyChange("stepMjd", new Double(oldStepMjd), new Double(stepMjd));
  }
  
  /** Getter for property currentMjd.
   * @return Value of property currentMjd.
   */
  public double getCurrentMjd() {
    //return timeSet.getCurrentMjd();
      return currentMjd;
  }
  /** Setter for property currentMjd.
   * @param currentMjd New value of property currentMjd.
   *
   * @throws PropertyVetoException
   */
  public void setCurrentMjd(double currentMjd) throws IllegalArgumentException {
    double oldCurrentMjd = getCurrentMjd();
    
    if (currentMjd > getStopMjd() + 2e-10 ) {
        String reason = "Time is greater, than stop time\n(" +
                  Time.toString(currentMjd)+" > " + 
                  Time.toString(getStopMjd())+") ";// +currentMjd+" "+getStopMjd();
        throw new IllegalArgumentException(reason);
      }
      
      if (currentMjd < getStartMjd()) {
        String reason = "Current time could not be earlier than start time\n(" +
                  Time.toString(currentMjd)+" < " + 
                  Time.toString(getStartMjd())+")";
        throw new IllegalArgumentException(reason);
      }
    
    TimeSet tSet = new TimeSet(this);
    this.currentMjd = tSet.getClosestFor(currentMjd);
    timeSet.setCurrentMjd(this.currentMjd);
    
    firePropertyChange(PROP_CURRENT_MJD, new Double (oldCurrentMjd), new Double (currentMjd));
    //timeChangeSupport.fireTimeChange(PROP_CURRENT_MJD, null, timeSet);
  }
  

  
  /** returns time, from wich is possible to start 
   *
   *
  public double getStartFor(double mjd) {
    double start = getStartMjd();
    double step = getStepMjd();
    if (mjd <= start) return start;
    else {
      // mjd > startMjd
      int n = (int)((mjd - start) / step);
      return start + step * (n + 1);
    }
  }*/
  
  /** Getter for property customizerVisible.
 * @return Value of property customizerVisible.
 */
public boolean isCustomizerVisible() {
    if (!OVTCore.isServer()) return customizer.isVisible();  
    else return false; 
}

/** Setter for property customizerVisible.
 * @param customizerVisible New value of property customizerVisible.
 */
public void setCustomizerVisible(boolean customizerVisible) {
  boolean oldCustomizerVisible = isCustomizerVisible();
  if (oldCustomizerVisible && customizerVisible) {
      if (!OVTCore.isServer()) customizer.toFront();
  }
  if (!OVTCore.isServer()) { 
        customizer.setVisible(customizerVisible);
        propertyChangeSupport.firePropertyChange ("customizerVisible", new Boolean (oldCustomizerVisible), new Boolean (customizerVisible));
  }
}

public java.lang.reflect.Method getFireChangeMethod() {
    Method method = null;
    try {
         method = getClass().getMethod("fireTimeChange", null);
    } catch (NoSuchMethodException e2) { e2.printStackTrace(); System.exit(-1); }
    return method; 
}

}

