import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.List;
import javax.media.opengl.*;
import com.sun.opengl.util.FPSAnimator;
import com.sun.opengl.util.texture.*;
import javax.media.opengl.glu.GLU;

/**
 * CS400 3DMotionCapture
 * CMCVideoThread
 * 
 * Display the jpg pictures in the specified folder.  
 * Due to its I/O input slowness, this thread should run ahead of CMCAnimation.
 * So, if you want to notify something when the two panels display the same frame, you should update CMCAnimationThread instead.
 * @author Kohei Shinkawa*/
public class CMCVideoThread implements Runnable, GLEventListener{

	private GLU glu = new GLU();
	GLJPanel canvas; 
	double[][] coordsArray; 
	FPSAnimator animator;
	private CMCThreadInfo info;
	Object[][] pics = new Object[3][];

	
	public CMCVideoThread(double[][] coords, GLJPanel canvas, int fps, CMCThreadInfo info, String inFolder){	
		this.info = info;
		this.canvas = canvas;
		ArrayList<File> FILES0 = new ArrayList<File>();
		ArrayList<File> FILES1 = new ArrayList<File>();
		ArrayList<File> FILES2 = new ArrayList<File>();
		
		/*Load up all the filenames in the folders*/
		addFilesRecursively(new File(inFolder+"/RC"), FILES0);
		Collections.sort((List<File>)FILES0, new FileComparator());
		addFilesRecursively(new File(inFolder+"/CC"), FILES1);
		Collections.sort((List<File>)FILES1, new FileComparator());
		addFilesRecursively(new File(inFolder+"/LC"), FILES2);
		Collections.sort((List<File>)FILES2, new FileComparator());

		pics[0] = FILES0.toArray();
		pics[1] = FILES1.toArray();
		pics[2] = FILES2.toArray();
		
		info.setDone(true);
		animator = new FPSAnimator(this.canvas, fps);
		animator.setRunAsFastAsPossible(true);
		coordsArray = coords;
		canvas.addGLEventListener(this);
		canvas.requestFocus();
	}


	public void run() {
		/*Animator calls display at the constant rate*/
		animator.start();	
	}

	/*Called from FPSAnimator displays the current picture*/
	public void display(GLAutoDrawable glDrawable) {
		if(info.isInit() && !info.isReady()){
			/*Do nothing if it's in the initialization process*/
			final GL gl = glDrawable.getGL();
			gl.glLoadIdentity();
			gl.glMatrixMode(GL.GL_MODELVIEW);
			
			gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
			gl.glClear(GL.GL_COLOR_BUFFER_BIT);
			info.setReady(true);
		}
		else if(info.isReady() || !info.isDone()){
			/*Wait for the CMCAnimation to update*/ 
			info.setReady(true);

			}
		else if((info.getCurFrame() >= info.getEndFrame()-1 && !info.isRewind()) || (info.getCurFrame() <= info.getEndFrame()-1 && info.isRewind())) {
			/*Do nothing because there is no more frames*/
		}
		else{
			
			final GL gl = glDrawable.getGL();
			
			
			//GL Texturing ...fast but can't make it smaller...
			gl.glMatrixMode(GL.GL_PROJECTION);

			gl.glLoadIdentity();
			glu.gluOrtho2D((double) 0,(double) 720,(double) 480,(double) 0);
			gl.glMatrixMode(GL.GL_MODELVIEW);
			
			gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
			gl.glClear(GL.GL_COLOR_BUFFER_BIT);
			
	
			Texture pic = null;
			try {
				pic = TextureIO.newTexture(new File(pics[info.getMode()][info.getCurFrame()].toString()), true);
			} catch (IOException e) {
			}
			
			pic.enable();
			pic.bind();
            TextureCoords coords = pic.getImageTexCoords();
            
            /*Texture the image to the entire panel*/
            double scale = 1;
            gl.glBegin(GL.GL_POLYGON);
            gl.glTexCoord2f(coords.left(), coords.bottom());
            gl.glVertex2d(0, 480*scale);
            gl.glTexCoord2f(coords.right(), coords.bottom());
            gl.glVertex2d(720*scale, 480*scale);
            gl.glTexCoord2f(coords.right(), coords.top());
            gl.glVertex2d(720*scale, 0);
            gl.glTexCoord2f(coords.left(), coords.top());
            gl.glVertex2d(0, 0);
            gl.glEnd();
            gl.glFlush();
            pic.disable();
            pic.dispose();
			info.setReady(true);
		}
	}		


	public void displayChanged(GLAutoDrawable arg0, boolean arg1, boolean arg2) {
	}

	public void init(GLAutoDrawable glDrawable) {
	}

	public void reshape(GLAutoDrawable arg0, int arg1, int arg2, int arg3,int arg4) {
	}

	/*Builds array containing the picture files as File objects.  
	 *We iterate through this array later to find the coordinates of each of the markers in each picture.
	 *Same code as one in MarkerTracking class*/
	private static void addFilesRecursively(File file, Collection<File> all) {
		final File[] children = file.listFiles();
		if (children != null) {
			for (File child : children) {
				if(child.getName().endsWith(".jpg") && !child.getName().startsWith("."))all.add(child);
				addFilesRecursively(child, all);
			}
		}
	}
}
