package util;

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

import Targa.*;
import util.Median;

/**
* Traces contour of .msk files. Uses region growing to find all of the pixels.
* Originally, this was used with the output of boundary detection algorithms,
* so region growing was necessary, but with hand drawn masks it is really no
* longer required. Traces the contour using 8-connectedness... and writes points
* to a .bnd file
*/
public class TraceContour {
	public Vector boundaryData;
	TargaPicture tp;



	public TraceContour(TargaPicture tp, String s) {
		Point p = null;
		this.tp = tp ;
		boundaryData = new Vector();

		p = regionGrow();
		traceContour(p);
		writeContour(s);
//		tp.writeMask(s.substring(0,s.indexOf('.'))+".tc");
	}



	public void writeContour(String s) {
		Point p = null;
		try {
			FileOutputStream fos = new FileOutputStream(s) ;
			DataOutputStream dos = new DataOutputStream(fos) ;
			dos.writeBytes(boundaryData.size()+"\n");
			for (int i = 0; i < boundaryData.size() ; i++) {
				p = (Point)boundaryData.elementAt(i) ;
				dos.writeBytes(p.x + " " + p.y+ "\n") ;
			}
		} catch (IOException e) {
System.out.println("Error writing BoundaryDataFile " + e) ;
System.exit(1) ;
		}
	}



	public Vector getBoundaryVector() {
		return boundaryData;
	}



	public Point[] getBoundaryArray() {
		Point[] points = new Point[boundaryData.size()];
		for (int i=0; i < boundaryData.size(); i++) {
			points[i] = (Point)(boundaryData.elementAt(i)) ;
		}
		return points;
	}


	

	public Point regionGrow() {
		int x,y;
		Point p;
		TargaPicture tp2 = new TargaPicture(tp.w,tp.h);
		Vector v = new Vector() ;
		v.addElement(p=findLesion()) ;
		for (int i = 0; i < v.size(); i++) {
			x = ((Point)v.elementAt(i)).x;
			y = ((Point)v.elementAt(i)).y;
			try {
        tp2.setImageData(x,y,tp.getImageData(x,y));

      	if((tp.getMaskData(x-1,y) == true) && (tp2.getMaskData(x-1,y) == false)){
			  	v.addElement(new Point(x-1,y)) ;
  				tp2.setMaskData(x-1,y,true);
	  		}

		  	if((tp.getMaskData(x+1,y) == true)&& (tp2.getMaskData(x+1,y) == false)) {
			  	v.addElement(new Point(x+1,y)) ;
				  tp2.setMaskData(x+1,y,true);
  			}

	  		if((tp.getMaskData(x,y+1) == true) && (tp2.getMaskData(x,y+1) == false)){
		  		v.addElement(new Point(x,y+1)) ;
			  	tp2.setMaskData(x,y+1,true);
  			}

	  		if((tp.getMaskData(x,y-1) == true) && (tp2.getMaskData(x,y-1) == false)){
		  		tp2.setMaskData(x,y-1,true);
			  	v.addElement(new Point(x,y-1)) ;
  			}
      } catch (ArrayIndexOutOfBoundsException e) {
      // Off the edge of the picture, so dont add any pixels
System.out.println("Off edge");
      }

//System.out.print("\b\b\b\b\b\b"+v.size());
		}

		tp = tp2;
		return p;
	}


	/** 
	* Once region grow has found a point in the lesion, trace contour traces
	* the boundary of the lesion using eight-connectedness.
	*/
	public void traceContour(Point pt) {
		int sum, sx=0, sy=0 ;
		int cx,cy ;

		cx = pt.x;
		cy = pt.y;

		while (tp.getMaskData(cy*tp.w+cx+1) == true) {
				cx++ ;
		}

		
		byte dir = 2;
		Point pnt  = new Point(cx,cy) ;
		int q = 0; int newQ ;
		boolean[] r = new boolean[10] ;

		boundaryData.addElement(pnt);
		do {
			r[0] = tp.getMaskData(pnt.x+1+(pnt.y*tp.w));
			r[1] = tp.getMaskData(pnt.x+1+(pnt.y+1)*tp.w) ;
			r[2] = tp.getMaskData(pnt.x+(pnt.y+1)*tp.w) ;
			r[3] = tp.getMaskData(pnt.x-1+(pnt.y+1)*tp.w);
			r[4] = tp.getMaskData(pnt.x-1+(pnt.y*tp.w)) ;
			r[5] = tp.getMaskData(pnt.x-1+(pnt.y-1)*tp.w);
			r[6] = tp.getMaskData(pnt.x+(pnt.y-1)*tp.w) ;
			r[7] = tp.getMaskData(pnt.x+1+(pnt.y-1)*tp.w);

		        newQ = q ;
			do {
				if (r[newQ] == true) break ;
				else newQ ++ ;
				if (newQ > 7) {
					newQ = 0;
				}

			} while (newQ != q );
			
			switch(newQ) {
				case 0 : pnt = new Point(pnt.x+1,pnt.y) ; q = 6; break ;
				case 1 : pnt = new Point(pnt.x+1,pnt.y+1) ; q = 6; break ;
				case 2 : pnt = new Point(pnt.x,pnt.y+1) ; q = 0; break ;
				case 3 : pnt = new Point(pnt.x-1,pnt.y+1); q = 0; break ;
				case 4 : pnt = new Point(pnt.x-1,pnt.y); q = 2; break ;
				case 5 : pnt = new Point(pnt.x-1,pnt.y-1); q = 2 ; break ;
				case 6 : pnt = new Point(pnt.x,pnt.y-1); q = 4; break ;
				case 7 : pnt = new Point(pnt.x+1,pnt.y-1); q = 4; break ;
			}

			boundaryData.addElement(pnt) ;
		} while(!(pnt.equals(boundaryData.elementAt(0)))) ;
System.out.println(boundaryData.size() + " Boundary elements found");
	}


	/**
	* This works similarl to the PSPMaskToMask code. It can either be run on a directory or on a 
	* single file. Takes args[0] which is targa file, args[1] which is mask file (or directory)
	* and output .bnd boundary file either to the original file directory (in the case of single file)
	* or to a `bound' directory that branches from the image directory
	*/  

	public static void main(String[] args) {
		int[] met = new int[4];
		RGBPoint pt = null;
		File f = new File(args[0]) ;
		if (f.exists() == true) {
			if (f.isDirectory() != true) {

			try {
				TargaPicture tp = new TargaPicture(args[0]) ;
				tp.read() ;
				tp.readMask(args[1]);
				TraceContour tc = new TraceContour(tp,args[0]+".bnd") ;
				tp.setBoundary(tc.boundaryData);
				TargaView tv = new TargaView(tp);
			} catch (IOException e) {
System.out.println("Error " +e);
			}
		} else { // file is a directory so process all .tga files
			String[] directory = f.list() ; // get list of all files in directory
			String outputFile = null;
			String maskFile = null;
			for (int i =0; i < directory.length; i++) {
System.out.println("________________________________________________");
				try {
					if (directory[i].lastIndexOf(".tga") == -1) {
System.out.println(directory[i] + " is not a valid targa file. Action:CONTINUING");
						continue;
					}
System.out.println("TRACE CONTOUR : "+ directory[i]);
					maskFile =args[1]+directory[i].substring(0,directory[i].indexOf('.'))+".msk";
					TargaPicture tp = new TargaPicture(args[0]+directory[i]) ;
					tp.read() ;
					if (tp.readMask(maskFile) == -1) {
System.out.println("Error reading mask " + maskFile + " Action: CONTINUING");
						continue;
					}
					outputFile = args[0]+"bound\\"+
					directory[i].substring(0,directory[i].indexOf('.'))+".bnd";
					TraceContour tc = new TraceContour(tp,outputFile) ;
System.out.println("_________________________________________");
				} catch (IOException e) {
System.out.println("Trace Contour Error - Directory: "+ e) ;
				}
			}
		}
	} else { // File doesnot exist
System.out.println("Cant find file " + args[0] + ". Does it exist?");
	}

	}


}
