import java.applet.Applet;
import java.awt.event.*;
import java.awt.*;
import java.awt.geom.*;


public class GridCorrect {
    Manager M;


    public GridCorrect() {}


    public static GeneralPath marker(Complex z) {
	GeneralPath gp=new GeneralPath();
	gp.moveTo((float)(z.x-.01),(float)(z.y-.01));
	gp.lineTo((float)(z.x-.01),(float)(z.y+.01));
	gp.moveTo((float)(z.x-.01),(float)(z.y+.01));
	gp.lineTo((float)(z.x+.01),(float)(z.y+.01));
	gp.moveTo((float)(z.x+.01),(float)(z.y+.01));
	gp.lineTo((float)(z.x+.01),(float)(z.y-.01));
	gp.moveTo((float)(z.x+.01),(float)(z.y-.01));	
        gp.lineTo((float)(z.x-.01),(float)(z.y-.01));
	return(gp);
    }


    /*decides if point should be reversed.  We apply this routine
      to intersection points*/

    /*
    public static int decorate(GridDynamics GD,Complex z) {

	int[] val=incidenceValue(GD,z);
	if(val[0]==4) return(3);
	if(val[0]==3) return(2);

	double[][] d=new double[5][2];

	for(int i=1;i<5;++i) 	    d[i]=GD.lineIndex1(i,z);

	int[][] ind=new int[2][2];
	int count=0;

	for(int i=1;i<5;++i) {
	    if(d[i][1]<.0000001) {
	       ind[count][0]=i;
               ind[count][1]=(int)(d[i][0]);
	       ++count;
	    }
	}

	int type1=ind[0][0];
	int type2=ind[1][0];
	int index1=ind[0][1];
	int index2=ind[1][1];

	if(type1+type2==3) return(0);
	if(type1+type2==7) return(majorTest(GD,z));


        int FIN1=minorTest(GD,type1,index1,type2,index2,z);
        int FIN2=decorateNew(GD,z);

	if(FIN1!=FIN2)  {
	    System.out.println("fail");
	    z.print();
	}

        return(FIN1);
    }

    */

    public static int decorate(GridDynamics GD,Complex z) {

	int[] val=incidenceValueNew(GD,z);
	if(val[0]==4) return(3);
	if(val[0]==3) return(2);

	double[][] d=new double[5][2];

	for(int i=1;i<5;++i) 	    d[i]=GD.lineIndex1New(i,z);

	double[][] ind=new double[2][2];
	int count=0;

	for(int i=1;i<5;++i) {
	    if(d[i][1]<.0000001) {
	       ind[count][0]=i;
               ind[count][1]=d[i][0];
	       ++count;
	    }
	}

	int type1=(int)(ind[0][0]);
	int type2=(int)(ind[1][0]);
	double index1=ind[0][1];
	double index2=ind[1][1];

	if(type1+type2==3) return(0);
	if(type1+type2==7) return(majorTestNew(GD,z));
	return(minorTestNew(GD,type1,index1,type2,index2,z));
    }





    //3,1 means a type 1 triple and 3,2 means a type2 triple

    public static int[] incidenceValue(GridDynamics GD, Complex z) {
	double[][] d=new double[5][2];
	for(int i=1;i<5;++i) {
	    d[i]=GD.lineIndex1(i,z);
	}
	int count=0;
	int type=0;
	for(int i=1;i<5;++i) {
	    if(d[i][1]<.0000001) {
               ++count;
	       type=type+i;
	    }
	}
	    int[] COUNT={count,0};
	    if(count<3) return(COUNT);
	    COUNT[1]=1;
	    if(type==9) COUNT[1]=2;
	    return(COUNT);
    }



    public static int[] incidenceValueNew(GridDynamics GD, Complex z) {
	double[][] d=new double[5][2];
	for(int i=1;i<5;++i) {
	    d[i]=GD.lineIndex1New(i,z);
	}
	int count=0;
	int type=0;
	for(int i=1;i<5;++i) {
	    if(d[i][1]<.0000001) {
               ++count;
	       type=type+i;
	    }
	}
	    int[] COUNT={count,0};
	    if(count<3) return(COUNT);
	    COUNT[1]=1;
	    if(type==9) COUNT[1]=2;
	    return(COUNT);
    }








    public static int minorTest(GridDynamics GD,int type1,int index1,int type2,int index2,Complex z) {

	int index=index1;
	int val=0;
	if(type1<3) index=index2;                     //index corresponds to line3 or line4.

	if(type1*type2==6) {
	    val=test3(GD,index,1,z);
	    if(val==1) return(1);
	    val=test3(GD,index,-1,z);
	    if(val==1) return(1);
	}

	if(type1*type2==4) {
	    val=test4(GD,index,1,z);
	    if(val==1) return(1);
	    val=test4(GD,index,-1,z);
	    if(val==1) return(1);
	}

	return(0);
    }



    public static int minorTestNew(GridDynamics GD,int type1,double index1,int type2,double index2,Complex z) {

	double index=index1;
	int val=0;
	if(type1<3) index=index2;                     //index corresponds to line3 or line4.

	if(type1*type2==6) {
	    val=test3New(GD,index,1,z);
	    if(val==1) return(1);
	    val=test3New(GD,index,-1,z);
	    if(val==1) return(1);
	}

	if(type1*type2==4) {
	    val=test4New(GD,index,1,z);
	    if(val==1) return(1);
	    val=test4New(GD,index,-1,z);
	    if(val==1) return(1);
	}

	return(0);
    }








    public static int test3(GridDynamics GD,int index,int sign,Complex z) {
	double[] ind=GD.lineIndex3(4,z);
	double indX=ind[0];
	if(sign==-1) indX=ind[1];
	Complex w=KiteGrid.intersection(3,index,4,indX,GD.P,GD.Q);
	int[] val=incidenceValue(GD,w);
	if(val[0]==3) return (0);	
	if(GD.between(1,z,w)==1) return(0);
	if(GD.between(2,z,w)==1) return(0);
	return(test2(GD,-sign,w));
    }


    public static int test3New(GridDynamics GD,double index,int sign,Complex z) {
	double[] ind=GD.lineIndex3New(4,z);
	double indX=ind[0];
	if(sign==-1) indX=ind[1];
	Complex w=KiteGrid.intersectionNew(3,index,4,indX,GD.P,GD.Q);
	int[] val=incidenceValueNew(GD,w);
	if(val[0]==3) return (0);	
	if(GD.betweenNew(1,z,w)==1) return(0);
	if(GD.betweenNew(2,z,w)==1) return(0);
	return(test2New(GD,-sign,w));
    }






    public static int test4(GridDynamics GD,int index,int sign,Complex z) {
	double[] ind=GD.lineIndex3(3,z);
	double indX=ind[1];
	if(sign==-1) indX=ind[0];
	Complex w=KiteGrid.intersection(4,index,3,indX,GD.P,GD.Q);
	int[] val=incidenceValue(GD,w);
	if(val[0]==3) return (0);	
	if(GD.between(1,z,w)==1) return(0);
	if(GD.between(2,z,w)==1) return(0);
	return(test1(GD,sign,w));
    }



    public static int test4New(GridDynamics GD,double index,int sign,Complex z) {
	double[] ind=GD.lineIndex3New(3,z);
	double indX=ind[1];
	if(sign==-1) indX=ind[0];
	Complex w=KiteGrid.intersectionNew(4,index,3,indX,GD.P,GD.Q);
	int[] val=incidenceValueNew(GD,w);
	if(val[0]==3) return (0);	
	if(GD.betweenNew(1,z,w)==1) return(0);
	if(GD.betweenNew(2,z,w)==1) return(0);
	return(test1New(GD,sign,w));
    }









    public static int majorTest(GridDynamics GD,Complex z) {
           int test=0;
	   test=test1(GD,+1,z);
	   if(test==1) return(1);
	   test=test1(GD,-1,z);
	   if(test==1) return(1);
	   test=test2(GD,+1,z);
	   if(test==1) return(1);
	   test=test2(GD,-1,z);
	   if(test==1) return(1);
	return(0);
	}


    public static int majorTestNew(GridDynamics GD,Complex z) {
           int test=0;
	   test=test1New(GD,+1,z);
	   if(test==1) return(1);
	   test=test1New(GD,-1,z);
	   if(test==1) return(1);
	   test=test2New(GD,+1,z);
	   if(test==1) return(1);
	   test=test2New(GD,-1,z);
	   if(test==1) return(1);
	return(0);
	}






    public static int test1(GridDynamics GD,int sign,Complex z) {
	Complex z0=new Complex(z);
	int halt=0;
	while(halt==0) {
	   double[][] ind=diamondIndex(GD,z0,sign);
	   int[] t=checkDiamond(GD,ind,z0);
	   if(t[0]==0) return(0);
	   Complex z1=predecessor(GD,ind,-sign);


	   if(t[0]==1) z0=new Complex(z1);
	   if(t[0]==2) return(GD.between(1,z0,z1)); 
	   if((t[0]==3)&&(t[1]==1)) return(1);
	   if(t[0]==3) halt=1;
	}
	return(0);
    }


    public static int test1New(GridDynamics GD,int sign,Complex z) {
	Complex z0=new Complex(z);
	int halt=0;
	while(halt==0) {
	   double[][] ind=diamondIndexNew(GD,z0,sign);
	   int[] t=checkDiamondNew(GD,ind,z0);
	   if(t[0]==0) return(0);
	   Complex z1=predecessorNew(GD,ind,-sign);


	   if(t[0]==1) z0=new Complex(z1);
	   if(t[0]==2) return(GD.betweenNew(1,z0,z1)); 
	   if((t[0]==3)&&(t[1]==1)) return(1);
	   if(t[0]==3) halt=1;
	}
	return(0);
    }






    public static int test2(GridDynamics GD,int sign,Complex z) {
	Complex z0=new Complex(z);
	int halt=0;
	while(halt==0) {
	   double[][] ind=diamondIndex(GD,z0,sign);
	   int[] t=checkDiamond(GD,ind,z0);
	   if(t[0]==0) return(0);
	   Complex z1=predecessor(GD,ind,sign);
	   if(t[0]==1) z0=new Complex(z1);
	   if(t[0]==2) return(GD.between(2,z0,z1));
           if((t[0]==3)&&(t[1]==2)) return(1);
           if(t[0]==3) halt=1;
	}
	return(0);
    }




    public static int test2New(GridDynamics GD,int sign,Complex z) {
	Complex z0=new Complex(z);
	int halt=0;
	while(halt==0) {
	   double[][] ind=diamondIndexNew(GD,z0,sign);
	   int[] t=checkDiamondNew(GD,ind,z0);
	   if(t[0]==0) return(0);
	   Complex z1=predecessorNew(GD,ind,sign);
	   if(t[0]==1) z0=new Complex(z1);
	   if(t[0]==2) return(GD.betweenNew(2,z0,z1));
           if((t[0]==3)&&(t[1]==2)) return(1);
           if(t[0]==3) halt=1;
	}
	return(0);
    }






    public static int[] checkDiamond(GridDynamics GD,double[][] ind,Complex z) {	
        int[] CHECK=new int[2];
	if(ind[0][1]-ind[0][0]>1) return(CHECK);  //not a diamond
	if(ind[1][1]-ind[1][0]>1) return(CHECK);  //not a diamond
	int[] val=incidenceValue(GD,z);
	if(val[0]==3) {                           //triple point
	    CHECK[0]=3;
	    CHECK[1]=val[1];
	    return(CHECK);
	}
	Complex[] Z=getDiamond(GD,ind);
	int test=GD.cleanDiamond(Z);
	if(test==0) CHECK[0]=1;  //clean
	if(test==1) CHECK[0]=0;  //double cross
	if(test==2) CHECK[0]=2;  //not clean
	return(CHECK);
    }



    public static int[] checkDiamondNew(GridDynamics GD,double[][] ind,Complex z) {	
        int[] CHECK=new int[2];
	if(ind[0][1]-ind[0][0]>1) return(CHECK);  //not a diamond
	if(ind[1][1]-ind[1][0]>1) return(CHECK);  //not a diamond
	int[] val=incidenceValue(GD,z);
	if(val[0]==3) {                           //triple point
	    CHECK[0]=3;
	    CHECK[1]=val[1];
	    return(CHECK);
	}
	Complex[] Z=getDiamondNew(GD,ind);
	int test=GD.cleanDiamondNew(Z);
	if(test==0) CHECK[0]=1;  //clean
	if(test==1) CHECK[0]=0;  //double cross
	if(test==2) CHECK[0]=2;  //not clean
	return(CHECK);
    }








    public static double[][] diamondIndex(GridDynamics GD,Complex z,int sign) {
	Complex w=new Complex(z.x+.5*sign,z.y);
	double[] ind1=GD.lineIndex3(3,w);
	double[] ind2=GD.lineIndex3(4,w);
	double[][] ind=new double[2][2];
	ind[0]=ind1;
	ind[1]=ind2;
	return(ind);
    }




    public static double[][] diamondIndexNew(GridDynamics GD,Complex z,int sign) {
	Complex w=new Complex(z.x+.5*sign,z.y);
	double[] ind1=GD.lineIndex3New(3,w);
	double[] ind2=GD.lineIndex3New(4,w);
	double[][] ind=new double[2][2];
	ind[0]=ind1;
	ind[1]=ind2;
	return(ind);
    }








    public static Complex[] getDiamond(GridDynamics GD,double[][] ind) {
	Complex[] Z=new Complex[4];
        Z[0]=KiteGrid.intersection(3,ind[0][0],4,ind[1][0],GD.P,GD.Q);
        Z[1]=KiteGrid.intersection(3,ind[0][1],4,ind[1][1],GD.P,GD.Q);
        Z[2]=KiteGrid.intersection(3,ind[0][0],4,ind[1][1],GD.P,GD.Q);
        Z[3]=KiteGrid.intersection(3,ind[0][1],4,ind[1][0],GD.P,GD.Q);
	return(Z);
    }


    public static Complex[] getDiamondNew(GridDynamics GD,double[][] ind) {
	Complex[] Z=new Complex[4];
        Z[0]=KiteGrid.intersectionNew(3,ind[0][0],4,ind[1][0],GD.P,GD.Q);
        Z[1]=KiteGrid.intersectionNew(3,ind[0][1],4,ind[1][1],GD.P,GD.Q);
        Z[2]=KiteGrid.intersectionNew(3,ind[0][0],4,ind[1][1],GD.P,GD.Q);
        Z[3]=KiteGrid.intersectionNew(3,ind[0][1],4,ind[1][0],GD.P,GD.Q);
	return(Z);
    }



    public static Complex predecessor(GridDynamics GD,double[][]ind,int sign) {
	double lim1=ind[0][0];
	double lim2=ind[1][1];
	if(sign==1) {
	    lim1=ind[0][1];
	    lim2=ind[1][0];
	}
        Complex w=KiteGrid.intersection(3,lim1,4,lim2,GD.P,GD.Q);
        return(w);
    }


    public static Complex predecessorNew(GridDynamics GD,double[][]ind,int sign) {
	double lim1=ind[0][0];
	double lim2=ind[1][1];
	if(sign==1) {
	    lim1=ind[0][1];
	    lim2=ind[1][0];
	}
        Complex w=KiteGrid.intersectionNew(3,lim1,4,lim2,GD.P,GD.Q);
        return(w);
    }






}

  