import java.io.*;
import java.util.*;
import javax.swing.text.BadLocationException;
import javax.media.opengl.*;

/**
 * CS400 3DMotionCapture
 * CMCAnimationPanel
 * Control class for the threads that display animation according to the data given from MarkerTracking class 
 * and display the original images in synchronizing  
 * 
 * @author Kohei Shinkawa
 * @version 3-11-2010
 * */

public class CMCAnimationPanel implements StickFigureAnimation{
	
	static final double HEIGHT = 2; //Used to be necessary to display 2D animation (not for 3D)
	static final double WIDTH =  2;
	
	private int fps; /*Frame per second to pass for animators in the threads class*/
	private String folder;
	double[][] coordsArray;
	float scale;

	private GLJPanel panelAnim = new GLJPanel();  /*Two panels where the pictures are drawn*/
	private GLJPanel panelVid = new GLJPanel();
	
	private CMCThreadInfo info;
	private CMCAnimationThread3D stickFigure = null;
	private CMCVideoThread video = null;
	private Thread animeT, videoT;
	
	private double zmin; 
	
	public CMCAnimationPanel(){
		this(30);
	}

	public CMCAnimationPanel(int fps){
		this.fps = fps;
	}
	
	/*Initialize the threads constructing the two threads class and information class to share*/
	public void initializeThreads(){
		//Kill the thread if they have been created before
		if(video != null){
			video.animator.stop();
			stickFigure.animator.stop();
			video.animator.remove(video.canvas);
			stickFigure.animator.remove(stickFigure.canvas);
			animeT.stop();
			videoT.stop();

		}
		
		info = new CMCThreadInfo(HEIGHT, WIDTH, false,  0, coordsArray.length);
		video = new CMCVideoThread(coordsArray, panelVid, fps, info, folder);
		stickFigure = new CMCAnimationThread3D(coordsArray, panelAnim, fps, info, scale, zmin);
		videoT = new Thread(video);
		animeT = new Thread(stickFigure);
		videoT.start();
		animeT.start();
	}
	
	/**Looks complicated but it's just a setter*/
	public void loadDirect(double[][] coords) {
		coordsArray = coords;
	}

	/**
	 * Load file name inputFile. The data must be stored in csv format.
	 * The first row of the file should be the name of folder where the pictures are obtained
	 * Determine the maximum length of along x-y-z axies to scale all the coordinates later*/
	public void loadFile(String filename) {
		ArrayList<double[]> list = new ArrayList<double[]>();
		BufferedReader reader = null;
		int row =0;
		int column = 0;
		double maxx = -100;
		double minx = 100;
		double maxy = -100;
		double miny = 100;
		double maxz = -100;
		double minz = 100;
		try{
			FileInputStream fstream = new FileInputStream(filename);
			DataInputStream in = new DataInputStream(fstream);
			reader = new BufferedReader(new InputStreamReader(in));
			int count = 0;
			String strLine;
			while ((strLine = reader.readLine()) != null)   {
				if(count == 0){
					/*Treat the first line differently*/
					setInFolder(strLine.trim());
					count ++;
				}
				else{
					String[] temp = strLine.split(","); 
					double[] tempdoubles = new double[temp.length];
					for(int i =0; i < temp.length; i++){
						tempdoubles[i] = Double.valueOf(temp[i]);
						if(i%3 ==0){
							if(maxx < tempdoubles[i]) maxx = tempdoubles[i];
							if(minx > tempdoubles[i]) minx = tempdoubles[i];
						}
						if(i%3 ==1){
							if(maxy < tempdoubles[i]) maxy = tempdoubles[i];
							if(miny > tempdoubles[i]) miny = tempdoubles[i];
						}
						if(i%3 ==2){
							if(maxz < tempdoubles[i]) maxz = tempdoubles[i];
							if(minz > tempdoubles[i]) minz = tempdoubles[i];
						}
					}
					list.add(tempdoubles);
					row++;
				}
			}
		}catch(IOException ioe){
			ioe.printStackTrace();
		}
		column = list.get(0).length;

		//Fixing the ArrayList to Array
		double[][] coords = new double[row][column];
		for(int k = 0; k< list.size(); k++){
			coords[k] = list.get(k);
		}

		loadDirect(coords);
		zmin = minz;
		double xdiff = maxx-minx;
		double ydiff = maxy-miny;
		double zdiff = maxz-minz;
		
		if((xdiff > ydiff) && (xdiff > zdiff)) scale = 1/(float)xdiff;
		else if(ydiff > zdiff) scale = 1/(float)ydiff;
		else scale = 1/(float)zdiff;
	}
	
	/**Change the folder name to load pictures*/
	public void setInFolder(String folder){
		this.folder = folder;
	}
	
	/**Returns the panes for CMCgui*/
	public GLJPanel[]  getCanvas(){
		GLJPanel[] temp = {panelAnim, panelVid};
		return temp;
	}

	
	public int getNumFrames() {
		return coordsArray.length;
	}
	
/*****Control methods. Change the variables for threads. Then threads internally catches it in their display() method...****/
	
	public void setFrame(int frame) throws BadLocationException {
		info.setCurFrame(frame);
	}
	
	public int getFrame(){
		return info.getCurFrame();
	}
	
	public void setRotation(double[] trans){
		double[] temp = info.getRotation();
		temp[0] = temp[0]+ trans[0];
		temp[1] = temp[1]+ trans[1];
		temp[2] = temp[2]+ trans[2];
		info.setRotation(temp);
	}
	
	public void resetRotation(){
		double[] temp ={0,0,0};
		info.setRotation(temp);
	}
	
	public void setCameraDisplay(int mode){
		info.setMode(mode);
	}

	public void playAnimation() {
		info.setPlay(false);
		info.setCurFrame(0);
		
		info.setEndFrame(coordsArray.length);
		info.setRewind(false);
		info.setPlay(true);
	}

	public void playAnimation(int framenum) throws BadLocationException {
		info.setPlay(false);
		if(info.getCurFrame()+framenum > coordsArray.length) throw new BadLocationException("Bad Forwarding Request", info.getCurFrame()+framenum - coordsArray.length);
		info.setEndFrame(info.getCurFrame()+ framenum);
		info.setRewind(false);
		info.setPlay(true);
	}

	public void rewindAnimation() {
		info.setPlay(false);
		
		if(!info.isRewind()){
			info.setEndFrame(0);
			info.setRewind(true);
			}
		else{
			info.setRewind(false);
			info.setEndFrame(coordsArray.length);
		}
		info.setPlay(true);

	}
	public void rewindAnimation(int framenum) throws BadLocationException {
		System.out.println("RewindAnimation");
		info.setPlay(false);
		int curFrame = info.getCurFrame();
		if(curFrame-framenum < 0) throw new BadLocationException("Bad Rewinding Request", curFrame+framenum - coordsArray.length);	
		info.setCurFrame(info.getEndFrame());
		info.setEndFrame(curFrame-framenum);
		info.setPlay(true);
		info.setRewind(true);
	}

	public void pause() {
		if(info.isPlay()){info.setPlay(false);}
		else{info.setPlay(true);}
	}

	public void setSkin(int skinMode){		
		info.setSkin(skinMode);
	}
	public void resetAnimation() {
		info.setPlay(false);
		info.setRewind(false);

		info.setCurFrame(0);
		info.setEndFrame(1);
		info.setPlay(true);

		
		info.setPlay(false);
		info.setCurFrame(0);
		info.setEndFrame(coordsArray.length);
	}

	public float[] getCurMatrix(){
		return info.getCurMatrix();
	}

}
