package projectEQ2440.camera;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.content.Context;

/**
 * <b>public class PreviewPicture</b><br/>
 * Class to save the pictures, contains only one channel (for colored pictures, 3 <i>PreviewPicture</i> are needed)
 */
public class PreviewPicture {
	
	// the context of the application
	private static Context context;
	
	// Size of the picture
	private int width, height;
	
	// The values of each pixel
	private byte[][][] image;
	
	// Information about the picture
	private Info info;
	
	// File for saving on SD card
	private File fileSD;
	
	// TODO comment
	public static void setContext(Context newContext) {
		context = newContext;
	}
	
	// TODO comments
	public PreviewPicture(byte[] data, int width, int height, Info info) {
		this.height = height;
		this.width = width;
		this.info = info;
		
		register(data);
		
		info = null;
		fileSD = null;
	}
	
	//TODO comments
	private void register(byte[] data) {
		int i, j, kY, kCb, kCr;
		
		if (info.color == Info.BW) {
			image = new byte[1][height][width];
			
			kY = 0;
			for (i=0; i<height; i++) {
				for (j=0; j<width; j++) {
					image[0][i][j] = data[kY];
					kY++;
				}
			}
		} else if (info.color == Info.RGB) {
			image = new byte[3][height][width];
			
			kY = 0;
			int CrOffset = width*height;
			int CbOffset = (CrOffset/4)*5;
			int width2 = width/2;
			
			for (i=0; i<height; i++) {
				for (j=0; j<width; j++) {
					kCr = CrOffset + width2*(i/2) + j/2;
					kCb = CbOffset + width2*(i/2) + j/2;
					image[0][i][j] = (byte) Math.max(0,Math.min(255, (data[kY]&0xFF) + (1402*((data[kCr]&0xFF)-128))/1000 ));
					image[1][i][j] = (byte) Math.max(0,Math.min(255, (data[kY]&0xFF) - ( 71414*((data[kCr]&0xFF)-128) + 34414*((data[kCb]&0xFF)-128) )/100000 ));
					image[2][i][j] = (byte) Math.max(0,Math.min(255, (data[kY]&0xFF) + (1772*((data[kCb]&0xFF)-128))/1000 ));
					kY++;
				}
			}
		}
		
	}
	
	// TODO comment
	public void saveOnSD() {
		if (image == null) return;
		try {
			if (fileSD == null) fileSD = File.createTempFile("Preview", "Picture.tmp", context.getExternalCacheDir());
			
			FileOutputStream out = new FileOutputStream(fileSD);
			
			for (int k=0; k<image.length; k++) {
				for (int l=0; l<image[k].length; l++) {
					out.write(image[k][l]);
				}
			}
			
			out.close();
			
			image = null;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	// TODO comment
	public void loadFromSD() {
		if (fileSD == null) return;

		try {
			FileInputStream in = new FileInputStream(fileSD);
			
			byte[] data = new byte[(int) fileSD.length()];
			in.read(data, 0, data.length);
			register(data);
			
			in.close();
			
			fileSD.delete();
			fileSD = null;
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	
	// TODO comments
	public boolean onSD() {
		return fileSD != null;
	}
	
	// TODO comments
	public byte pixelWhite(int row, int col) {
		if (row < 0 || row >= height || col < 0 || col >= width || info.color != Info.BW) return 0;
		if (fileSD != null && image == null) loadFromSD();
		return image[0][row][col];
	}
	
	// TODO comments
	public byte pixelRed(int row, int col) {
		if (row < 0 || row >= height || col < 0 || col >= width || info.color != Info.RGB) return 0;
		if (fileSD != null && image == null) loadFromSD();
		return image[0][row][col];
	}
	
	// TODO comments
	public byte pixelGreen(int row, int col) {
		if (row < 0 || row >= height || col < 0 || col >= width || info.color != Info.RGB) return 0;
		if (fileSD != null && image == null) loadFromSD();
		return image[1][row][col];
	}
	
	// TODO comments
	public byte pixelBlue(int row, int col) {
		if (row < 0 || row >= height || col < 0 || col >= width || info.color != Info.RGB) return 0;
		if (fileSD != null && image == null) loadFromSD();
		return image[2][row][col];
	}
	
	/**
	 * <b>public int getWidth()</b><br/>
	 * Get the width of the picture
	 * 
	 * @return the width of the picture
	 */
	public int getWidth() {
		return width;
	}
	
	/**
	 * <b>public int getHeight()</b><br/>
	 * Get the height of the picture
	 * 
	 * @return the height of the picture
	 */
	public int getHeight() {
		return height;
	}

	/**
	 * <b>public void destroyPicture()</b><br/>
	 * Clean the picture by destroying everything in the memory. Very useful to save memory but nothing left except the information if set. 
	 */
	public void destroyPicture() {
		height = 0;
		width = 0;
		
		if (image != null) {
			image = null;
		}
		
		if (fileSD != null) {
			fileSD.delete();
			fileSD = null;
		}
	}
	
	/**
	 * <b>public Info getInfo()</b><br/>
	 * Get the informations about the picture
	 * 
	 * @return information about the picture
	 */
	public Info getInfo() {
		return info;
	}
	
	/**
	 * <b>public static class Info</b><br/>
	 * Class saving informations about the picture
	 */
	public static class Info {
		
		// Static corresponding values for some informations
		public final static int BLANK = -1;
		public final static int BW = 0;
		public final static int RGB = 1;
		
		/**
		 * <b>public final int color</b><br/>
		 * The color of the picture
		 */
		public final int color;
		
		/**
		 * <b>public final long time</b><br/>
		 * The time when the picture has been taken
		 */
		public final long time;

		/**
		 * <b>public Info(int color, long time)</b><br/>
		 * Constructor which definitely set the informations values 
		 * 
		 * @param color : the color of the picture (see static values of <i>Info</i> class)
		 * @param time : the time when the picture has been taken in millisecond
		 */
		public Info(int color, long time) {
			this.color = color;
			this.time = time;
		}
		
	}
	
}
