package yi.iu.processor.ort;

import yi.iu.processor.*;
import yi.iu.processor.canny.*;
import yi.iu.ui.DisplayFrame;

import java.awt.*;
import java.util.Vector;

public class ChainPixel extends yi.iu.processor.ImageProcessor
{
    //option: whether keep all the tracks
    public static int ALLLISTS=0;
    public static int ONLYSTRONGEST=1;

    //canny edge detector arguments
    double sigma= 1;        // Standard deviation of the gaussian kernel.
    double tlow= 0.5;       // Fraction of the high threshold in hysteresis.
    double thigh= 50;      // High hysteresis threshold control. The actual

    public int getArguNum() { return 3;}

    public void setArgument(int i, String st)
    {
        if (st.length()==0) return;
        if (i==0) sigma= Double.valueOf(st).doubleValue();
        else if (i==1) tlow= Double.valueOf(st).doubleValue();
        else if (i==2) thigh= Double.valueOf(st).doubleValue();
    }

    public String getArgument(int i)
    {
        if (i==0) return (new Double(sigma)).toString();
        else if (i==1) return (new Double(tlow)).toString();
        else if (i==2) return (new Double(thigh)).toString();
        return null;
    }

    public String getArguName(int i)
    {
        if (i==0) return "canny_sigma";
        else if (i==1) return "canny_low";
        else if (i==2) return "canny_high";
        return null;
    }

    public ChainPixel() {super();
    }
    public ChainPixel(double s, double l, double h) {
        sigma=s; tlow=l; thigh=h;
    }

    public int[] getProcessed(int source[], Dimension d)
    {
        link_and_save(source, d, ALLLISTS);
        return null;
    }

    public int[] getProcessedPseudoColor(int source[], Dimension d)
    {
        Vector rst= link_and_save(source, d, ALLLISTS);
        int[][] label= new int[d.height][d.width];
        for (int i=0;i<rst.size();i++) {
            int[][] ps= (int[][])rst.elementAt(i);
            for (int j=0;j<ps.length;j++)
                label[ps[j][1]][ps[j][0]]=i+1;
        }
        int[] label_1= yi.util.ImageUtil.twoD2oneD(label);
        int[] img= yi.util.ImageUtil.makeNewImageFromLabel(label_1);
        label=null;label_1=null;
        System.gc();
        (new DisplayFrame("rst", img, d.width, d.height)).show();
        return img;
    }


    static char BLACK= 0;           // Canny output edge pixel 1   RC91
    static char WHITE= 255;         // WHITE left as orig - never used RC91

    double aspect_ratio=1.0;
    int thresh_sig= 1000;           //how long to consider as a long enough line (1000/255)
    boolean closed_only   = false;  //whether only find the close lines

    public Vector link_and_save(int source[], Dimension d, int option)
    //option used to determine if all lists (0) or only the strongest (1)  are saved to disk
    {
        int height=d.height, width= d.width;
        int i,j;
        char[][] image= new char[height][width];

        int[] edges= (new CannyEdgeDetector(sigma, tlow, thigh)).getProcessed(source, d);
        int[] edges_img= yi.util.ImageUtil.makeNewImageFromBinary(edges);

        int index=0;
        for (i=0;i<height;i++) {
            for (j=0;j<width;j++) {
                if ( edges[index] != 0) {
	    	        image[i][j] = (char) WHITE;
	            } else {
		            image[i][j] = (char) 0;
  		        }
		        index++;
	        }
        }

        //display("edge", image);

        //clean up image, make all object 8 connected
        //not crossing of two lines after
        clean(image, width, height);
        //display("clean", image);

        //remove isolated points - of no interest to us here
        remove_isolated(image, width, height);

        // link open edges
        Vector open_cp= link_open(image, width, height, option); //chained pixels
        //display("open_cp", image);

        // remove isolated points - of no interest to us here
        remove_isolated(image, width, height);

        // link closed edges
        Vector close_cp= link_closed(image, width, height, option);

        // remove isolated points - of no interest to us here
        remove_isolated(image, width, height);

        Vector rst= new Vector();
        for (i=0;i<open_cp.size();i++)
            rst.addElement(open_cp.elementAt(i));
        for (i=0;i<close_cp.size();i++)
            rst.addElement(close_cp.elementAt(i));

        return rst;

    }

    void clean(char[][] image, int width, int height)
    {
        int loop1,loop2;
        char i1,i2,i3,i4;
        long number;

        // clear border
        for(loop1=0;loop1<height;loop1++){
            image[loop1][0] = BLACK;
            image[loop1][width-1] = BLACK;
        }
        for(loop1=0;loop1<width;loop1++){
            image[0][loop1] = BLACK;
            image[height-1][loop1] = BLACK;
        }
        //number= counting_pixels(image, width, height);
        for(loop1=1;loop1<height-1;loop1++)
            for(loop2=1;loop2<width-1;loop2++)
                if(image[loop1][loop2] != BLACK){
          	        i1 = image[loop1-1][loop2];
          	        i2 = image[loop1][loop2-1];
          	        i3 = image[loop1+1][loop2];
          	        i4 = image[loop1][loop2+1];
          	        if((i1 != BLACK) && (i2 != BLACK)){
          	            image[loop1][loop2] = BLACK;
          	        }
          	        else if((i2 != BLACK) && (i3 != BLACK)){
          	            image[loop1][loop2] = BLACK;
          	        }
          	        else if((i3 != BLACK) && (i4 != BLACK)){
          	            image[loop1][loop2] = BLACK;
          	        }
          	        else if((i4 != BLACK) && (i1 != BLACK)){
          	            image[loop1][loop2] = BLACK;
          	        }
	            }
        //number= counting_pixels(image, width, height);
    }


    long counting_pixels(char[][] image, int width, int height)
    {
        int loop1,loop2;
        long number;

        number = 0;
        for(loop1=0;loop1<height;loop1++)
            for(loop2=0;loop2<width;loop2++)
	            if(image[loop1][loop2] != BLACK)
        		    number++;
		return number;
    }


    //remove the single pixel
    void remove_isolated(char[][] image, int width, int height)
    {
        int loop1,loop2;
        char i1,i2,i3,i4,i6,i7,i8,i9;
        long number;

        number = 0;
        for(loop1=1;loop1<height-1;loop1++)
   	        for(loop2=1;loop2<width-1;loop2++)
      	        if(image[loop1][loop2] != BLACK){
          	        i1 = image[loop1-1][loop2-1];
          	        i2 = image[loop1][loop2-1];
          	        i3 = image[loop1+1][loop2-1];
          	        i4 = image[loop1-1][loop2];
          	        i6 = image[loop1+1][loop2];
          	        i7 = image[loop1-1][loop2+1];
          	        i8 = image[loop1][loop2+1];
          	        i9 = image[loop1+1][loop2+1];
          	        if((i1+i2+i3+i4+i6+i7+i8+i9) == (8*BLACK)){
             	        image[loop1][loop2] = BLACK;
             	        number++;
             	    }
                }
    }

    static int MAX_PIX= 10000;

    //option = 0  write list to disk
    //option = 1  write significant lines to disk
    Vector link_open(char[][] image, int width, int height, int option)
    {
        Vector rst= new Vector();
        int[] xpix= new int[MAX_PIX],ypix= new int[MAX_PIX];
        int weight,loopindex;

        int loop1,loop2,loop3;
        char i1,i2,i3,i4,i6,i7,i8,i9;
        int xp,yp;
        boolean end_of_line;

        for(loop1=0;loop1<height;loop1++)
   	        for(loop2=0;loop2<width;loop2++){
      	        // find pixel at end of line
      	        if(image[loop1][loop2] != BLACK){
      	            i1 = 0;
         	        i2 = 0;
         	        i3 = 0;
         	        i4 = 0;
         	        i6 = 0;
         	        i7 = 0;
         	        i8 = 0;
         	        i9 = 0;
         	        if(image[loop1-1][loop2-1] != BLACK)
            	        i1 = 1;
                    if(image[loop1][loop2-1] != BLACK)
            	        i2 = 1;
         	        if(image[loop1+1][loop2-1] != BLACK)
            	            i3 = 1;
         	        if(image[loop1-1][loop2] != BLACK)
            	            i4 = 1;
         	        if(image[loop1+1][loop2] != BLACK)
            	            i6 = 1;
         	        if(image[loop1-1][loop2+1] != BLACK)
            	            i7 = 1;
         	        if(image[loop1][loop2+1] != BLACK)
            	            i8 = 1;
         	        if(image[loop1+1][loop2+1] != BLACK)
            	            i9 = 1;
         	        if((i1+i2+i3+i4+i6+i7+i8+i9) == 1){
         	        //it is a end point
            	        weight = 0;
            	        loopindex  = 0;
            	        end_of_line = false;
            	        //track to end of line
            	        xp = loop2;
            	        yp = loop1;
            	        do{
               		        weight = weight + image[yp][xp];
               		        loopindex++;
               		        xpix[loopindex] = xp;
               		        ypix[loopindex] = (int)Math.round(yp/aspect_ratio);
               		        image[yp][xp] = BLACK;
               		        // goto next pixel if an edge pixel
               		        i1 = image[yp-1][xp-1];
               		        i2 = image[yp][xp-1];
               		        i3 = image[yp+1][xp-1];
               		        i4 = image[yp-1][xp];
               		        i6 = image[yp+1][xp];
               		        i7 = image[yp-1][xp+1];
               		        i8 = image[yp][xp+1];
               		        i9 = image[yp+1][xp+1];
               		        if(i1 != BLACK){
                  	            xp--;
                  	            yp--;
                  	        }
               		        else if(i2 != BLACK){
                  	            xp--;
        			        }
               		        else if(i3 != BLACK){
                  	            yp++;
                  	            xp--;
                  	        }
               		        else if(i4 != BLACK){
                  	            yp--;
               		        }
			                else if(i6 != BLACK){
                  	                    yp++;
			                }
               		        else if(i7 != BLACK){
                  	            yp--;
                  	            xp++;
                  	        }
               		        else if(i8 != BLACK){
                  	            xp++;
        			        }
               		        else if(i9 != BLACK){
                  	            xp++;
                  	            yp++;
                  	        }
               		        else
                  	            end_of_line = true;
               	        }while(end_of_line == false);

               	        if(option == 1){
               	            // only write if significant
               	            if(weight > thresh_sig){
               	                if(closed_only == false){
               	                    int[][] pixels= new int[loopindex][2];
               	                    for(loop3=1;loop3<=loopindex;loop3++) {
               	                        pixels[loop3-1][0]=xpix[loop3];
               	                        pixels[loop3-1][1]=ypix[loop3];
               	                    }
               	                    rst.addElement(pixels);
               	                }
               	            }
		                }
		                else{ // option = 0
		                    // write all lines
		                    if(closed_only == false){
		                        int[][] pixels= new int[loopindex][2];
		                        for(loop3=1;loop3<=loopindex;loop3++) {
		                            pixels[loop3-1][0]=xpix[loop3];
		                            pixels[loop3-1][1]=ypix[loop3];
		                        }
		                        rst.addElement(pixels);
		                    }
    	    	        }
    	    	    }
    	        }
	        }
	    xpix=ypix=null;
	    System.gc();
	    return rst;
    }

    Vector link_closed(char[][] image, int width, int height, int option)
    //option = 0  write list to disk
    //option = 1  write significant lines to disk
    {
        Vector rst= new Vector();
        int[] xpix= new int[MAX_PIX],ypix= new int[MAX_PIX];
        int weight=0;
        int loopindex;

        int loop1,loop2,loop3;
        char i1,i2,i3,i4,i6,i7,i8,i9;
        int xp,yp;
        boolean end_of_line;


        for(loop1=0;loop1<height;loop1++)
    	    for(loop2=0;loop2<width;loop2++){
      	        // find any remaining pixel
      	        if(image[loop1][loop2] != BLACK){
         	        // at beginning of a line
         	        weight = 0;
         	        loopindex = 0;
         	        end_of_line = false;
         	        // track to end of line
         	        xp = loop2;
         	        yp = loop1;
         	        do{
            	        loopindex++;
            	        xpix[loopindex] = xp;
            	        ypix[loopindex] = (int)Math.round(yp / aspect_ratio);
            	        weight = weight + image[yp][xp];
            	        image[yp][xp] = BLACK;
            	        // goto next edge pixel
            	        i1 = image[yp-1][xp-1];
            	        i2 = image[yp][xp-1];
            	        i3 = image[yp+1][xp-1];
            	        i4 = image[yp-1][xp];
            	        i6 = image[yp+1][xp];
            	        i7 = image[yp-1][xp+1];
            	        i8 = image[yp][xp+1];
            	        i9 = image[yp+1][xp+1];
            	        if(i1 != BLACK){
               		        xp--;
               		        yp--;
                        }
            	        else if(i2 != BLACK){
                   		    xp--;
        	            }
            	        else if(i3 != BLACK){
               		        yp++;
               		        xp--;
               	        }
            	        else if(i4 != BLACK){
                   		    yp--;
        		        }
            	        else if(i6 != BLACK){
                   		    yp++;
		                }
            	        else if(i7 != BLACK){
               		        yp--;
               		        xp++;
		                }
            	        else if(i8 != BLACK){
                   		    xp++;
		                }
            	        else if(i9 != BLACK){
               		        xp++;
               		        yp++;
		                }
                        else
               	            end_of_line = true;
                    }while(end_of_line != true);
                    if(option == 1){
                        // only write if signoficant
                        if(weight > thresh_sig){
	    				    int[][] pixels= new int[loopindex][2];
	    				    for(loop3=1;loop3<=loopindex;loop3++) {
                           	    pixels[loop3-1][0]=xpix[loop3];
                           	    pixels[loop3-1][1]=ypix[loop3];
                           	}
                           	rst.addElement(pixels);
                        }


                    }
                    else{ // option = 0
                        // write all lines
                        int[][] pixels= new int[loopindex][2];
                        for(loop3=1;loop3<=loopindex;loop3++) {
                            pixels[loop3-1][0]=xpix[loop3];
                            pixels[loop3-1][1]=ypix[loop3];
                        }
                        rst.addElement(pixels);
                    }
                }
            }
	    xpix=ypix=null;
	    System.gc();
	    return rst;
    }

    void display(String name, char[][] data)
    {
        int h=data.length, w=data[0].length;
	    int[] data_1=yi.util.ImageUtil.makeNewImageFromBare(data);
  	    (new DisplayFrame(name,data_1,w,h)).show();
	}
}