/*
 * Created on 23.03.2004 19:49:26
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package evalplayer;

import java.util.Vector;

//import java.util.Enumeration;

import mauda.*;
import mauda.evaluation.OpTimeStamp;
import mauda.evaluation.PlayerExercise;
import mauda.evaluation.TimeStampRecorder;
import mauda.operation.*;

import jedas.io.*;

/**
 * The scheduler for playing operations in Evaluation-Player. This
 * scheduler replaces the jedas-scheduler.
 * 
 * @author Markus Krebs
 */
public class OperationPlayerThread extends Thread {

	// DEBUG: Abspielen in der Animation aktivieren/deaktivieren
	private static final boolean playingEnabled = true;
	
	private boolean playAnimation;

	private PlayerExercise exercise;
	
	public static long animStepTime = 25;
	
	private PlayerScheduler playerScheduler;
	long animLength;
	
	/**
	 * Creates an OperationPlayerThread
	 * @param exercise PlayerExercise
	 */
	public OperationPlayerThread(PlayerExercise exercise) {
		super();
		this.exercise = exercise;
		this.playerScheduler = null;
		animLength = 0;
	}

	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		playAnimation = true;
		
		playerScheduler = exercise.getJedasPlayer().getPlayerScheduler();
		OperationRecorder or = exercise.getOperationRecorder();
		TimeStampRecorder tsr = exercise.getTimeStampRecorder();
		animLength = exercise.getJedasPlayer().getJedasAnimation().animLength;
		
		exercise.setActionsAllowed(false);

		int opsToAnimateSize = exercise.opsToAnimate.size();
		int opsToAnimateCounter = 0;

		while (exercise.opsToAnimate.size() > 0) {
			Object obj = exercise.opsToAnimate.firstElement();
			//System.out.println("OperationPlayerThread.run(): Performing: "+obj);
			synchronized (exercise.opsToAnimate) {
				exercise.opsToAnimate.removeElementAt(0);
			}

			opsToAnimateCounter++;
			
			// Fortschritt nur bei mehreren Operation anzeigen
			if(opsToAnimateSize>1) {
				int percent = (int)(((double)opsToAnimateCounter/(double)opsToAnimateSize)*100.0);
				exercise.jedasPanel.setPercentLabel("Progress: "+percent+"% ");
			}

			//exercise.performAction(obj);

			//System.out.println("position = "+position);
			if(obj instanceof SimpleOperation) {
				exercise.performAction(obj);
				//playOpTimeStamp(tsr.getEntry(position));
				//playSeqOpTimeStamp(tsr.getSeqEntry(position));
			} else if(obj instanceof ExerciseUpdateEvent) {
				ExerciseUpdateEvent eue = (ExerciseUpdateEvent)obj;
				// Bei einem Undo-Event auch springen
				if(eue.getID() == ExerciseUpdateEvent.JUMP ||
					eue.getID() == ExerciseUpdateEvent.BACK ||
					eue.getID() == ExerciseUpdateEvent.FORWARD) {
					int position = or.getCurrentOffset()-or.getOffset(0,-1);
					TimeSlider timeSlider = TimeSlider.getInstance();
					if(timeSlider.opProcessing!=null) {
						timeSlider.checkAndSendOperationExecutedMessage();
						// Da START_OF_EXECUTION, stimmt der Sprung-Wert nicht (eins zu hoch)
						if(eue.getID() == ExerciseUpdateEvent.JUMP) eue.setValue(eue.getValue()-1);
					}
					exercise.performAction(obj);
					position = or.getCurrentOffset()-or.getOffset(0,-1);
					OpTimeStamp ots = tsr.getSeqEntry(position);
					long stop = 0;
					if(ots != null) stop = ots.getStop();
					if(playingEnabled) timeSlider.setTime(stop);
				} else {
					exercise.performAction(obj);
				}
			}
		}
		exercise.setActionsAllowed(true);

		// null = Default-Text
		exercise.jedasPanel.setPercentLabel(null);

		// Folgende Ausgabe wird erst gemacht, wenn letzte
		// Operation ausgeführt wurde
		//System.out.println("OperationPlayerThread.run(): end of execution");
		ExerciseUpdateEvent eue = new ExerciseUpdateEvent(exercise, ExerciseUpdateEvent.END_OF_EXECUTION);
		exercise.sendExerciseUpdateMessages(eue);
	}
	public void playSeqOpTimeStamp(OpTimeStamp ots) {
		if(!playingEnabled) return;
		
		if(ots==null) return;

		TimeSlider timeSlider = TimeSlider.getInstance();
		
		Vector timeStamps = ots.getTimeStamps();
		long start = ((Long)timeStamps.firstElement()).longValue();
		long end = ((Long)timeStamps.lastElement()).longValue();
		// Jetzt abspielen
		long actualTime = start;
		
		// An dem Ort mit der Animation starten, an dem man stehen blieb
		if(actualTime<timeSlider.getTime()) {
			actualTime=timeSlider.getTime();
			//System.out.println("OperationPlayerThread.playSeqOpTimeStamp(): start at: "+actualTime);
		}

		//System.out.println("OperationPlayerThread.playSeqOpTimeStamp(): playing "+start+"-"+end+"...");

		while(playAnimation) {
			//actualTime += (long)(Math.pow(((double)animStepTime)/5, 2));
			actualTime += animStepTime;
			if(actualTime>end) {
				timeSlider.setTime(end);
				actualTime = end;
				return;
			} 
			timeSlider.setTime(actualTime);
			try { sleep(10); }
			catch(Exception ex) {
				System.out.println("OperationPlayerThread.run(): sleep() -> Exception");
				return;
			}
			/*
			// Wenn Regler von Hand betätigt wurde ...
			long timeSliderTime = timeSlider.getTime();
			if(timeSliderTime<start || timeSliderTime>end) playAnimation = false;
			else actualTime = timeSliderTime;
			*/
		}					
	}
	
	public void stopAnimation() {
		playAnimation = false;
	}
	public boolean isPlaying() { return playAnimation; }
	
}
