/**
 * MyValve.java - MyValve class is water event source and listener
 * Copyright (c) 1997 by Dmitri Kondratiev
 *
 * @author <a href="mailto:dima@paragraph.com">Dmitri Kondratiev</a>
 * @version 1.0 Mar 1997
 * History :
 *
 * 10-Mar-97 - Created
 */

package bdktest.water;

import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Color;
import java.util.Vector;
import java.io.*;

public class MyValve extends Canvas implements WaterListener, 
                                                Runnable, Serializable {

  private Vector waterListeners = new Vector(); //list of listeners 
  //last water event received, will not serialize it
  transient private WaterEventObject lastWaterEvent; 
  private boolean open = true; //open/close valve property
  //thread class does not support the Serializable interface - will not serialize it
  transient Thread thread;  

  public MyValve() {
    dbgOut("Constuctor"); 
    resize(40,60);
    setBackground(Color.white); 
    initThread();
  }

  private void initThread() {

    if(thread == null) {
        thread = new Thread(this);
        thread.start();
    }
  }

/**
 * We implement writeObject method with this signature: 
 *
 * private void writeObject(java.io.ObjectOutputStream out)
 *     throws IOException
 *
 * We use the default mechanism for saving the Object's
 * by calling oos.defaultWriteObject. The method does not need to concern itself
 * with the state belonging to its superclasses or subclasses. State is saved by writing the individual
 * fields to the ObjectOutputStream using the writeObject method or by using the methods for primitive
 * data types supported by DataOutput. 
 */
  private void writeObject(ObjectOutputStream oos) throws IOException {

      oos.defaultWriteObject();
  }

/**
 * We implement readObject method with this signature: 
 *
 * private void readObject(java.io.ObjectInputStream in)
 *    throws IOException, ClassNotFoundException; 
 *
 * We use the default mechanism to restore the object's non-static
 * and non-transient fields from the stream by calling 
 * ois.defaultReadObject method.
 */
  private void readObject(ObjectInputStream ois) throws IOException {

    dbgOut("readObject");
    try {
      ois.defaultReadObject();
      thread = null;
      initThread();
    }
    catch(Exception e) {
      e.printStackTrace();
      throw new IOException("error in WaterSource.readObject" + e.getMessage());
    }
  }
  
  //property get and set methods
  public boolean isOpen() { 

		//dbgOut("isOpen() : "+open);
    return open; 
  }

  public void setOpen(boolean x) { 

		open = x; 
		//dbgOut("setOpen() to : "+open);
	}
  
  public Dimension getMinimumSize() { return new Dimension(40,60); }

  // this method is specified in the WaterListener interface 
  // (which this class implements).
  public void handleSplash(WaterEventObject e) { 
  
    lastWaterEvent = e; 
    if (isOpen()) { 
      setBackground(Color.blue); 
      repaint(); 
      splash(); 
    } 
  }

  public void run() { 
    while(true) { 
      try { thread.sleep(1000); } catch (Exception e) {}

      if (lastWaterEvent != null) { 
      // make the valve white if a WaterEventObject 
      // has not been recieved in the last 2 seconds or if 
      // the valve is closed
        long dt = System.currentTimeMillis() -lastWaterEvent. getTimeOfEvent(); 
        if ((dt > 2000) || (!isOpen())) { 
          setBackground(Color.white); 
          repaint(); 
        } 
      } 
    } 
  } 

  // BeanBox will call these methods to add and remove registered listeners
    
  public synchronized void addWaterListener(WaterListener l) { 
  
    waterListeners.addElement(l); 
  }

  public synchronized void removeWaterListener(WaterListener l) { 
  
    waterListeners.removeElement(l); 
  }


  // send a water event to registered listeners

  void splash() { 
  
    Vector l; 
    WaterEventObject weo = new WaterEventObject(this);

    synchronized(this) { 
      l = (Vector)waterListeners.clone(); 
    }

    // send a water event to registered listeners  
    for (int i = 0; i < l.size(); i++) { 
      WaterListener wl = (WaterListener) l.elementAt(i); 
      wl.handleSplash(weo);
    } 
  } 

	/**
	 * Print this module debug info
	 */
	void dbgOut(String msg) {

		System.out.println("MyValve : "+msg);
	}

}

