import java.io.*;
import java.util.Vector;

import Targa.*;

/**
* This is the Variance of variance calculation class. Box size is 20x20. Arbitrary of
* course, but it is very difficult to establish an optimal box size.
*/
public class DiffVariance{
	TargaPicture tp;
  PrintWriter log;

	public DiffVariance(String s, PrintWriter ps) throws IOException {
		this.log = ps;
		tp = new TargaPicture(s) ;
		tp.read();
	}




	double getDiffVariance() {
		double meanVarianceRed = 0.0;
 		double meanVarianceBlue = 0.0;
		double meanVarianceGreen = 0.0;
 		double meanVarianceL = 0.0;
 		double meanVarianceAlpha = 0.0;
 		double meanVarianceBeta = 0.0;
 		double meanVarianceLx = 0.0;
 		double meanVarianceAx = 0.0;
 		double meanVarianceBx = 0.0;
 		double meanVarianceCx = 0.0;
 		double meanVarianceHue = 0.0;

		double varVarianceRed = 0.0;
 		double varVarianceBlue = 0.0;
		double varVarianceGreen = 0.0;
 		double varVarianceL = 0.0;
 		double varVarianceAlpha = 0.0;
 		double varVarianceBeta = 0.0;
 		double varVarianceLx = 0.0;
 		double varVarianceAx = 0.0;
 		double varVarianceBx = 0.0;
 		double varVarianceCx = 0.0;
 		double varVarianceHue = 0.0;

    int count = 0;
    Vector varianceRed = new Vector();
    Vector varianceBlue = new Vector();
    Vector varianceGreen = new Vector();
    Vector varianceL = new Vector();
    Vector varianceAlpha = new Vector();
    Vector varianceBeta = new Vector();
    Vector varianceLx = new Vector();
    Vector varianceAx = new Vector();
    Vector varianceBx = new Vector();
    Vector varianceCx = new Vector();
    Vector varianceHue = new Vector();


    double[] temp = null;
		for (int i = 0; i < tp.h-21; i+= 21) {
			for (int j = 0; j < tp.w-21; j+= 21) {
				if (tp.getMaskData(j+10,i+10) == true) { // is middle of box lesion?
          temp = getVariance(tp,j,i,21,1,1);
      		varianceRed.addElement(new Double( temp[0]));
      		varianceBlue.addElement(new Double( temp[1]));
      		varianceGreen.addElement(new Double( temp[2]));
      		varianceL.addElement(new Double( temp[3]));
      		varianceAlpha.addElement(new Double( temp[4]));
      		varianceBeta.addElement(new Double( temp[5]));
      		varianceLx.addElement(new Double( temp[6]));
      		varianceAx.addElement(new Double( temp[7]));
      		varianceBx.addElement(new Double( temp[8]));
      		varianceCx.addElement(new Double( temp[9]));
      		varianceHue.addElement(new Double( temp[10]));
          count ++ ;
				}
			}
		}

    for (int i = 0; i < count; i++) {
  		meanVarianceRed += ((Double)varianceRed.elementAt(i)).doubleValue();
   		meanVarianceBlue += ((Double)varianceGreen.elementAt(i)).doubleValue();
   		meanVarianceGreen += ((Double)varianceBlue.elementAt(i)).doubleValue();
   		meanVarianceL += ((Double)varianceL.elementAt(i)).doubleValue();
   		meanVarianceAlpha += ((Double)varianceAlpha.elementAt(i)).doubleValue();
   		meanVarianceBeta += ((Double)varianceBeta.elementAt(i)).doubleValue();
   		meanVarianceLx += ((Double)varianceLx.elementAt(i)).doubleValue();
   		meanVarianceAx += ((Double)varianceAx.elementAt(i)).doubleValue();
   		meanVarianceBx += ((Double)varianceBx.elementAt(i)).doubleValue();
   		meanVarianceCx += ((Double)varianceCx.elementAt(i)).doubleValue();
   		meanVarianceHue += ((Double)varianceHue.elementAt(i)).doubleValue();
    }
		meanVarianceRed /= count;
 		meanVarianceBlue /= count;
		meanVarianceGreen /= count;
 		meanVarianceL /= count;
 		meanVarianceAlpha /=count;
 		meanVarianceBeta /=count;
 		meanVarianceLx /= count;
 		meanVarianceAx /= count;
 		meanVarianceBx /= count;
 		meanVarianceCx /= count;
 		meanVarianceHue /= count;

    double r=0,g=0,b=0,L=0,Alpha=0,Beta=0,Lx=0,Ax=0,Bx=0, Cx=0, Hue=0;
    for (int i = 0; i < count; i++) {
      r = ((Double)varianceRed.elementAt(i)).doubleValue();
      g = ((Double)varianceGreen.elementAt(i)).doubleValue();
      b = ((Double)varianceBlue.elementAt(i)).doubleValue();
      L = ((Double)varianceL.elementAt(i)).doubleValue();
      Alpha = ((Double)varianceAlpha.elementAt(i)).doubleValue();
      Beta = ((Double)varianceBeta.elementAt(i)).doubleValue();
      Lx= ((Double)varianceLx.elementAt(i)).doubleValue();
      Ax= ((Double)varianceAx.elementAt(i)).doubleValue();
      Bx= ((Double)varianceBx.elementAt(i)).doubleValue();
      Cx= ((Double)varianceCx.elementAt(i)).doubleValue();
      Hue= ((Double)varianceHue.elementAt(i)).doubleValue();

  		varVarianceRed += (r-meanVarianceRed)*(r-meanVarianceRed);
   		varVarianceGreen += (g-meanVarianceGreen)*(g-meanVarianceGreen);
   		varVarianceBlue += (b-meanVarianceBlue)*(b-meanVarianceBlue);
   		varVarianceL += (L-meanVarianceL)*(L-meanVarianceL);
   		varVarianceAlpha += (Alpha-meanVarianceAlpha)*(Alpha-meanVarianceAlpha);
   		varVarianceBeta += (Beta-meanVarianceBeta)*(Beta-meanVarianceBeta);
   		varVarianceLx += (Lx-meanVarianceLx)*(Lx-meanVarianceLx);
   		varVarianceAx += (Ax-meanVarianceAx)*(Ax-meanVarianceAx);
   		varVarianceBx += (Bx-meanVarianceBx)*(Bx-meanVarianceBx);
   		varVarianceCx += (Cx-meanVarianceCx)*(Cx-meanVarianceCx);
   		varVarianceHue += (Hue-meanVarianceHue)*(Hue-meanVarianceHue);
    }
log.print("\t"+varVarianceRed);
log.print("\t"+varVarianceGreen);
log.print("\t"+varVarianceBlue);
log.print("\t"+varVarianceL);
log.print("\t"+varVarianceAlpha);
log.print("\t"+varVarianceBeta);
log.print("\t"+varVarianceLx);
log.print("\t"+varVarianceAx);
log.print("\t"+varVarianceBx);
log.print("\t"+varVarianceCx);
log.println("\t"+varVarianceHue);



    return 0;
	}




	double[] getVariance(TargaPicture targPic, int x, int y, int wid, int xDirection, int yDirection) {
		RGBPoint pt = null;
		double sumRed = 0, sumGreen = 0, sumBlue = 0;
		double sumL = 0, sumAlpha = 0, sumBeta = 0;
		double sumLx = 0, sumAx = 0, sumBx = 0, sumCx = 0, sumHue =0;
		double varianceRed = 0, varianceGreen = 0, varianceBlue = 0;
		double varianceL = 0, varianceAlpha = 0, varianceBeta = 0;
		double varianceLx = 0, varianceAx = 0, varianceBx = 0, varianceCx = 0, varianceHue = 0;
		sumRed = 0; sumBlue = 0; sumGreen = 0;
		int count = 0;
		for (int i = 0; i < wid; i++) {
			for (int j=0; j < wid; j++) {
        try {
  				pt = new RGBPoint(targPic.getImageData(x+(j*xDirection),y+(i*yDirection))) ;
        } catch (ArrayIndexOutOfBoundsException e) {
          continue;
        }
				if (pt.r> 0) {
          pt.calcSpherical();
          pt.calcLAB();
					sumRed += pt.r;
					sumGreen += pt.g;
					sumBlue += pt.b;
          sumL += pt.L;
					sumAlpha += pt.alpha;
					sumBeta += pt.beta;
          sumLx += pt.Lx;
					sumAx += pt.ax;
					sumBx += pt.bx;
					sumCx += pt.Cx;
					sumHue += pt.hue;

					count++ ;
				}
			}
		}
		if (count < 1) return new double[3];
		sumRed /= count;
		sumGreen /= count;
		sumBlue /= count;
    sumL /=count;
		sumAlpha /=count;
		sumBeta /=count;
    sumLx /=count;
		sumAx /=count;
		sumBx /=count;
		sumCx /=count;
		sumHue /= count;

		 varianceRed = 0; varianceGreen = 0; varianceBlue = 0;
		 varianceL = 0; varianceAlpha = 0; varianceBeta = 0;
		 varianceLx = 0; varianceAx = 0; varianceBx = 0; varianceCx = 0; varianceHue =0;

		for (int i = 0; i < wid; i++) {
			for (int j=0; j < wid; j++) {
        try {
  				pt = new RGBPoint(targPic.getImageData(x+(j*xDirection),y+(i*yDirection))) ;
        } catch (ArrayIndexOutOfBoundsException e) {
          continue;
        }
				if (pt.r > 0 || pt.g > 0 || pt.b > 0) {
          pt.calcLAB();
          pt.calcSpherical();
					varianceRed += (pt.r-sumRed)*(pt.r-sumRed);
					varianceGreen += (pt.g-sumGreen)*(pt.g-sumGreen);
					varianceBlue += (pt.b-sumBlue)*(pt.b-sumBlue);
					varianceL += (pt.L-sumL)*(pt.L-sumL);
					varianceAlpha += (pt.alpha-sumAlpha)*(pt.alpha-sumAlpha);
					varianceBeta += (pt.beta-sumBeta)*(pt.beta-sumBeta);
					varianceLx += (pt.Lx-sumLx)*(pt.Lx-sumLx);
					varianceAx += (pt.ax-sumAx)*(pt.ax-sumAx);
					varianceBx += (pt.bx-sumBx)*(pt.bx-sumBx);
					varianceCx += (pt.Cx-sumCx)*(pt.Cx-sumCx);
					varianceHue += (pt.hue-sumHue)*(pt.hue-sumHue);

				}
			}
		}

		varianceRed /= count;
		varianceBlue /= count;
		varianceGreen /= count;
		varianceL /= count;
		varianceAlpha /= count;
		varianceBeta /= count;
		varianceLx /= count;
		varianceAx /= count;
		varianceBx /= count;
		varianceCx /= count;
		varianceHue /= count;

		double[] variance = new double[11];
		variance[0]= java.lang.Math.sqrt(varianceRed);
		variance[1]= java.lang.Math.sqrt(varianceGreen);
		variance[2]= java.lang.Math.sqrt(varianceBlue);
		variance[3]= java.lang.Math.sqrt(varianceL);
		variance[4]= java.lang.Math.sqrt(varianceAlpha);
		variance[5]= java.lang.Math.sqrt(varianceBeta);
		variance[6]= java.lang.Math.sqrt(varianceLx);
		variance[7]= java.lang.Math.sqrt(varianceAx);
		variance[8]= java.lang.Math.sqrt(varianceBx);
		variance[9]= java.lang.Math.sqrt(varianceCx);
		variance[10]= java.lang.Math.sqrt(varianceHue);
		return variance;

	}






	public static void main(String []args) {
    PrintWriter logFile = null;

    if (args[0].equals("iterate") == true) {
  		Vector files = new Vector() ;
		  FileReader fr = null;
  		StreamTokenizer st = null;
      int numberOfFiles = 0;
      String file = null;
      String dir1=null, dir2=null;

	  	try {
		  	fr = new FileReader(args[1]) ;
			  st = new StreamTokenizer(fr) ;
        st.slashStarComments(true);
  			st.nextToken() ;
        numberOfFiles = (int)st.nval;

  			st.nextToken() ;
        dir1 = (String)st.sval;
  			st.nextToken() ;
        dir2 = (String)st.sval;

		  	for (int i = 0; i < numberOfFiles; i++) {
			  	st.nextToken() ;
				  file = (new Integer((int)st.nval)).toString();
			          st.nextToken() ;
          if (st.sval != null && st.sval.length() == 1) {
            file += st.sval;
        	}
	else {
		st.pushBack();
	}
System.out.println(file);
		files.addElement(file) ;
			  }
  		} catch (IOException e) {
System.out.println("Read Error in Specification File: ACTION: EXIT") ;
System.exit(1);
	  	}

      // Create log stream
      FileWriter fw = null;
      try {
        fw = new FileWriter(args[2]) ;
        logFile = new PrintWriter(fw, true);
      } catch (IOException e) {
System.out.println("Error opening Log File: ACTION: Use System.out") ;
        // true turns automatic flushing on, so every println causes something to print
        logFile = new PrintWriter(System.out, true) ;
      }
System.out.println(numberOfFiles+" NNNN");
      DiffVariance d = null;
logFile.println("\t\tVVRed\t\tVVBlue\t\tVVGreen\t\tVVL\t\tVVAlpha\t\tVVBeta\t\tVVL*\t\tVVa*\t\tVVb*");
      for (int i = 0; i < numberOfFiles; i++) {
        try {
System.out.println(dir1+(String)files.elementAt(i));
          d = new DiffVariance(dir1+(String)files.elementAt(i)+".tga", logFile);
          } catch (IOException e) {
            logFile.println("File not found "+e) ;
            continue;
          }
          if (d.tp.readMask(dir2+(String)files.elementAt(i)+".msk") == -1) {
            logFile.println("Mask Error");
            continue;
          } else {
            logFile.print((String)files.elementAt(i)+"\t");
            d.getDiffVariance();
          }

      }
    }



    else { // Only iterate once, and print output to std out
      logFile =new PrintWriter(System.out,true);
logFile.print("\t\tVVRed\t\tVVBlue\t\tVVGreen\t\tVVL\t\tVVAlpha\t\tVVBeta\t\tVVL*\t\tVVa*\t\tVVb*");
      
      DiffVariance d = null;
      try {
    		d = new DiffVariance(args[0]+".tga",logFile);
      } catch (IOException e) {
System.out.println("Error loading file: " + e +" action EXIT") ;
        System.exit(1);
      }
      if (d.tp.readMask(args[1]+".msk") == -1) {
        logFile.println("Mask Error");
        System.exit(1);
      }
      d.getDiffVariance();
      logFile.println();
    }
	}
}

