import java.awt.*;
import java.lang.Math;
import java.util.*;

class NewIon extends Thread{
	int i, x, y;
	Vector ions;
	Enumeration e;
	Ion tempIon;
    static int counter = 0;  // to track moves/s
    static boolean run;
    static boolean eForceOn=true;   // ions affected by electric field
    int sleepTime;
    static int temp=20;     // temperature in degrees C
    static int tof=40;      // time of flight factor: depends on viscosity
    static int particles=0; // number of particles created
	Graphics gll, grr;
	static Graphics offlg, offrg;
	Image offLImg, offRImg;
	RCompartment rCompar;
	LCompartment lCompar;
	Rectangle lRec, rRec;
	Channel chann;

	NewIon (int a, int b, int c, int d, Rectangle lr, Rectangle rr, LCompartment leftCompart, RCompartment rightCompart, Channel chan, Image imga, Image imgb, Image imgc) {
		ions = new Vector();
		sleepTime = 70;
		gll = leftCompart.getGraphics();
		grr = rightCompart.getGraphics();
		lRec = lr;
		rRec = rr;
		lCompar = leftCompart;
		rCompar = rightCompart;
		chann = chan;
		offLImg = leftCompart.createImage(lr.width, lr.height);
		offRImg = rightCompart.createImage(rr.width, rr.height);
		offlg = offLImg.getGraphics();
		offrg = offRImg.getGraphics();
		for (i = 0; i < a; i++) {
			x = (int)(lr.x + 2 + java.lang.Math.random()* (lr.width - 12));
			y = (int)(lr.y + 2 + java.lang.Math.random()* (lr.height - 12));
			ions.addElement(new K(x, y, leftCompart, imga, offlg));
		}
        for (i = 0; i < b; i++) {  //number of chlorides same as K+
            x=(int)(lr.x+2+java.lang.Math.random()*(lr.width-12));
            y=(int)(lr.y+2+java.lang.Math.random()*(lr.height-12));
            ions.addElement(new Cl(x, y, leftCompart, imgc, offlg));
        }
        for (i = 0; i < c; i++) {
            x=(int)(rr.x+2+java.lang.Math.random()*(rr.width-12) );
            y=(int)(rr.y+2+java.lang.Math.random()*(rr.height-12) );
            ions.addElement(new Na(x, y, rightCompart, imgb, offrg));
        }
        for (i = 0; i < d; i++) { //number of chlorides same as Na+
            x=(int)(rr.x+2+java.lang.Math.random()*(rr.width-12) );
            y=(int)(rr.y+2+java.lang.Math.random()*(rr.height-12) );
            ions.addElement(new Cl(x, y, rightCompart, imgc, offrg));
        }
	}
	
	void paint() {
		for (e = ions.elements(); e.hasMoreElements(); ) {
			tempIon = ((Ion)e.nextElement());
			tempIon.g.drawImage(tempIon.img, tempIon.x - tempIon.x0, tempIon.y - tempIon.y0, null);
		}
		lCompar.getGraphics().drawImage(offLImg, 0, 0, null);
		rCompar.getGraphics().drawImage(offRImg, 0, 0, null);
	}

    public void run() {
		try {
            int j = 293 * sleepTime;
            while (true) {
				try {
					sleep(j / (273+temp));
				} catch(InterruptedException e) {}
				if (run) {
					chann.getGraphics().fillRect(0, 0, chann.bounds().width, chann.bounds().height);
					offlg.fillRect(0, 0, lRec.width, lRec.height);
					offrg.fillRect(0, 0, rRec.width, rRec.height);
					for (e = ions.elements(); e.hasMoreElements(); ) {						
						((Ion)e.nextElement()).move();
					}
					paint();
				}
           }
        } catch(ThreadDeath t) {
			particles--;
			for (e = ions.elements(); e.hasMoreElements(); ) {
				((Ion)e.nextElement()).g.dispose();
			}
			throw(t);
        }
    }
	
    // set temperture
    static void setTemp(int degC) {
        temp = degC;
        tof = (int)( 10.0*Math.pow(2.0,temp/10.0) ); //time of flight, reflects viscosity
    }

    // get elapsed simulation time in ns
    static int getTime() {
		return counter*293/((273+temp)*particles*12);
	}
	
    static void resetMoveCounter() {
		counter=0;
	}
}

class Ion {
    static int imbalance;   //extra charge in right compartment
    static Random rand=new Random();
    protected int slowness;           // mean speed factor: depends on diameter
    int diam;
    int charge;
    int x, y, dx, dy, oldX, width, height;
    int x0, y0;             // compartment offsets
    Color c;
    Component compon;
    IonCompartment compart;
    Graphics g;
    Color bgc;
	Image img;

    Ion(int xx, int yy, IonCompartment startComp, Color cc, Image img, Graphics inG) {
        compart=startComp;
        c=cc;
        bgc=compart.getBackground();
        g = inG;
        x=xx;
        y=yy;
        NewIon.particles++;
        Point p=compart.location();
        x0=p.x;
        y0=p.y;
		this.img = img;
    }

    void setCompartment(IonCompartment cmpt) {
        compart = cmpt;
        Point p = cmpt.location();
        x0=p.x;
        y0=p.y;
		if (compart instanceof LCompartment)
			g = NewIon.offlg;
		else if (compart instanceof RCompartment)
			g = NewIon.offrg;
		else
			g = cmpt.getGraphics();
        if (cmpt instanceof Membrane) { //The following is a terrible clooge
            Channel c=((Membrane)cmpt).getChannel(); //never do this, please
            p=c.location();
            x0+=p.x;
            y0+=p.y;
            g=c.getGraphics();
        }
    }
    
    // get number of ion moves
    static int getMoveCounter() {
		return NewIon.counter;
	}

    // get temperature
    static int getTemp() {
		return NewIon.temp;
	}

	void move() {
        oldX = x;
        int r=rand.nextInt();
        int mfp=2 + NewIon.tof/slowness;	// since N mod 1 = 0 (a boring case)
        dx=dx/2 + r%mfp;					//    ^for momentum
		//  if ( (dx>40)||(-dx>40) ) System.out.println("dx="+dx+" x="+x);
        int eForceCoupling=2; //how much field affects ions: range 1-5
        if (NewIon.eForceOn) dx += (eForceCoupling*compart.getField(x)*charge)/slowness;
        r=rand.nextInt();
        dy=dy/2 + r%mfp;
        x += dx;
        y += dy;
        compart.contain(this);
        NewIon.counter++;
   }
}

class Na extends Ion {
    Na(int x, int y, IonCompartment cm, Image img, Graphics g) {
        super(x, y, cm, Color.red, img, g);
        diam=6; // 0.4 nm
        slowness=(int)( diam*Math.sqrt( (double)diam) );
        charge=1;
        cm.addCharge(x, charge);
    }
}

class K extends Ion {
    K(int x, int y, IonCompartment cm, Image img, Graphics g) {
        super(x, y, cm, Color.blue, img, g);
        diam=4; // 0.3 nm
        slowness=(int)( diam*Math.sqrt( (double)diam) );
        charge=1;
        cm.addCharge(x, charge);
    }
}

class Cl extends Ion {
    Cl(int x, int y, IonCompartment cm, Image img, Graphics g) {
        super(x, y, cm, Color.orange, img, g);
        diam=5; // 0.5 nm
        slowness=(int)( diam*Math.sqrt( (double)diam) );
        charge=-1;
        cm.addCharge(x, charge);
    }
}
class Glucose extends Ion {
    Glucose(int x, int y, IonCompartment cm, Image img, Graphics g) {
        super(x, y, cm, Color.magenta, img, g);
        slowness=(int)( diam*Math.sqrt((double)diam));
        diam=8; // 0.8 nm
        charge=0;
    }
}
