import Targa.*;
import java.util.Vector;
import java.awt.Point;
import java.io.*;
import java.awt.Color;

/**
* Box count calculates the fractal index of a binary image. Basically, it just
* covers the image with squares of size n, and counts how many squares contain
* lesion. Then n is varied, and the results saved to a file. Subsequent working
* out of the fractal dimension is performed in Excel 97
*/

public class BoxCount2 {
	TargaPicture tp;
	int startRValue, endRValue, numberIterations;
	PrintWriter logFile;


	//-------------------------------------------------
	BoxCount2(String targaFile, String maskFile, PrintWriter logfile) {
		this(targaFile, maskFile, logfile, "10","10","30") ;
	}
	//-------------------------------------------------
	BoxCount2(String targaFile, String maskFile, PrintWriter logfile,
	String numberIterationsString, String startRValueString,
	String endRValueString) {
		try {
			tp = new TargaPicture(targaFile) ;
			//tp.read();
			tp.readMask(maskFile);
		} catch (IOException e) {
System.out.println("Error reading targa file " + targaFile + ". ACTION: Exit");
			System.exit(1) ;
		}

		this.logFile = logfile;
		try {
			numberIterations = new Integer(numberIterationsString).intValue() ;
		} catch (NumberFormatException e) {
System.out.println("Number format exception: numberIterations " + e) ;
System.out.println("using default: 10 iterations") ;
			numberIterations = 10;
		}
		try {
			startRValue = new Integer(startRValueString).intValue() ;
		} catch (NumberFormatException e) {
System.out.println("Number format exception: startRValue " + e) ;
System.out.println("using default: 5") ;
			startRValue = 5;
		}
		try {
			endRValue = new Integer(endRValueString).intValue() ;
		} catch (NumberFormatException e) {
System.out.println("Number format exception: endRValue " + e) ;
System.out.println("using default: 50") ;
			endRValue = 50;
		}
	}



	//-------------------------------------------------
	public void calculateFractalDimension() {
		int nr = 0;
		double ln10 = java.lang.Math.log(10);

		int rIncrement = (int)java.lang.Math.ceil(( endRValue - startRValue )/numberIterations);
		for (int i = 0, rValue = startRValue; i < numberIterations; i++, rValue += rIncrement) {
			nr = 0;
			for (int y = 0; y < tp.h; y += rValue) {
				for (int x = 0; x < tp.w; x += rValue) {
					if (isBoxFull(x,y,rValue) == false) {
// This code draws boxes like in the thesis document. To view, uncomment the new TargaView(tp); line below the
// loops.
						/* tp.addLine(new Point(x,y), new Point(x+rValue,y), Color.blue );
						tp.addLine(new Point(x,y), new Point(x,y+rValue), Color.blue);
						tp.addLine(new Point(x+rValue,y), new Point(x+rValue,y+rValue),Color.blue );
						tp.addLine(new Point(x,y+rValue), new Point(x+rValue,y+rValue),Color.blue );*/
					} else { // box has lesion in it
						nr ++;
						/*tp.addLine(new Point(x+rValue-1,y), new Point(x+rValue-1,y+rValue-1),Color.yellow);
						tp.addLine(new Point(x,y), new Point(x+rValue-1,y), Color.yellow );
						tp.addLine(new Point(x,y), new Point(x,y+rValue-1), Color.yellow);
						tp.addLine(new Point(x,y+rValue-1), new Point(x+rValue,y+rValue-1),Color.yellow );*/
					}
				}
			}
			//new TargaView(tp);
logFile.print("\t\t\t\t\t\tR:" + rValue + "\t" + (java.lang.Math.log(rValue))+"\t");
logFile.println("\tNR:" + nr + "\t" +(java.lang.Math.log(nr)));
		}
	}


  //-------------------------------------------------
	/** 
	* Takes a x,y position, and a length of box side value (r). Returns true if the mask data
	* indicates at least one pixel in the box is lesion.
	*/
	public boolean isBoxFull(int x, int y, int r) {
		try {
			for (int i = y; i < y+r; i++) {
				for (int j = x; j < x+r; j++) {
					if (tp.getMaskData(j,i) == true) return true;   // Box contains a pixel
				}
			}
			return false; // box empty
		} catch (ArrayIndexOutOfBoundsException e) {
			return false ; // assume box is empty
		}
  	}

	//-------------------------------------------------
	/** 
	* Boxcount takes the same arguments as Asym4. 2 if single iteration required, 3 if multiple iterations are performed.
	* See Asym4 for more details
	*/
	public static void main(String[] args) {
		if (args[0].equals("iterate") == true) {
			Vector v = new Vector() ;
			FileReader fr = null;
			StreamTokenizer st = null;
			int file = 0, numberOfFiles = 0;
			String dir1=null, dir2=null;
			
			try {
				fr = new FileReader(args[1]) ;
				st = new StreamTokenizer(fr) ;
				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 = (int)st.nval;
					v.addElement(new Integer(file)) ;
				}
			} catch (IOException e) {
System.out.println("Read Error in Specification File: ACTION: EXIT") ;
System.exit(1);
			}

			// Create log stream
			FileWriter fw = null;
			PrintWriter logFile = 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) ;
			}

			BoxCount2 b = null;
			for (int i = 0; i < numberOfFiles; i++) {
				logFile.print(((Integer)v.elementAt(i)).toString()+".tga");
				b= new BoxCount2(dir1+((Integer)v.elementAt(i)).toString()+".tga",dir2+((Integer)v.elementAt(i)).toString()+".msk",logFile);
				b.calculateFractalDimension() ;
			}
		} else { // Only iterate once, and print output to std out
			BoxCount2 b = new BoxCount2(args[0],args[1],new PrintWriter(System.out, true), args[2],args[3], args[4]) ;
			b.calculateFractalDimension() ;
		}
	}
}



