package background;

import gui.GUIText;

import java.util.ArrayList;
import java.util.Stack;
import java.util.Timer;

import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JPanel;
import javax.swing.JTextArea;

import language.Translator;

import control.CommandTimerTask;

import visualization.VisualPanel;
import background.commands.*;

public class CommandManager {
	public VariableManager variableManager;
	public ExpressionInterpreter expressionInterpreter;	
	public VisualPanel visualPanel;
	public IOManager ioManager;
	public ErrorHandler errorManager;
	public volatile Stack<Command> commandsToDo;
	public CommandTimerTask ttask;
	public Timer timer;
	public JButton button;
	
	public JPanel questionPanel;
	public JEditorPane questionArea;	
	public JTextArea correctAnswer;	
	
	public JEditorPane currentText;	
	public Boolean shouldResetActives;

	
	public CommandManager(VisualPanel vp, IOManager io, GUIText guiT) {
		visualPanel = vp;		
		ioManager = io;
		errorManager = new ErrorHandler(ioManager, this, guiT);
		variableManager = new VariableManager(errorManager);
		expressionInterpreter = new ExpressionInterpreter(variableManager);
		commandsToDo = new Stack<Command>();
	}
		
	
	public void reset() {
		commandsToDo = new Stack<Command>();
		variableManager.reset();
		expressionInterpreter.initializeEI();
		ioManager.reset();
		visualPanel.reset();
		visualPanel.refresh();
		shouldResetActives = false;
	}

	
	public void setTTask(Timer ti, CommandTimerTask t) {
		timer = ti;
		ttask = t;
	}
	
	public void setButton(JButton b) {
		button = b;
	}
	
	public void setCurrentCommandText(JEditorPane pane) {
		currentText = pane;
	}
	
	public void setQuestionThings(JPanel panel, JEditorPane question, JTextArea answer) {
		questionPanel = panel;
		questionArea = question;
		correctAnswer = answer;
	}
	
	public void initializeToDoList(ArrayList<Command> commands) {
		ArrayList<Command> reversedList = new ArrayList<Command>();		
		for (int i=commands.size()-1; i>=0; i--) {  reversedList.add(commands.get(i)); }		
		for (Command com: reversedList) { appendCommand(com); }			
	}	
	
	public void writeActions() {
		variableManager.writeVisibleVariables();
		variableManager.writeAllArrays();
		variableManager.writeAllTables();
		visualPanel.refresh();		
		try {Thread.sleep(getVisualisationSpeed()); } catch (InterruptedException e) {e.printStackTrace();} 
		if (!commandsToDo.isEmpty() && "Image Question Pause".contains(commandsToDo.peek().getType())) shouldResetActives = false; 
	}
	
	public int getVisualisationSpeed() {
		return 800;
	}

	
	public void appendCommand(Command c) {
		commandsToDo.push(c);		
	}
	
	public String getCodeLineText(String s) {
		return "<html><head><style>body {color: black; font-family: 'Lucida Console', Monaco, sans; font-size: 10px;}</style></head><body>"+s+"</body></html>";
	}
	
	public void applyNextCommand() {		
		if (!commandsToDo.isEmpty()) {
			if (shouldResetActives) variableManager.resetActives();			
			Command com = commandsToDo.pop();			
			if (com.vizualize) currentText.setText(getCodeLineText(Translator.processForHTML(com.codeLine)));
			com.applyCommand();				
			if (com.vizualize) { shouldResetActives = true; writeActions(); }				
			else { shouldResetActives = false; }
		} else {
			finishCurrentVisualisation();
		}
	}
		
	public void finishCurrentVisualisation() {
		System.out.println("done"); 
		variableManager.resetActives();
		writeActions();
		if (timer!=null) timer.cancel(); 			 		
	}
	
		
	public Command getCommand(String type, Boolean vis) {		
		switch (type) {
			case "Variable": return new VariableCommand(vis, this);
			case "For": return new Cycle("For", vis, this);
			case "Repeat": return new Cycle("Repeat",vis, this);
			case "While": return new Cycle("While", vis, this);
			case "If": return new IfSegment(vis, this);
			case "Operation": return new Operation(vis, this);
			case "Breakpoint": return new Breakpoint(true, this);
			case "Read": return new Read(true, this);
			case "Write": return new Write(true, this);
			case "Image": return new SaveImage(true, this);
			case "Question": return new Question(true, this);
			case "Global": return new GlobalSettings(true, this);
			default: return null;
		}
	}
	
	
}
