package Targa;
/**
* TargaPicture reads, stores and manipulates an image stored in Targa format.
* The mask files for each picture are also loaded and stored in this class. Every
* targa file will be an instance of this class. To view targa files, make an instance
* of TargaPicture,tp, and tp.read(); then create a new TargaView(tp);... 
* Often however, actually reading the file is not necessary. If you are simply interested
* in the mask data, tp = new TargaPicture(filename) and tp.readMaskData(maskfile) are all
* that is required. This saves a lot of time... 
*/
import java.io.* ;
import java.util.Vector;
import java.awt.Point;
import java.awt.Color;

public class TargaPicture {
	public int w,h;
	private int []imageData;
	private boolean []maskData;

	Vector boundary ;
	Vector lines;
	Vector colours;

	byte[] byteStore ;
	int byteCount=0;

	private int []redHistogram;
	private int []greenHistogram;
	private int []blueHistogram;
	private byte fileType ;
	private File targaFile ;
	private String fileName;

	static final int NONE = 0;
	static final int COLOUR_MAPPED = 1;
	static final int TRUE_COLOUR_UNC = 2;
	static final int BLACK_WHITE_UNC = 3;
	static final int COLOUR_MAPPED_RLE= 9;
	static final int TRUE_COLOUR_RLE= 10;
	static final int BLACK_WHITE_RLE= 11;


  //----------------------------------------------------
	public TargaPicture(String file) throws IOException {
		byteStore = new byte[100];
		targaFile = new File(file) ;
		fileName = file;

		if (!(targaFile.exists())) throw new IOException("File doesnt exist:"+file) ;
 
		FileInputStream fis = new FileInputStream(targaFile) ;
		BufferedInputStream bis = new BufferedInputStream(fis);
		DataInputStream dis = new DataInputStream(bis) ;
		dis.readByte();		dis.readByte();
		fileType = dis.readByte() ;							// Read in Image Type
		for (int i = 0; i < 9; i++) {
			dis.readByte();
		}

//System.out.println("File type:"+fileType) ;
															// Read in next four bytes which is width and height data
		w += dis.readUnsignedByte() ;
		w += 256*dis.readUnsignedByte() ;
		h += dis.readUnsignedByte() ;
		h += 256*dis.readUnsignedByte() ;
System.out.println("File:"+file+" Width "+w+" height "+h);

		imageData = new int[w*h] ;
		maskData = new boolean[w*h];
		redHistogram = new int[256];
		greenHistogram = new int[256];
		blueHistogram = new int[256];

		dis.close() ;
		bis.close() ;
		fis.close() ;
	}


  //----------------------------------------------------
	public TargaPicture(int w,int h,int col) {
		this.w = w;
		this.h = h;
		imageData = new int[w*h] ;
		int val = w*h;
		if (col != 0) {
			for (int i = 0; i < val; i++) {
				imageData[i] = col;
			}
		}
		maskData = new boolean[w*h];
		redHistogram = new int[256];
		greenHistogram = new int[256];
		blueHistogram = new int[256];
	}

	public TargaPicture(int w,int h) {
		this(w,h,0);
	}


  //----------------------------------------------------
	public void read() throws IOException {

		FileInputStream fis = new FileInputStream(targaFile) ;
		BufferedInputStream bis = new BufferedInputStream(fis);
		DataInputStream dis = new DataInputStream(bis) ;
		int r=0,g=0,b=0,l=0 ;
		int heightIndex = 0;
		for (int i = 0; i < 18; i++) {
			byteStore[i] = dis.readByte() ;										// Skip next 9 bytes
		}
		for (int j = 0; j < h; j++) {
			heightIndex = j*w;
			for (int i = 0; i < w; i++) {
				r = dis.readUnsignedByte();
				g = dis.readUnsignedByte();
				b = dis.readUnsignedByte();
				redHistogram[r]++;
				greenHistogram[g]++;
				blueHistogram[b]++;

				imageData[i+heightIndex] = 0xff000000 | r | g << 8 | b << 16;
			}
		}

		dis.close() ;
		bis.close() ;
		fis.close() ;
//System.out.println("Finished read") ;
	}


  //----------------------------------------------------
	public void write(String file, boolean writeMask) throws IOException {
		int r,g,b,pt;

		FileOutputStream fos = new FileOutputStream(file) ;
		DataOutputStream dos = new DataOutputStream(fos) ;
		int heightIndex = 0;


		for (int i = 0; i < 18; i++) {
			dos.writeByte(byteStore[i]) ;		// Write next 18 stored bytes
		}

		for (int j = 0; j < h; j++) {
			heightIndex = j*w;
			for (int i = 0; i < w; i++) {
				pt = getImageData(i+heightIndex);
				r = (pt & 0xFF0000) >>> 16;
				g = (pt & 0xFF00) >>> 8 ;
				b = (pt & 0xFF) ;

				if (writeMask == true) {
					if (getMaskData(i+heightIndex) == true) {
						r = g = b = 255;
					} else {
						r = g = b = 0;
					}
				}

				dos.writeByte(b);
				dos.writeByte(g);
				dos.writeByte(r);

			}
		}
		dos.close() ;
		fos.close() ;
//System.out.println("Finished write") ;
	}


  //----------------------------------------------------
	public void writeMask(String file) {
		try {
			FileOutputStream fos = new FileOutputStream(file) ;
			DataOutputStream dos = new DataOutputStream(fos) ;
			dos.writeInt(w) ;
			dos.writeInt(h) ;
			for (int i =0; i < w*h; i++) {
				dos.writeBoolean(maskData[i]) ;
			}
			dos.close() ;
			fos.close() ;
		} catch (IOException e) {
System.out.println("Error: " + e) ;
		}
//System.out.println("Finished write mask") ;

	}


  //----------------------------------------------------
	public int readMask(String file) {
		try {
			FileInputStream fis = new FileInputStream(file) ;
			DataInputStream dis = new DataInputStream(fis) ;
			if (dis.readInt() != w) {
				return -1;
			}
			if (dis.readInt() != h) {
				return -1;
			}
			for (int i =0; i < w*h; i++) {
				maskData[i] = dis.readBoolean() ;
			}

			dis.close() ;
			fis.close() ;
		} catch (IOException e) {
System.out.println("Error: " + e) ;
      return -1;
		}
    return 0;
	}

  //----------------------------------------------------
	public int getImageData(int x,int y) {
		if ((x < w) && (y < h) && (x >= 0) && (y >= 0)) return imageData[x+y*w] ;
		else throw new ArrayIndexOutOfBoundsException("Image Data out of range: "+ x + " " +y+" " + w + " " + h);
	}


  //----------------------------------------------------
	public boolean getMaskData(int x,int y) {
		if ((x < w) && (y < h) && (x >= 0) && (y >= 0)) return maskData[x+y*w] ;
		else return false;
	}


  //----------------------------------------------------
	public int getWidth() { return w; }
	public int getHeight() { return h; }
	public int[] getImageData() { return imageData; }
  //----------------------------------------------------
  public int getImageData(int offset) throws ArrayIndexOutOfBoundsException {
    if (offset < imageData.length) return imageData[offset] ;
    else throw new ArrayIndexOutOfBoundsException("Image Data out of range:"+offset + " " + imageData.length);
  }
 //----------------------------------------------------
	public boolean getMaskData(int offset) {
    if (offset < imageData.length) return maskData[offset] ;
    else throw new ArrayIndexOutOfBoundsException("Mask Data out of range:"+offset + " " + maskData.length);

  }
  //---------------------------------------------------
	public boolean[] getMaskData() { return maskData; }
	public int getRedHistogramValue(int i) { return redHistogram[i] ; }
	public int getGreenHistogramValue(int i) { return greenHistogram[i] ; }
	public int getBlueHistogramValue(int i) { return blueHistogram[i] ; }
	public int [] getRedHistogram() { return redHistogram ; }
	public int [] getGreenHistogram() { return greenHistogram ; }
	public int [] getBlueHistogram() { return blueHistogram ; }
	public Vector getBoundaryVector() { return boundary; }
	public Vector getLinesVector() { return lines; }
	public Vector getColoursVector() { return colours; }

	public void setBoundary(Vector v) { boundary = v; }
	public void setLines(Vector v) { lines =v ;}

	public void setImageData(int x,int y,int rgba) { if ((x < w) && (y < h)) imageData[x+y*w] = rgba;}
	public void setImageData(int offset,int rgba) { if (offset < imageData.length) imageData[offset] = rgba;}
	public void setMaskData(int x,int y,boolean b) { if ((x < w) && (y < h)) maskData[x+y*w] = b;}
	public void setMaskData(int offset,boolean b) { maskData[offset] = b;}

	public String getName() {
		return targaFile.getName() ;
	}

  //----------------------------------------------------
	public void threshold(int r,int g, int b) {
		RGBPoint pt = null;
		int point = 0;

		if (r > 255 || r < 0) return ;
		if (g > 255 || g < 0) return ;
		if (b > 255 || b < 0) return ;

		int threshold = 0xFF000000 | r << 16 | g << 8 | b ;
		for (int i = 0; i < w*h; i++) {
			pt = new RGBPoint(imageData[i]);
			if(pt.r < r && pt.g < g && pt.b < b) {
				maskData[i] = true;
			}
/*
			if(pt.r < r) {
				point += 0xFF0000;
			}
			if(pt.g < g) {
				point += 0xFF00;
			}
			if(pt.b < b) {
				point += 0xFF;
			}
			point += 0xff000000;
			imageData[i] = point;*/
		}

	}



	public void threshold(int greyLevel) { threshold(greyLevel,greyLevel,greyLevel) ;}


  //----------------------------------------------------
	public void calculateHistogram() {
		RGBPoint pt = null;
		redHistogram = new int[256];
		greenHistogram = new int[256];
		blueHistogram = new int[256];

		for (int i = 0; i < w*h; i++) {
			pt = new RGBPoint(getImageData(i)) ;
			redHistogram[pt.r]++ ;
			blueHistogram[pt.b]++ ;
			greenHistogram[pt.g]++ ;

		}
System.out.println("Finished histogram");
	}

  //----------------------------------------------------
	public void addLine(int x1,int y1, int x2,int y2) {
		if (lines== null) {
			lines= new Vector() ;
		}
		lines.addElement(new Point(x1,y1)) ;
		lines.addElement(new Point(x2,y2)) ;
	}

	public void addLine(Point p1,Point p2) {
		addLine(p1.x, p1.y, p2.x,p2.y) ;
	}

  public void addLine(Point p1, Point p2, Color c) {
		addLine(p1.x, p1.y, p2.x,p2.y) ;
    if (colours == null) colours = new Vector();
    colours.addElement(c) ;
	}


  //----------------------------------------------------
	public static void main(String [] args) {
		try {
			TargaPicture t = new TargaPicture(args[0]) ;
			t.read();
			new TargaView(t);
//			t.write(args[1],false);
//			t.threshold(240,240,240) ;
// 			t.writeMask(args[0]);
		} catch (IOException e) {
System.out.println("IO error " + e) ;
		}
	}
}






