//******************************************************************************
// VClampCanvas.java:	Canvas
//
//******************************************************************************
import java.applet.Applet;
import java.awt.*;
//import gjt.*;

class VClampCanvas extends Panel implements Runnable
{
	// THREAD SUPPORT:
	//		m_diffusion	is the Thread object for the applet
	//--------------------------------------------------------------------------
	Thread	m_diffusion = null;
	//Thread	m_watch = null;
	protected Applet applet;
	public int NUM_PARTICLE=100;
	public Particle p[];

	protected Graphics m_g,m_r;
	protected Image m_image,m_ready;
	protected Dimension m_dimImage;
	protected int Tick=0;
	protected Color BG=new Color(153,204,204);
	protected Point Start,UL,LR;
	protected boolean ResetLocation=false;
	protected boolean ImageReady=false;

	public Membrane m_Membrane;
	public double m_Voltage=-60.0;
	protected int m_Barrier=-1;
	int Rin,Rout,Bin,Bout;
	protected int m_InnerLoop;
	//ReportLabel R_in=new ReportLabel("+100"), 
	//  R_out=new ReportLabel("+0"), 
	//  B_in=new ReportLabel("-100"), 
	//  B_out=new ReportLabel("-0"), 
	//  Voltage=new ReportLabel("-60 mV");
	protected Label R_in=new Label("+100"), 
	  R_out=new Label("+000"), 
	  B_in=new Label("-100"), 
	  B_out=new Label("-000"), 
	  Voltage=new Label("-600 mV");


	// VClamp Class Constructor
	//--------------------------------------------------------------------------
	public VClampCanvas(Applet applet)
	{
		this.applet=applet;
	}

	
	public VClampCanvas(){}
	
	// APPLET INFO SUPPORT:
	//		The getAppletInfo() method returns a string describing the applet's
	// author, copyright date, or miscellaneous information.
    //--------------------------------------------------------------------------
	public String getAppletInfo()
	{
		return "Name: diffusion\r\n" +
		       "Author: Joe Patlak\r\n" +
		       "Created with Microsoft Visual J++ Version 1.0";
	}


	// The init() method is called by the AWT when an applet is first loaded or
	// reloaded.  Override this method to perform whatever initialization your
	// applet needs, such as initializing data structures, loading images or
	// fonts, creating frame windows, setting the layout manager, or adding UI
	// components.
    //--------------------------------------------------------------------------
	public void init()
	{
		Dimension dim=size();
		int nWidth=dim.width;
		int nHeight=dim.height;
		Start= new Point(15,15);
		m_InnerLoop=0;
		UL=new Point(0,0);
		LR=new Point(nWidth-5,nHeight-5);

		m_Membrane=new Membrane();
		m_Membrane.SetVoltage(m_Voltage);
		m_Membrane.addElement(0.2);
		m_Membrane.addElement(0.0);

		m_Barrier=nWidth/2;


		int charge=1;
		p = new Particle[NUM_PARTICLE];

		for (int i=0; i<NUM_PARTICLE; i++){
			//if (i>=NUM_PARTICLE/2) charge=-1;
			p[i]= new Particle(applet,charge,Start,UL,LR);
			p[i].m_StdDev=5.0;
			p[i].BG=getBackground();
			p[i].m_Barrier=m_Barrier;
			p[i].m_Membrane=m_Membrane;
			//p[i].m_MembraneIndex=0;
			//if (i<NUM_PARTICLE/2) p[i].m_MembraneIndex=0;
			//else 
			p[i].m_MembraneIndex=0;

		}

		ResizeImage();


		R_in.setAlignment(Label.LEFT);
		B_in.setAlignment(Label.LEFT);
		R_out.setAlignment(Label.LEFT);
		R_out.setAlignment(Label.LEFT);
		Voltage.setAlignment(Label.CENTER);

	}

	// Place additional applet clean up code here.  destroy() is called when
	// when you applet is terminating and being unloaded.
	//-------------------------------------------------------------------------
	public void destroy(){
	}

	// VClamp Paint Handler
	//--------------------------------------------------------------------------
	public void paint(Graphics g)
	{
		if (m_ready != null){
			g.drawImage(m_ready,0,0,null);
		}
		R_in.setText("+"+Rin);
		B_in.setText("-"+Bin);
		R_out.setText("+"+Rout);
		B_out.setText("-"+Bout);
	}

	//--------------------------------------------------------------------------
	public void update(Graphics g)
	{
		ResizeImage();
		paint(g);
		ImageReady=false;
	}


	//--------------------------------------------------------------------------
	protected void ResizeImage(){
		Dimension dim = size();
		int nWidth = dim.width;
		int nHeight = dim.height;

		if (m_dimImage != null &&
			m_dimImage.width == nWidth &&
			m_dimImage.height == nHeight){

			return;
		}

		m_dimImage = new Dimension(nWidth, nHeight);
		m_image = createImage(nWidth, nHeight);
		m_ready = createImage(nWidth, nHeight);
		m_g = m_image.getGraphics();
		m_r = m_ready.getGraphics();
		LR=new Point(nWidth-5,nHeight-5);	
		m_Barrier=nWidth/2;
		for (int i=0; i<NUM_PARTICLE; i++){
			if (p[i].m_StdDev>=0.0){
				p[i].NewLimits(UL,LR);
				p[i].m_Barrier=m_Barrier;
			}
		}
	}



	//--------------------------------------------------------------------------
	public void start()
	{
		if (m_diffusion == null)
		{
			m_diffusion = new Thread(this);
			//m_watch = new Stopwatch();  //Don't be its client for now
			m_diffusion.start();
			//m_watch.start();
		}
	}
	
	//--------------------------------------------------------------------------
	public void stop()
	{
		if (m_diffusion != null)
		{
			m_diffusion.stop();
			//m_watch.stop();
			m_diffusion = null;
			//m_watch = null;
		}

	}


	//--------------------------------------------------------------------------
	//public void tick(){
	//	Tick = ++Tick % 4;
	//	if ( Tick==0 && ImageReady) repaint();
	//}

	//--------------------------------------------------------------------------
	public void run()
	{
		while (true)
		{
		  if (m_g != null){
		    if (ResetLocation){
		      int charge=1;
		      for (int i=0; i<NUM_PARTICLE; i++){
			//if (i>=NUM_PARTICLE/2) charge=-1;
			p[i].Init(charge,Start,UL,LR);
		      }
		      ResetLocation=false;
		    }

		    m_g.setColor(BG);
		    m_g.fillRect(0,0,m_dimImage.width,m_dimImage.height);
		    for (int i=0; i<NUM_PARTICLE; i++){
		      //for (int j=0; j<m_InnerLoop; j++){
		      p[i].NewMove();
		      //}
		      //}

		      //((Stopwatch)m_watch).reset();
		      //for (int i=0; i<NUM_PARTICLE; i++){
		      p[i].DrawParticle(m_g);
		    }
		    //m_InnerLoop=(int)((Stopwatch)m_watch).elapsedTime()/100;


		    m_g.setColor(Color.black);
		    m_g.drawLine(m_Barrier,0,m_Barrier,m_dimImage.height);
		    m_r.drawImage(m_image,0,0,null);
		    Rin=0; Rout=0; Bin=0; Bout=0;
		    for (int i=0; i<NUM_PARTICLE; i++){
		      if (p[i].IsInside()){
			if (p[i].m_Charge<0) Bin-=p[i].m_Charge; 
			else Rin+=p[i].m_Charge;
		      }else{
			if (p[i].m_Charge<0) Bout-=p[i].m_Charge; 
			else Rout+=p[i].m_Charge;
		      }
		    }
		    double VUnits=(Rin-Bin)-(Rout-Bout);
		    m_Membrane.SetVoltage(m_Voltage);

		    Voltage.setText(m_Membrane.GetVoltage()+" mv");
		    ImageReady=true;
		    ((VClamp)applet).OutBar.setFillPercent(100.0*((double)Rout/(double)(Rin+Rout)));
		    repaint();
		  }
		}
	}

	// MOUSE SUPPORT:
	//		The mouseDown() method is called if the mouse button is pressed
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseDown(Event evt, int x, int y)
	{
		Start=new Point(x,y);
		ResetLocation=true;
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseUp() method is called if the mouse button is released
	// while the mouse cursor is over the applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseUp(Event evt, int x, int y)
	{
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseDrag() method is called if the mouse cursor moves over the
	// applet's portion of the screen while the mouse button is being held down.
	//--------------------------------------------------------------------------
	public boolean mouseDrag(Event evt, int x, int y)
	{
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseMove() method is called if the mouse cursor moves over the
	// applet's portion of the screen and the mouse button isn't being held down.
	//--------------------------------------------------------------------------
	public boolean mouseMove(Event evt, int x, int y)
	{
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseEnter() method is called if the mouse cursor enters the
	// applet's portion of the screen.
	//--------------------------------------------------------------------------
	public boolean mouseEnter(Event evt, int x, int y)
	{
		return true;
	}

	// MOUSE SUPPORT:
	//		The mouseExit() method is called if the mouse cursor leaves the
	// applet's portion of the screen.
 	//--------------------------------------------------------------------------
	public boolean mouseExit(Event evt, int x, int y)
	{
		return true;
	}


}


/*
class ReportLabel extends Label {

	ReportLabel(){
		super.setAlignment(Label.LEFT);
	}

	ReportLabel(String string){
		super.setAlignment(Label.LEFT);
		super.setText(string);
	}

	ReportLabel(String string, int alignment){
		super.setAlignment(alignment);
		super.setText(string);
	}


	public Insets insets(){
		return new Insets(0,0,0,0);
	}


}
*/

