import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;

/**
 * Title:        WaterMixApplet
 * Description:  Mixing water with Fuzzy Logic
 * Copyright:    Copyright (c) 2001
 * @author S. Robl <stefan@qdev.de>, A. Heinze <mail@aheinze.de>
 * @version 1.0
 */

public class WaterMixApplet extends JApplet 
{
  boolean isStandalone = false;

  // my variables
  private myDebug debug = new myDebug(10);
  private panControls panCtrls = new panControls();
  private boolean reset = false;
  private panWaterMixAnim panAnim = new panWaterMixAnim();
  private WaterMixFuzzyLogic watermix=new WaterMixFuzzyLogic();
  private panFuzzyGraphic panFuzzyVol=new panFuzzyGraphic();
  private panFuzzyGraphic panFuzzyTemp=new panFuzzyGraphic();
  private panFuzzyGraphic panFuzzyFill=new panFuzzyGraphic();
  private panTemperature panTemp = new panTemperature();
  private boolean animationFinished = true, abortAnimationFlag=false;
  private WaterMixAppletAnimThread animationThread = null;

  // double-buffering
  private Image dbImage;
  private Graphics dbGraphics;

  // jb_variables
  JLabel lblTitle = new JLabel();

  /**Get a parameter value*/
  public String getParameter(String key, String def) 
  {
    return isStandalone ? System.getProperty(key, def) : (getParameter(key) != null ? getParameter(key) : def);
  }

  /**Construct the applet*/
  public WaterMixApplet() 
  {
  }

  /**Initialize the applet*/
  public void init() 
  {
    debug.Write("WaterMixApplet:Init()",0);

    panFuzzyTemp.setFuzzyCollection(watermix.getTempFuzzyCollection(),true);
    panFuzzyVol.setFuzzyCollection(watermix.getRemainVolFuzzyCollection(),true);
    panFuzzyFill.setFuzzyCollection(watermix.getFillVolFuzzyCollection(),false);

    panFuzzyTemp.setTitle("Temperature");
    panFuzzyVol.setTitle("Water volume");
    panFuzzyFill.setTitle("Filling volume");

    try 
    {
      jbInit();
    }
    catch(Exception e) 
    {
      e.printStackTrace();
    }
  }

  /**Component initialization*/
  private void jbInit() throws Exception 
  {
    debug.Write("WaterMixApplet:jbInit()",0);

    lblTitle.setFont(new java.awt.Font("Dialog", 1, 20));
    lblTitle.setText("WaterMixApplet");
    lblTitle.setBounds(new Rectangle(7, 5, 159, 26));

    panAnim.setBounds(new Rectangle(5, 40, 260, 340));
    panTemp.setBounds(new Rectangle(5, 385, 260, 170));

    panCtrls.setBounds(new Rectangle(270, 40, 380, 170));

    panFuzzyTemp.setBounds(new Rectangle(270, 215, 380, 110));
    panFuzzyVol.setBounds(new Rectangle(270, 330, 380, 110));
    panFuzzyFill.setBounds(new Rectangle(270, 445, 380, 110));

    this.setSize(new Dimension(657, 561));
    this.getContentPane().setLayout(null);

    // control-panel eventhandler
    panCtrls.sldTcold.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        sldTcold_stateChanged(e);
      }
    });
    
    panCtrls.sldThot.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        sldThot_stateChanged(e);
      }
    });
    
    panCtrls.sldTstart.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        sldTstart_stateChanged(e);
      }
    });
    
    panCtrls.sldTtarget.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        sldTtarget_stateChanged(e);
      }
    });
    panCtrls.sldVstart.addChangeListener(new javax.swing.event.ChangeListener() {
      public void stateChanged(ChangeEvent e) {
        sldVstart_stateChanged(e);
      }
    });
    
    InitValues();

    // Buttons
    panCtrls.btnStart.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        btnStart_actionPerformed(e);
      }
    });

    panCtrls.btnReset.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        btnReset_actionPerformed(e);
      }
    });

    panCtrls.btnStep.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        btnStep_actionPerformed(e);
      }
    });
    // end control-panle events

    this.getContentPane().add(lblTitle, null);
    this.getContentPane().add(panCtrls, null);
    this.getContentPane().add(panFuzzyVol, null);
    this.getContentPane().add(panFuzzyFill, null);
    this.getContentPane().add(panFuzzyTemp, null);
    this.getContentPane().add(panAnim, null);
    this.getContentPane().add(panTemp, null);
  }

  /**Start the applet*/
  public void start() 
  {
    debug.Write("WaterMixApplet:start()",0);
  }

  /**Stop the applet*/
  public void stop() 
  {
    debug.Write("WaterMixApplet:stop()",0);
  }

  public void paint(Graphics g) 
  {
    debug.Write("WaterMixApplet:paint()",0);
    super.paint(g);
  }

  public void update(Graphics g)
  {
    // initialize double-buffer
   /* if (dbImage == null) 
    {
      dbImage = createImage(panAnim.getSize().width, panAnim.getSize().height+50);
      dbGraphics = dbImage.getGraphics();
    }
	*/
    
	dbGraphics = this.getGraphics();
	
    // clear background
    //dbGraphics.setColor(getBackground());
    //dbGraphics.fillRect(0, 0, this.getSize().width, this.getSize().height);
	
	//dbGraphics.setColor(Color.black);
	//dbGraphics.fillRect(0, 0, this.getSize().width, this.getSize().height);
    
    // draw foreground
    //dbGraphics.setColor(getForeground());
    paint(this.getGraphics());
    
    // draw offscreen image
    //g.drawImage(dbImage,0,0,panAnim);
  }

  /**Destroy the applet*/
  public void destroy() 
  {
    debug.Write("WaterMixApplet:destroy()",0);
  }

  /**Get Applet information*/
  public String getAppletInfo() 
  {
    return "WaterMixApplet - FH Regensburg - Neuronale Netze - Stefan Robl, Alexander Heinze";
  }
  /**Get parameter info*/
  public String[][] getParameterInfo() 
  {
    return null;
  }

  private void InitValues() 
  {
    debug.Write("Initialise Fuzzy-Values! - " +
                              panCtrls.sldTstart.getValue() + ", " +
							  panCtrls.sldVstart.getValue()/10 + ", " +
							  panCtrls.sldTcold.getValue() + ", " +
							  panCtrls.sldThot.getValue() + ", " +
							  panCtrls.sldTtarget.getValue() + ", " +
							  10.0,7);
							  
    watermix.setInitialValues(panCtrls.sldTstart.getValue(),
                          panCtrls.sldVstart.getValue()/10,
                          panCtrls.sldTcold.getValue(),
                          panCtrls.sldThot.getValue(),
                          panCtrls.sldTtarget.getValue(),
                          10.0);
						  
    panAnim.CupCold.setLevel(100);
    panAnim.CupCold.setWaterTemp(watermix.getColdCupWaterTemp());
    panAnim.CupHot.setLevel(100);
    panAnim.CupHot.setWaterTemp(watermix.getHotCupWaterTemp());
    panAnim.WaterCont.setLevel(0,10,watermix.getContainerWaterVolume());
    panAnim.WaterCont.setWaterTemp(watermix.getContainerWaterTemp());

    panAnim.setCupLabelValues(panAnim.CupCold.getWaterTemp() , watermix.getColdCupWaterVolume(),
                              panAnim.CupHot.getWaterTemp(), watermix.getHotCupWaterVolume());
    panAnim.setContainerLabelValues(watermix.getContainerWaterTemp(), watermix.getContainerWaterVolume());

    panTemp.reset();
    panTemp.setTargetTemperature(panCtrls.sldTtarget.getValue());
    panTemp.addTemperature(panCtrls.sldTstart.getValue());

    reset=true;

    panTemp.paint(panTemp.getGraphics());
    this.getContentPane().add(panAnim, null);
    this.getContentPane().add(panCtrls, null);
    this.getContentPane().add(panTemp, null);
    this.getContentPane().add(panFuzzyTemp, null);
    this.getContentPane().add(panFuzzyVol, null);
    this.getContentPane().add(panFuzzyFill, null);
    this.getContentPane().add(lblTitle, null);
	
	update(this.getGraphics());
  }

  void sldTcold_stateChanged(ChangeEvent e) 
  {
    debug.Write("sldTcold_statechanged",3);
    // change temperature of cold water
    InitValues();
  }

  void sldThot_stateChanged(ChangeEvent e) 
  {
    debug.Write("sldThot_statechanged",3);
    // change temperature of hot water
    InitValues();
  }

  void sldTstart_stateChanged(ChangeEvent e) 
  {
    debug.Write("sldTstart_statechanged",3);
    // change start temperature
    InitValues();
  }

  void sldTtarget_stateChanged(ChangeEvent e) 
  {
    debug.Write("sldTtarget_statechanged",3);
    // change end-temperature
    InitValues();
  }

  void sldVstart_stateChanged(ChangeEvent e) 
  {
    debug.Write("sldVstart_statechanged",3);
    // change start volume
    InitValues();
  }

  void btnStart_actionPerformed(ActionEvent e) 
  {
    debug.Write("btnStart_actionPerformed",3);
	// start button clicked
	if (animationThread==null)
	  startAnimation(true);
	else
	  abortAnimationFlag=true;
  }
  
  void startAnimation(boolean animation)
  {
	if (animationThread==null)
	{
	  abortAnimationFlag=false;
	  panCtrls.setAnimationState(true);
	  animationThread = new WaterMixAppletAnimThread(this, animation);
	  Thread thread = new Thread(animationThread);
	  thread.start();
	}
  }
  
  public void setAnimationState(boolean finished)
  {
	if (finished)
	{
		animationThread = null;
		panCtrls.setAnimationState(false);
	}
  }
  
  public void setResetFalse()
  {
	reset = false;
  }
  
  public boolean getReset()
  {
	return reset;
  }
  
  public boolean getAbortAnimationFlag()
  {
    return abortAnimationFlag;
  }
  
  public boolean finishedCalculation()
  {
	return watermix.finishedCalculation();
  }
  
  void btnStep_actionPerformed(ActionEvent e) 
  {
    debug.Write("btnStep_actionPerformed",3);
    // step button clicked
	startAnimation(false);
  }
  
  void singleStep()
  {
    if (watermix.finishedCalculation()) 
    {
      debug.Write("Calculation finished!",7);
      return;
    }

    double oldWaterContVolume=watermix.getContainerWaterVolume();
    double oldWaterContTemp=watermix.getContainerWaterTemp();
    watermix.singleCalculation();

    panAnim.setCupLabelValues(panAnim.CupCold.getWaterTemp() , watermix.getColdCupWaterVolume(),
                              panAnim.CupHot.getWaterTemp(), watermix.getHotCupWaterVolume());

    panFuzzyFill.paint(panFuzzyFill.getGraphics());
    panFuzzyTemp.paint(panFuzzyTemp.getGraphics());
    panFuzzyVol.paint(panFuzzyVol.getGraphics());

    animate(watermix.getColdCupWaterVolume(),0,
            watermix.getHotCupWaterVolume(),0,
            oldWaterContVolume,watermix.getContainerWaterVolume(),
            oldWaterContTemp,watermix.getContainerWaterTemp(),
            20,1);

    panTemp.addTemperature(watermix.getContainerWaterTemp());
    panTemp.paint(panTemp.getGraphics());

    debug.Write("WaterCont_Level: " + watermix.getContainerWaterVolume(),7);
    debug.Write("WaterCont_Temp: " + watermix.getContainerWaterTemp(),7);

    if (watermix.getColdOrHotCup()) 
      debug.Write("FillWater: COLD - " + watermix.getColdCupWaterVolume(),7);
    else
      debug.Write("FillWater: HOT  - " + watermix.getHotCupWaterVolume(),7);
	  
	update(this.getGraphics());
  }
  
  void animate(double ColdLevelBefore, double ColdLevelAfter,
               double HotLevelBefore, double HotLevelAfter,
               double ContainerLevelBefore, double ContainerLevelAfter,
               double ContainerTempBefore, double ContainerTempAfter,
               int steps, int delay) 
  {
    boolean cold=true; // cold or hot water?
    
    if (ColdLevelBefore==ColdLevelAfter)
      cold=false;

    double ColdDiff=(ColdLevelAfter-ColdLevelBefore)/steps;
    double HotDiff=(HotLevelAfter-HotLevelBefore)/steps;
    double ContDiff=(ContainerLevelAfter-ContainerLevelBefore)/steps;
    double TempDiff=(ContainerTempAfter-ContainerTempBefore)/steps;



	panAnim.initRender(cold, panAnim.CupCold.getWaterColor(), panAnim.CupHot.getWaterColor(), steps);


    for (int i=1; i<=steps; i++) // steps iterations
    {
      if (cold)
        panAnim.CupCold.setLevel(0,1,ColdLevelBefore+i*ColdDiff);
      else
        panAnim.CupHot.setLevel(0,1,HotLevelBefore+i*HotDiff);
      
      panAnim.renderStep();
	  panAnim.update(panAnim.getGraphics());
      
      try { Thread.sleep(delay); } catch (InterruptedException ie) { }
    }

    for (int i=1; i<=steps; i++) // steps iterations
    { 
      double wclevel=ContainerLevelBefore+i*ContDiff;
      double wctemp=ContainerTempBefore+i*TempDiff;
      panAnim.WaterCont.setLevel(0,10,wclevel);
      panAnim.WaterCont.setWaterTemp(wctemp);
      panAnim.setContainerLabelValues(wctemp,wclevel);

      panAnim.renderStep();
      panAnim.update(panAnim.getGraphics());
	  try { Thread.sleep(delay); } catch (InterruptedException ie) { }
    }
  }

  void btnReset_actionPerformed(ActionEvent e) 
  {
    debug.Write("btnReset_actionPerformed",3);
    // reset button clicked
    InitValues();
  }
}