/*
 * Created on 18.12.2003 13:25:37
 *
 * Multimediale Algorithmen und Datenstrukturen Assessments
 */
package mauda;

import mauda.operation.*;
import mauda.plugin.JedasMainCompObj;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import jedas.*;
import jedas.utils.*;
/**
 * The panel for displaying jedas and additionally allows
 * control for a quick-animation. Furthermore it shows the
 * progress-status in percent of the completion of the
 * currently to-execute operations.
 * 
 * @author Markus Krebs
 */
public class JedasPanel extends JPanel implements JedasApplication, ActionListener {
	
	protected static Scheduler scheduler;
	protected static ControlPanel controlPanel;
	protected static CompPanel compPanel;
	
	protected static ControlPanel memControlPanel;	// Remembers the ControlPanel (kann nur einmal instanziiert werden!)
	
	protected static ZoomSetPanel zoomSetPanel;
	
	protected static JPanel messagePanel;
	
	protected Exercise exercise;

	protected JLabel typeLabel;
	protected JLabel difficultyLabel;
	protected JLabel modeLabel;
	
	protected JCheckBox quickButton;
	protected JCheckBox adjustZoomButton;
	protected JLabel percentLabel;
	
	protected static final String percentLabelDefaultText = " ";	// Auf Leerzeichen setzen, damit das Layout schneller geht
	
	// Gibt an ob beim nächsten Ausführen das Progress-Bar-Fenster
	// angezeigt werden soll. Wird dann wieder sofort auf false
	// zurückgesetzt.
	// -> Wird beim Replay gesetzt
	protected boolean nextNoProgressBar;

	/**
	 * Creates a new JedasPanel
	 */
	public JedasPanel() {
		super();
		scheduler = new Scheduler();
		controlPanel = new ControlPanel(this, scheduler);
		memControlPanel = controlPanel;

		compPanel = new CompPanel();
		//compPanel.setGrid(true);

		// GraphicsQuality-Einstellung
		// quality = "high" | "low" (default: high)
		//compPanel.setGraphicsQuality(String quality, boolean autoAdjust)
		//compPanel.setGraphicsQuality("high", false);
				
		setLayout(new BorderLayout());

		JPanel aboveJedas = new JPanel();
		aboveJedas.setLayout(new BorderLayout());
		
		// LEFT PANEL
		
		JPanel leftPanel = new JPanel();
		leftPanel.setLayout(new BorderLayout());
		typeLabel = new JLabel("?");
		typeLabel.setFont(new Font("SansSerif", Font.PLAIN, 20));
		leftPanel.add(typeLabel, BorderLayout.CENTER);
		
		JPanel labelPanel = new JPanel();
		labelPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0,0 ));
		Font font = new Font("SansSerif", Font.PLAIN, 10);
		modeLabel = new JLabel("Mode: ");
		modeLabel.setFont(font);
		labelPanel.add(modeLabel);
		
		JLabel sepLabel = new JLabel("  /  ");
		sepLabel.setFont(font);
		labelPanel.add(sepLabel);
		
		difficultyLabel = new JLabel("Difficulty: ");
		difficultyLabel.setFont(font);
		labelPanel.add(difficultyLabel);
		
		leftPanel.add(labelPanel, BorderLayout.SOUTH);
		
		aboveJedas.add(leftPanel, BorderLayout.WEST);
		
		// RIGHT PANEL
		
		JPanel rightPanel = new JPanel();
		rightPanel.setLayout(new BorderLayout());
		
		quickButton = new JCheckBox("Quick-Anim");
		quickButton.setSelected(false);
		quickButton.addActionListener(this);
		rightPanel.add(quickButton, BorderLayout.CENTER);
		
		adjustZoomButton = new JCheckBox("Adjust-Zoom");
		adjustZoomButton.setSelected(false);
		adjustZoomButton.addActionListener(this);
		rightPanel.add(adjustZoomButton, BorderLayout.WEST);
		
		percentLabel = new JLabel(percentLabelDefaultText);
		percentLabel.setFont(font);	// font von oben übernommen (Difficulty/Mode)
		percentLabel.setHorizontalAlignment(SwingConstants.RIGHT);
		rightPanel.add(percentLabel, BorderLayout.SOUTH);
		
		aboveJedas.add(rightPanel, BorderLayout.EAST);
		
		// GESAMT
		
		add(aboveJedas, BorderLayout.NORTH);
		
		zoomSetPanel = new ZoomSetPanel(compPanel);
		add(zoomSetPanel, BorderLayout.CENTER);

		add(controlPanel, BorderLayout.SOUTH);
		
		messagePanel = null;
				
	}
	/**
	 * Sets that the next time the jedas-animation will be started,
	 * that there's no progress-bar should displayed.
	 */
	public void nextNoProgressBar() { nextNoProgressBar = true; }
	
	/**
	 * Gets the Jedas-Scheduler
	 * @return Jedas-Scheduler
	 */
	public Scheduler getScheduler() {
		return scheduler;
	}
	/**
	 * Gets the Jedas-ControlPanel
	 * @return Jedas-ControlPanel
	 */
	public ControlPanel getControlPanel() {
		return controlPanel;
	}
	/**
	 * Gets the Jedas-CompPanel
	 * @return Jedas-CompPanel
	 */
	public CompPanel getCompPanel() {
		return compPanel;
	}
	public void setNormalCompPanel(CompPanel co) {
		// Sollte der normale CompPanel noch aktiv sein, dann nichts tun.
		if(controlPanel==memControlPanel) return;
		//System.out.println("Need to set normal compPanel!");
		if(zoomSetPanel!=null) remove(zoomSetPanel);
		else if(compPanel!=null) remove(compPanel.getDrawPanel());
		if(controlPanel!=null) remove(controlPanel);
		if(messagePanel!=null) remove(messagePanel);
		zoomSetPanel = new ZoomSetPanel(co);
		compPanel = co;
		controlPanel = memControlPanel;
		messagePanel = null;
		add(zoomSetPanel, BorderLayout.CENTER);
		add(controlPanel, BorderLayout.SOUTH);
		adjustZoomButton.setEnabled(true);
		quickButton.setEnabled(false);
		invalidate();
		revalidate();		
		/*
		SwingUtilities.invokeLater(new Runnable() { 
				public void run() {
					add(zoomSetPanel, BorderLayout.CENTER);
					add(controlPanel, BorderLayout.SOUTH);
					adjustZoomButton.setEnabled(false);
					quickButton.setEnabled(false);
					invalidate();
					revalidate();
				}
			});
			*/
	}
	/**
	 * Sets the JedasPlayer-CompPanel.
	 * @param co CompPanel from Jedas-Animation
	 */
	public void setPlayerCompPanel(CompPanel co) {
		if(zoomSetPanel!=null) remove(zoomSetPanel);
		else if(compPanel!=null) remove(compPanel.getDrawPanel());
		if(controlPanel!=null) remove(controlPanel);
		if(messagePanel!=null) remove(messagePanel);
		zoomSetPanel = null;
		compPanel = co;
		controlPanel = null;
		messagePanel = null;
		add(compPanel.getDrawPanel(), BorderLayout.CENTER);
		//remove(controlPanel);
		adjustZoomButton.setEnabled(false);
		quickButton.setEnabled(false);
		invalidate();
		revalidate();
	}
	public void setMessage(String msg) {
		if(zoomSetPanel!=null) remove(zoomSetPanel);
		else if(compPanel!=null) remove(compPanel.getDrawPanel());
		if(controlPanel!=null) remove(controlPanel);
		if(messagePanel!=null) remove(messagePanel);
		zoomSetPanel = null;
		compPanel = null;
		controlPanel = null;
		messagePanel = new JPanel();
		messagePanel.setLayout(new BorderLayout());
		JLabel label = new JLabel(msg);
		messagePanel.setBackground(new Color(255,255,255));
		label.setFont(new Font("SansSerif", Font.ITALIC, 20));
		label.setHorizontalAlignment(SwingConstants.CENTER);
		messagePanel.add(label, BorderLayout.CENTER);
		add(messagePanel, BorderLayout.CENTER);
		adjustZoomButton.setEnabled(false);
		quickButton.setEnabled(false);
		invalidate();
		revalidate();		
	}
	/**
	 * Sets the exercise from where the JedasPanel gets his
	 * information for operations to execute
	 * @param ex Exercise
	 */
	public void setExercise(Exercise ex) {
		exercise = ex;
		typeLabel.setText(ex.getMetaData().getType());
	}
	
	/**
	 * Sets the text of the difficulty-label
	 * @param s Difficulty-string
	 */
	public void setDifficultyLabel(String s) {
		difficultyLabel.setText(s);
	}
	/**
	 * Sets the text of the mode-label
	 * @param s Mode-string
	 */
	public void setModeLabel(String s) {
		modeLabel.setText(s);
	}
	/**
	 * Sets the text of the percent-label
	 * @param s Percent-String
	 */
	public void setPercentLabel(String s) {
		if(s==null) s = percentLabelDefaultText;
		percentLabel.setText(s);
	}
	
	/* (non-Javadoc)
	 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
	 */
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == quickButton) {
			Exercise.setQuickAnim(quickButton.isSelected());
		} else if(e.getSource() == adjustZoomButton) {
			boolean enabled = adjustZoomButton.isSelected(); 
			AutomaticZoomThread.setEnabled(enabled);
			if(enabled) {
				AutomaticZoomThread.forceZoom(exercise);
				Jedas.updateDisplay();
			}
		}
	}
	/* (non-Javadoc)
	 * @see jedas.JedasApplication#initJedas()
	 */
	public void initJedas() {
		Jedas.updateDisplay();
	}

	/**
	 * This methode gets the animation-queue from the
	 * <code>Exercise</code> and executes them on the
	 * current data-structure.
	 * @see java.lang.Runnable#run()
	 */
	public void run() { // this method is invoked by the ControlUnit!
		
		exercise.setActionsAllowed(false);

		int opsToAnimateSize = exercise.opsToAnimate.size();
		int opsToAnimateCounter = 0;
		
		// Erst ab einer bestimmten Größe den Fortschritt
		// anzeigen
		if(opsToAnimateSize>4&&!nextNoProgressBar) {
			JedasPanelProgress.maxValue = opsToAnimateSize;
			new JedasPanelProgress();
		}
		// Damit beim nächsten Mal der ProgressBar auf jeden Fall
		// wieder angezeigt wird
		nextNoProgressBar = false;		
		
		// Da Routine nicht nur über play aufgerufen wird,
		// nachfragen, ob das der Fall war. Der folgende
		// boolean wird nur auf TRUE gesetzt, wenn die Queue
		// ein SimpleOperation-Objekt enthält
		//boolean dsChanged = false;
		
		AutomaticZoomThread automaticZoomThread = new AutomaticZoomThread();
		automaticZoomThread.startZooming(exercise);
		
		while (exercise.opsToAnimate.size() > 0) {
			
			Object obj = exercise.opsToAnimate.firstElement();
			//System.out.println("JedasPanel.run(): Performing: "+obj);
			synchronized (exercise.opsToAnimate) {
				exercise.opsToAnimate.removeElementAt(0);
			}

			opsToAnimateCounter++;
			JedasPanelProgress.actValue = opsToAnimateCounter;
				
			if(obj instanceof SimpleOperation) {
				if(obj instanceof SubOperation) {
					// Ausführung von SubOperationen auf nicht-Templates verhindern
					OperationRecorder or = exercise.getOperationRecorder();
					int copnr = or.getCurrentOperationNr();
					//javax.swing.JOptionPane.showMessageDialog(MAUDA.getApplicationMainFrame(), copnr+"");
					Operation op = or.getOperation(copnr);
					if(op==null||op.isExecuted()) {
						exercise.commit("Error", "Execution of SubOperation on none template!");
						continue;
					}
				}
				// Event erzeugen, das kurz vor Ausführung versendet
				// wird (wird für TimeStampRecorder benötigt)
				ExerciseUpdateEvent eue = new ExerciseUpdateEvent(exercise, ExerciseUpdateEvent.START_OF_EXECUTION);
				exercise.sendExerciseUpdateMessages(eue);

				SimpleOperation op = (SimpleOperation)obj;
				op.execute(exercise.getDSObject());
				//dsChanged = true;
				
				//System.out.println("JedasPanel.run(): "+obj+" performed.");

				exercise.operationExecuted(op);

				// Fortschritt nur bei mehreren Operation anzeigen
				if(opsToAnimateSize>1) {
					int percent = (int)(((double)opsToAnimateCounter/(double)opsToAnimateSize)*100.0);
					percentLabel.setText("Progress: "+percent+"% ");
				}
				// Nach jeder Operation auf jeden Fall ein update machen
				AutomaticZoomThread.forceZoom(exercise);
				
			} else if(obj instanceof ExerciseUpdateEvent) {
				ExerciseUpdateEvent event = (ExerciseUpdateEvent)obj;
				exercise.sendExerciseUpdateMessages(event);
				if(event.getID() == ExerciseUpdateEvent.DSOBJECT_HIDE) {
					quickButton.setSelected(true);
					quickButton.setEnabled(false);
					Exercise.setQuickAnim(true);
					((JedasMainCompObj)exercise.getDSObject()).getMainCompObj().hide();
				} else if(event.getID() == ExerciseUpdateEvent.DSOBJECT_SHOW) {
					quickButton.setSelected(false);
					quickButton.setEnabled(true);
					Exercise.setQuickAnim(false);					
					((JedasMainCompObj)exercise.getDSObject()).getMainCompObj().show();
					Jedas.updateDisplay();
				}
			}
			// Adjust Zoom in respect to the Items in CompObj
			//if(adjustZoomButton.isSelected()) adjustZoom();
			
			//Jedas.updateDisplay();	// hier nicht notwendig
		}
		
		//if(dsChanged)
			scheduler.start();
			
		// JedasPanelProgress-Fenster schließen
		JedasPanelProgress.close();
		
		percentLabel.setText(percentLabelDefaultText);
		exercise.setActionsAllowed(true);
		
		// Folgende Ausgabe wird erst gemacht, wenn letzte
		// Operation ausgeführt wurde
		//System.out.println("JedasPanel.run(): end of execution");
		ExerciseUpdateEvent eue = new ExerciseUpdateEvent(exercise, ExerciseUpdateEvent.END_OF_EXECUTION);
		exercise.sendExerciseUpdateMessages(eue);
		
		automaticZoomThread.stopZooming();
		
	}

	/**
	 * Gets information of the animation
	 * @return information-string
	 */
	public static String[] getAnimationInformation() {
		String[] infos = { "Author: Markus Krebs", "Date: 11 Nov 2003" };
		return infos;
	}

}
