import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.awt.geom.*;
import java.math.*;
import java.util.Arrays;

    public static Complex[][] bounce(Complex[][] ARI,Complex[][] OCT,int p,int q) {
	Complex[][] Z2=new Complex[ARI.length*OCT.length][2];
	int count=0;
	for(int i=0;i<ARI.length;++i) {
	    for(int j=0;j<OCT.length;++j) {
		int ari=ARI[i][0].ARI;
		int oct=OCT[j][0].OCT;
		boolean test=BoxCombinatorics.interact(ari,oct);
		if(test==false) {
		    int oct2=BoxCombinatorics.partner(false,ari,oct);
		    Complex z=Vector.findCross2(ARI[i][0],ARI[i][1],OCT[j][0],OCT[j][1]);
		    Z2[count]=line(z,oct2/2,p,q);
		    Z2[count][0].OCT=oct2;
		    Z2[count][0].CHARGE=OCT[j][0].CHARGE;
		    ++count;
		}
	    }
	}
	Z2=ListHelp.trimList(Z2,count);
	Z2=ListHelp.irredundantList(Z2);
	return(Z2);
    }


    public static Complex[][] getOriginalAriX(BoxModel[][] B) {
	Complex[][] Z=new Complex[8][2];

	for(int i=0;i<3;++i) {
	   Z[i][0]=new Complex(B[0][i].H0[0]);
	   Z[i][1]=new Complex(B[0][i].H0[1]);
	}
	Z[3][0]=new Complex(B[0][2].H1[0]);
	Z[3][1]=new Complex(B[0][2].H1[0]);

	for(int i=0;i<3;++i) {
	   Z[i+4][0]=new Complex(B[i][0].V0[0]);
	   Z[i+4][1]=new Complex(B[i][0].V0[1]);
	}
	Z[7][0]=new Complex(B[2][0].V1[0]);
	Z[7][1]=new Complex(B[2][0].V1[0]);
	return(Z);
    }


    public static Complex[][] getOriginalAri(BoxModel[][] B) {
	Complex[][] Z=new Complex[4][2];

	Z[0][0]=new Complex(B[0][0].H0[0]);
	Z[0][1]=new Complex(B[0][0].H0[1]);
	Z[1][0]=new Complex(B[0][2].H1[0]);
	Z[1][1]=new Complex(B[0][2].H1[0]);
	Z[2][0]=new Complex(B[0][0].V0[0]);
	Z[2][1]=new Complex(B[0][0].V0[0]);
	Z[3][0]=new Complex(B[2][0].V1[0]);
	Z[3][1]=new Complex(B[2][0].V1[0]);
	return(Z);
    }


public class BoxLineGenerator {
    BoxModel[][] B=new BoxModel[3][3];
    Complex[] DOT=new Complex[50];
    Complex[][] ARI=new Complex[50][2];
    Complex[][] OCT=new Complex[50][2];


    public static int random(int k) {
	return (int)(Math.floor(k*Math.random()));
    }

    public BoxLineGenerator(BoxModel[][] b) {
	this.B=b;
    }


    public static Complex[][] getLinesNew(BoxModel[][] b,int[] on) {
	BoxLineGenerator BLG=new BoxLineGenerator(b);
	return BLG.getLinesNewA();
    }
    public static Complex[] getPointsNew(BoxModel[][] b,int[] on) {
	BoxLineGenerator BLG=new BoxLineGenerator(b);
	return BLG.getPointsNewA();
    }


    public Complex[][] getLinesNewA() {
	int p=B[0][0].P;
	int q=B[0][0].Q;
	ARI=getAri(B);
	DOT=getPointsBasic();
	OCT=getOctTracker(DOT,p,q);
	for(int i=0;i<OCT.length;++i) OCT[i]=trim(B,OCT[i]);
	for(int i=0;i<1000;++i) {
	    augmentP();
	    augmentL();
	}
	return(OCT);
    }

    public Complex[] getPointsNewA() {
	int p=B[0][0].P;
	int q=B[0][0].Q;
	ARI=getAri(B);
	DOT=getPointsBasic();
	OCT=getOctTracker(DOT,p,q);
	for(int i=0;i<1000;++i) {
	    augmentP();
	    augmentL();
	}
	return(DOT);
    }

    public Complex[] getPointsBasic() {
	Complex[] LIST={};
	Complex[] NEW={};
	for(int i=0;i<3;++i) {
	    for(int j=0;j<3;++j) {
		NEW=ListHelp.trimList(B[i][j].Z,B[i][j].POINTS);
		LIST=ListHelp.mergeList(LIST,NEW);
	    }
	}
	return(LIST);
    }




    public void augmentP() {
	Complex z=randomP();
	if(z==null) return;
	Complex[] Z={z};
	DOT=ListHelp.mergeList(DOT,Z);
	DOT=ListHelp.irredundantList(DOT);
    }

    public void augmentL() {
	Complex[] z=randomL();
	if(z==null) return;
	Complex[][] Z={z};
	OCT=ListHelp.mergeList(OCT,Z);
	OCT=ListHelp.irredundantList(OCT);
    }


    public Complex randomP() {
	int k1=ARI.length;
	int k2=OCT.length;
	int r1=random(k1);
	int r2=random(k2);
	int ari=ARI[r1][0].ARI;
	int oct=OCT[r2][0].OCT;
	if(BoxCombinatorics.interact(ari,oct)==false) return null;
	Complex X=Vector.findCross2(ARI[r1][0],ARI[r1][1],OCT[r2][0],OCT[r2][1]);
	if(Complex.onSegment(X,ARI[r1][0],ARI[r1][1])==false) return(null);
	if(Complex.onSegment(X,OCT[r2][0],OCT[r2][1])==false) return(null);
	return(X);
    }

    public Complex[] randomL() {
	int p=B[0][0].P;
	int q=B[0][0].Q;
	int k1=ARI.length;
	int k2=OCT.length;
	int r1=random(k1);
	int r2=random(k2);
	int ari=ARI[r1][0].ARI;
	int oct=OCT[r2][0].OCT;
	if(BoxCombinatorics.interact(ari,oct)==false) return null;
	Complex X=Vector.findCross2(ARI[r1][0],ARI[r1][1],OCT[r2][0],OCT[r2][1]);
	if(Complex.onSegment(X,ARI[r1][0],ARI[r1][1])==false) return(null);
	if(Complex.onSegment(X,OCT[r2][0],OCT[r2][1])==false) return(null);
	oct=BoxCombinatorics.partner(true,ari,oct);
	Complex[] L=line(X,oct/2,p,q);
	L=trim(B,L);
	L[0].OCT=oct;
	L[0].CHARGE=OCT[r2][0].CHARGE;
	return(L);
    }








    public static Complex[][] getLinesNewX(BoxModel[][] B,int[] on) {
	int p=B[0][0].P;
	int q=B[0][0].Q;
	Complex[][] Z=getAri(B);
	Complex[] Z1=getPointsBasic(B);
	Complex[] Z2=BounceTracker.getPoints(B,on);
	Complex[][] W1=getOctBasic(Z1,p,q);
	Complex[][] W2=getOctTracker(Z2,p,q);
	Complex[][] W=ListHelp.mergeList(W1,W2);
	return(W);
    }

    public static Complex[] getPointsNewX(BoxModel[][] B,int[] on) {
	int p=B[0][0].P;
	int q=B[0][0].Q;
	Complex[][] Z=getAri(B);
	Complex[][] W=getLinesNewX(B,on);
	Complex[] X=CrossingModel2.getCross(Z,W,p,q);
	return(X);
    }


    public static Complex[] getPointsBasic(BoxModel[][] B) {
	Complex[] LIST=BounceTracker.track(B);
	Complex[] NEW={};
	for(int i=0;i<3;++i) {
	    for(int j=0;j<3;++j) {
		NEW=ListHelp.trimList(B[i][j].Z,B[i][j].POINTS);
		LIST=ListHelp.mergeList(LIST,NEW);
	    }
	}
	return(LIST);
    }

    public static Complex[][] getOctBasic(Complex[] Z0,int p,int q) {
	Complex[][] Z1=new Complex[Z0.length*2][2];
	int count=0;
	for(int i=0;i<Z0.length;++i) {
	    Complex z=Z0[i];
	    int oct0=z.OCT;
            int oct1=BoxCombinatorics.partner(true,z.ARI,oct0);  
            int choice0=oct0/2;
	    int choice1=oct1/2;
	    Z1[2*i+0]=line(z,choice0,p,q);
            Z1[2*i+1]=line(z,choice1,p,q);
	    Z1[2*i+0][0].OCT=oct0;
	    Z1[2*i+1][0].OCT=oct1;
	    Z1[2*i+0][0].CHARGE=z.CHARGE;
	    Z1[2*i+1][0].CHARGE=z.CHARGE;
	    Z1[2*i+0][0].ARI=z.ARI;
	    Z1[2*i+1][0].ARI=z.ARI;
	}
	Z1=ListHelp.irredundantList(Z1);
	return(Z1);
    }


    public static Complex[][] getOctTracker(Complex[] Z0,int p,int q) {
	Complex[][] Z1=new Complex[Z0.length][2];
	int count=0;
	for(int i=0;i<Z0.length;++i) {
	    Complex z=Z0[i];
	    int oct0=z.OCT;
            int choice0=oct0/2;
	    Z1[i]=line(z,choice0,p,q);
	    Z1[i][0].OCT=oct0;
	    Z1[i][0].CHARGE=z.CHARGE;
	    Z1[i][0].ARI=z.ARI;
	}
	Z1=ListHelp.irredundantList(Z1);
	return(Z1);
    }





    public static Complex[] line(Complex z,int choice,int p,int q) {
	double s=GridOct.slope(choice,p,q);
	Complex z1=new Complex(z.x-1,z.y-s);
	Complex z2=new Complex(z.x+1,z.y+s);
	Complex[] Z={z1,z2};
	return(Z);
    }

    public static BoxModel outerEdges(BoxModel[][] B) {
	BoxModel b=new BoxModel();
	b.H0[0]=new Complex(B[0][0].H0[0]);
	b.H0[1]=new Complex(B[2][0].H0[1]);
	b.H1[0]=new Complex(B[0][2].H1[0]);
	b.H1[1]=new Complex(B[2][2].H1[1]);

	b.V0[0]=new Complex(B[0][0].V0[0]);
	b.V0[1]=new Complex(B[0][2].V0[1]);
	b.V1[0]=new Complex(B[2][0].V1[0]);
	b.V1[1]=new Complex(B[2][2].V1[1]);

	int count=0;
	return(b);
    }

    /**This gets the new lines*/

    public static Complex[][] getAri(BoxModel[][] B) {
	Complex[][] Z={getLeft(B),getRight(B),getBot(B),getTop(B)};
	return(Z);
    }

    public static Complex[] getBot(BoxModel[][] B) {
	double x1=B[0][0].H0[0].x;
	double x2=B[2][0].H0[1].x;
	double y1=B[0][0].H0[0].y;
	double y2=B[0][0].H1[0].y;
	double y=2*y2-y1;
	Complex z1=new Complex(x1,y);
	Complex z2=new Complex(x2,y);
	z1.ARI=B[0][0].H1[0].ARI;
	Complex[] Z={z1,z2};
	return(Z);
    }


    public static Complex[] getTop(BoxModel[][] B) {
	double x1=B[0][0].H0[0].x;
	double x2=B[2][0].H0[1].x;
	double y1=B[0][2].H1[0].y;
	double y2=B[0][1].H1[0].y;
	double y=2*y2-y1;
	Complex z1=new Complex(x1,y);
	Complex z2=new Complex(x2,y);
	z1.ARI=B[2][2].H0[0].ARI;
	Complex[] Z={z1,z2};
	return(Z);
    }


    public static Complex[] getLeft(BoxModel[][] B) {
	double y1=B[0][0].V0[0].y;
	double y2=B[0][2].V0[1].y;
	double x1=B[0][0].V0[0].x;
	double x2=B[1][0].V0[0].x;
	double x=2*x2-x1;
	Complex z1=new Complex(x,y1);
	Complex z2=new Complex(x,y2);
	z1.ARI=B[0][0].V1[0].ARI;
	Complex[] Z={z1,z2};
	return(Z);
    }


    public static Complex[] getRight(BoxModel[][] B) {
	double y1=B[0][0].V0[0].y;
	double y2=B[0][2].V0[1].y;
	double x1=B[2][0].V1[0].x;
	double x2=B[1][0].V1[0].x;
	double x=2*x2-x1;
	Complex z1=new Complex(x,y1);
	Complex z2=new Complex(x,y2);
	z1.ARI=B[2][2].V0[0].ARI;
	Complex[] Z={z1,z2};
	return(Z);
    }




    public static Complex[] trim(BoxModel[][] B,Complex[] Z) {
	BoxModel b=outerEdges(B);
	Complex z1=Vector.findCross2(Z[0],Z[1],b.H0[0],b.H0[1]);
	Complex z2=Vector.findCross2(Z[0],Z[1],b.H1[0],b.H1[1]);
	Complex z3=Vector.findCross2(Z[0],Z[1],b.V0[0],b.V0[1]);
	Complex z4=Vector.findCross2(Z[0],Z[1],b.V1[0],b.V1[1]);

	double t=.00000001;
	Complex[] Z2=new Complex[2];
	int count=0;
	if((z1.x>b.H0[0].x-t)&&(z1.x<b.H0[1].x+t)) {
	    Z2[count]=new Complex(z1);
	    ++count;
	}

	if((z2.x>b.H1[0].x-t)&&(z2.x<b.H1[1].x+t)) {
	    Z2[count]=new Complex(z2);
	    ++count;
	}

	if((count<2)&&(z3.y>b.V0[0].y-t)&&(z3.y<b.V0[1].y+t)) {
	    Z2[count]=new Complex(z3);
	    ++count;
	}

	if((count<2)&&(z4.y>b.V1[0].y-t)&&(z4.y<b.V1[1].y+t)) {
	    Z2[count]=new Complex(z4);
	    ++count;
	}

	if(count<2) return(null);
	return(Z2);
    }



}

