package control;

import gui.GUIFactory;
import gui.GUIText;
import gui.MyTabbedPane;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Timer;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import com.jgoodies.looks.plastic.PlasticXPLookAndFeel;

import visualization.VisualPanel;

import background.CommandManager;
import background.IOManager;
import background.commands.Command;

import language.*;
import language.code.CTypeCode;
import language.visual.English;

public class VizzMain extends JApplet {
	

	private static final long serialVersionUID = 7107506138746273768L;
	
	public static void main(String[] args) {}

	public volatile CommandManager cm;		
	public VisualPanel vizPanel;
	public IOManager io;

	public CodeLanguage l2;
	public VizLanguage l;
	public Translator t;		
	
	public ArrayList<Command> commands;
    public Thread tCU;
    public String s;
	
    public JTextArea inputText = new JTextArea();
    public JTextArea inputArea = new JTextArea();
    public JTextArea outputArea = new JTextArea();
    public JTextArea errorArea = new JTextArea();
    public JEditorPane highlighted = new JEditorPane();
    public JEditorPane currentCommand = new JEditorPane();
    public JButton process;

	public JEditorPane questionArea = new JEditorPane();
	public JTextArea answerArea = new JTextArea();
	public JTextArea correctAnswer = new JTextArea();
	public JPanel questionPanel = new JPanel();
	    
	public JToolBar toolBar = new JToolBar();
	public GUIFactory gui = new GUIFactory();
		
    public JComboBox<String> visualBox;
    public JComboBox<String> codeBox;
    public JComboBox<String> guiBox;
	
	public JPanel inputPanel;
	public JPanel IOPanel;
	public MyTabbedPane tabs;
	public JScrollPane scrollInputText;
	public JScrollPane scrollHighlighted;

	public JPanel settingsPanel;
	public JComboBox<String> modeBox; 
	public Boolean codeExportFullMode = true;
	public JComboBox<String> xSizeBox;
	public JComboBox<String> ySizeBox;

	
	
	public void init() {
		super.init();		  
		setBackground(Color.WHITE);
	
		gui.guiText = new gui.text.English();
	
		vizPanel = new VisualPanel();
	    vizPanel.setBorder(gui.getBorderByName("vizPanel"));
	    gui.componentsWithTextBorder.put(vizPanel, "vizPanel");
	    vizPanel.setBackground(Color.WHITE);	    	  
	    
        io = new IOManager();
		cm = new CommandManager(vizPanel, io, gui.guiText);		
		l2 = new CTypeCode(cm);
		l = new English(cm, l2);
		t = new Translator(l2, l);					
		
		try {  UIManager.setLookAndFeel(new PlasticXPLookAndFeel()); } catch (UnsupportedLookAndFeelException e1) { e1.printStackTrace(); }
	
		setLayout(new BorderLayout());

		makeHighlightInputPanel();     
		makeIOPanel();
		makeToolbar();
		prepareSettingsPanel();
		
		tabs = new MyTabbedPane(inputPanel, scrollInputText, scrollHighlighted, IOPanel, toolBar, vizPanel, settingsPanel, this.gui);
		add(tabs);		
		
		validate();
   	}			
	
	
	
			
	public void makeHighlightInputPanel() {
		
	    inputPanel = gui.getJPanel(new BorderLayout(5, 5), "", new Dimension(350,680));
	    
	    inputText = gui.getTextArea("code", null, true);
	    inputText.setText("Input");
	    scrollInputText = gui.getScrollPane(inputText, new Dimension(260,250), "code");
	    
	    inputText.addCaretListener(new CaretListener() {
	    	public void caretUpdate(CaretEvent e) {
	    		process.setIcon(gui.icons.processedOff);
	    		highlighted.setText(t.highlightHTML(inputText.getText()));
	    	}});
	   		
		highlighted = gui.getEditorPane(null, false);		
	    highlighted.setText("<html><body>Tu sa automaticky zobrazí zvýraznený text programu.</body></html>");
	    scrollHighlighted = gui.getScrollPane(highlighted, new Dimension(500,250), "highCode");
	    
		currentCommand = gui.getEditorPane(null, false);
	    currentCommand.setText("<html><body>Práve vizualizovaný príkaz.</body></html>");
	    JScrollPane scrollCurrentCommand = gui.getScrollPane(currentCommand, new Dimension(250,100),"currentCode");
	    
	    cm.setCurrentCommandText(currentCommand);
	    
	    inputPanel.add(scrollInputText, "North");
	    inputPanel.add(scrollCurrentCommand, "Center");
	    inputPanel.add(scrollHighlighted, "South");	 	   
	}
	

	
	
	public void makeIOPanel() {
		IOPanel = gui.getJPanel(new BorderLayout(5, 5), "", new Dimension(1000,100));
	    
	    /* vstup do programu */
	    
	    inputArea = gui.getTextArea("code", null, true);
	    JScrollPane scrollInputArea = gui.getScrollPane(inputArea, new Dimension(300,100), "input");    	    
	
	    /* vystup z programu */
	    
	    outputArea = gui.getTextArea("code", null, false);
	    JScrollPane scrollOutputArea = gui.getScrollPane(outputArea, new Dimension(300,100), "output");    	    
	    
	    /* error panel */
	    
	    errorArea = gui.getTextArea("code", null, false);
	    errorArea.setForeground(Color.RED);
	    JScrollPane scrollErrorArea = gui.getScrollPane(errorArea, new Dimension(345,100), "error");    	    	    
	    
	    	    
	    IOPanel.add(scrollInputArea, "West");
	    IOPanel.add(scrollOutputArea, "Center");
	    IOPanel.add(scrollErrorArea, "East");
	    IOPanel.add(makeQuestionPanel(), "South");
	    
	    io.setAreas(inputArea, outputArea, errorArea);	    		   
	}
	

	public JPanel makeQuestionPanel() {
	    /* panel odpovedi a otazok */	    
		
		questionPanel = gui.getJPanel(new BorderLayout(15, 4), "", new Dimension(1000,45));
		
	    /* otazka */	
		
		questionArea = gui.getEditorPane(null, false);		
	    JScrollPane scrollQuestionArea = gui.getScrollPane(questionArea, new Dimension(200,35), "");
	    	    	       
	    answerArea.setBackground(Color.WHITE);	    
	    
	    resetQuestions();
	    
	    final JButton answerButton = gui.getButton("answer");    
	    answerButton.addActionListener(new ActionListener() {    
	        public void actionPerformed(ActionEvent ae){
        	    answerArea.setEditable(false);
        	    answerArea.setBorder(BorderFactory.createEmptyBorder());
        	    String s = "";
	        	if (answerArea.getText().trim().equals(correctAnswer.getText().trim())) {
	        	    questionPanel.setBorder(gui.getQuestionBorder(Color.GREEN));
	        	    s = gui.guiText.getAnswerBoolean(true);
	        	} else {
	        	    questionPanel.setBorder(gui.getQuestionBorder(Color.RED));
	        	    s = gui.guiText.getAnswerBoolean(false);
	        	}
	        	s = s+ gui.guiText.getCorrectAnswerText() +correctAnswer.getText();
	        	answerArea.setText(s);
	        	cm.button.setEnabled(true);	        	
	        }
	    });
	    
	    questionPanel.add(scrollQuestionArea, "West");
	    questionPanel.add(answerArea, "Center");
	    questionPanel.add(answerButton, "East");

	    cm.setQuestionThings(questionPanel, questionArea, correctAnswer);	    
	    
	    return questionPanel;
	}
	
	public void resetQuestions() {
	    questionPanel.setBorder(gui.getQuestionBorder(Color.LIGHT_GRAY));
	    questionPanel.setVisible(false);
		answerArea.setEditable(true);
		answerArea.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		answerArea.setText("");
		questionArea.setText("<html><body>"+gui.guiText.getQuestionText()+"question</body></html>");
		
	}
	
	
	
	public void makeToolbar() {
	    toolBar.setBackground(Color.WHITE);
	    toolBar.setFloatable(false);
	    toolBar.setRollover(true);
	    toolBar.setBorder(BorderFactory.createMatteBorder(5, 10, 5, 10, Color.WHITE));	    
	    
	    /* Tlacidlo pre spustenie programu a dalsie kroky */

	   	final JButton start = gui.getButton(gui.icons.next, "start");
	   	start.setEnabled(false);	   	
	   	start.setDisabledIcon(gui.icons.nextDisabled);
	   	start.setDisabledSelectedIcon(gui.icons.nextDisabled);
	   	start.setSelectedIcon(gui.icons.next);
	   	cm.setButton(start);
	   	
	    start.addActionListener(new ActionListener() {
	        public void actionPerformed(ActionEvent e) {    	        	
	        	start.setEnabled(false);
	        	
	    		CommandTimerTask ttask = new CommandTimerTask(cm);
	    		Timer timer = new Timer(true);
	    		
	    		cm.setTTask(timer, ttask);
	        	timer.scheduleAtFixedRate(ttask, 0, 50);	
	        	
	        	if (questionPanel.isVisible()) { questionPanel.setVisible(false); resetQuestions();}
	        }});		    
	      
	    /* Tlacidlo pre zastavenie programu */

	   	final JButton stop = gui.getButton(gui.icons.cancel, "stop");	   		   	
	    stop.addActionListener(new ActionListener() {
	        public void actionPerformed(ActionEvent e) {    	    
	    		cm.timer.cancel();
	    		start.setEnabled(true);	        	
	        }});		    

	    
	    /* Tlacidlo pre spracovanie vstupu */	    
	    
	   	process = gui.getButton(gui.icons.processedOff, "process");
	    process.addActionListener(new ActionListener() {
	        public void actionPerformed(ActionEvent e) {        		
	        	cm.reset();
	        	cm.initializeToDoList(t.translate(inputText.getText()));        	
	        	start.setEnabled(true);
	        	process.setIcon(gui.icons.processedOn);
	        }});
	    

	    /* Tlacidlo pre otvaranie inputu */
	    
	    final JButton openTextButton = gui.getButton(gui.icons.openText, "openText");    
	    openTextButton.addActionListener(new ActionListener() {    
	        public void actionPerformed(ActionEvent ae){
	        	getFile();
	        	highlighted.setText(t.highlightHTML(inputText.getText()));
	        }
	    });

	    /* Tlacidlo pre nahravanie textaku */
	    
	    final JButton saveTextButton = gui.getButton(gui.icons.saveText, "saveCode");    
	    saveTextButton.addActionListener(new ActionListener() {    
	        public void actionPerformed(ActionEvent ae){
	        	exportFile("code.txt");
	        }
	    });

	    
	    /* Tlacidlo pre nahravanie screenshotov */
	    
	    final JButton saveAllButton = gui.getButton(gui.icons.saveAll, "saveAll");    
	    saveAllButton.addActionListener(new ActionListener() {    
	        public void actionPerformed(ActionEvent ae){
	        	export("png", "image.png");
	        }
	    });

	    
	    /* Tlacidlo pre nahravanie obrazkov */
	    
	    final JButton saveButton = gui.getButton(gui.icons.save, "save");    
	    saveButton.addActionListener(new ActionListener() {    
	        public void actionPerformed(ActionEvent ae){        	            
	        	vizPanel.export("png", "image.png");
	        }
	    });
		
		/* Tlacidlo pre mriezku v pozadi */
		
	    final JButton gridButton = gui.getButton(gui.icons.gridOn, "gridOn");
	    gridButton.addActionListener(new ActionListener() {
	        public void actionPerformed(ActionEvent ae){        	                   	
	        	if (vizPanel.showGrid) {
	        		vizPanel.showGrid = false;
	        		gridButton.setIcon(gui.icons.gridOff);
	        		gridButton.setToolTipText(gui.guiText.getButtonDescription("gridOff"));
	        		vizPanel.refresh();
	        	} else {
	        		vizPanel.showGrid = true;
	        		gridButton.setIcon(gui.icons.gridOn);
	        		gridButton.setToolTipText(gui.guiText.getButtonDescription("gridOn"));
	        		vizPanel.refresh();
	        	}        	        	
	        }
	    }); 
	    	    
	    toolBar.add(openTextButton);
	    toolBar.addSeparator();
	    toolBar.add(saveAllButton);
	    toolBar.addSeparator();
	    toolBar.add(saveButton);
	    toolBar.addSeparator();
	    toolBar.add(saveTextButton);
	    toolBar.addSeparator();
	    toolBar.add(gridButton);
	    toolBar.add(Box.createRigidArea(new Dimension(60, 0)));
	    toolBar.add(process);	    
	    toolBar.addSeparator();
	    toolBar.add(start);
	    toolBar.addSeparator();
	    toolBar.add(stop);
	  
	    JPanel restOfToolbar = gui.getJPanel(new BorderLayout(), "", null);
	    
	    toolBar.add(Box.createRigidArea(new Dimension(160, 0)));
	    toolBar.add(restOfToolbar);	    	   
	    
	    /* language bar */;
	    JPanel langPanel = gui.getJPanel(new BorderLayout(10, 0), "", new Dimension(340,50));
	    	    
        visualBox = gui.getComboBox(new Dimension(165,50), "viz");
        visualBox.addItem("Angličtina");
        visualBox.addItem("Slovenčina");
        visualBox.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		setNewLanguages();
        	}});
        visualBox.setSelectedItem(1);
        
        codeBox = gui.getComboBox(new Dimension(165,50), "code");
        codeBox.addItem("C typ");
        codeBox.addItem("Pascal");
        codeBox.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		setNewLanguages();
        	}});
        
        langPanel.add(visualBox, "East");
        langPanel.add(codeBox, "West");
        restOfToolbar.add(langPanel, "East");        	    
	}
	
	public void setNewLanguages() {
		l2 = CodeLanguage.getLangByName(codeBox.getSelectedItem().toString(), cm);
		l = VizLanguage.getLangByName(visualBox.getSelectedItem().toString(), l2, cm);        		
		t = new Translator(l2, l);		        		
		highlighted.setText(t.highlightHTML(inputText.getText()));		
	}
	
	public void setNewGridSize() {
		vizPanel.xBoxSize = Integer.parseInt(xSizeBox.getSelectedItem().toString());
		vizPanel.yBoxSize = Integer.parseInt(ySizeBox.getSelectedItem().toString());
		vizPanel.reset();		
	}
	
	public void prepareSettingsPanel() {
		settingsPanel = gui.getJPanel(new FlowLayout(), BorderFactory.createLineBorder(Color.BLACK),null);
		
        xSizeBox = gui.getComboBox(new Dimension(150,50), "xBox");
        ySizeBox = gui.getComboBox(new Dimension(150,50), "yBox");
        for (int i=1; i<=10; i++) { xSizeBox.addItem(Integer.toString(10*i)); ySizeBox.addItem(Integer.toString(10*i)); }

        xSizeBox.setSelectedIndex(6);
        ySizeBox.setSelectedIndex(6);

        xSizeBox.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		setNewGridSize();
        	}});
        	      
        ySizeBox.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		setNewGridSize();        	
        	}});
        
        
        guiBox = gui.getComboBox(new Dimension(150,50), "guiLang");
        guiBox.addItem("Slovenčina");
        guiBox.addItem("Angličtina");
        guiBox.addActionListener(new ActionListener() {
        	public void actionPerformed(ActionEvent e) {
        		gui.guiText = GUIText.getGUITxtByName(guiBox.getSelectedItem().toString());
        		gui.resetTexts();
        	}});
        
        modeBox = gui.getComboBox(new Dimension(200,50), "mod");        
        modeBox.addItem("Plná funkcionalita");
        modeBox.addItem("Len vizualizácia");	      

        settingsPanel.add(guiBox);
        settingsPanel.add(modeBox);
        settingsPanel.add(xSizeBox);
        settingsPanel.add(ySizeBox);
	}

	public String getSettings() {
		String s="";
		s += "visual:"+Integer.toString(visualBox.getSelectedIndex())+"\r\n";
		s += "code:"+Integer.toString(codeBox.getSelectedIndex())+"\r\n";
		s += "gui:"+Integer.toString(guiBox.getSelectedIndex())+"\r\n";
		s += "mode:"+Integer.toString(modeBox.getSelectedIndex())+"\r\n";
		s += "xBox:"+Integer.toString(xSizeBox.getSelectedIndex())+"\r\n";
		s += "yBox:"+Integer.toString(ySizeBox.getSelectedIndex())+"\r\n";	
		return s;
	}
	
	public void useSettings(String s) {
		String parts[] = s.split("[\\r\\n]+");
		int partNum = 0;
		while (partNum<parts.length) {
			String subparts[] = parts[partNum].split(":");
			if (subparts.length>=2) {
				switch (subparts[0]) {
				case "visual": {visualBox.setSelectedIndex(Integer.parseInt(subparts[1])); this.setNewLanguages(); break;}
				case "code": {codeBox.setSelectedIndex(Integer.parseInt(subparts[1])); this.setNewLanguages(); break;}
				case "gui": {guiBox.setSelectedIndex(Integer.parseInt(subparts[1])); gui.guiText = GUIText.getGUITxtByName(guiBox.getSelectedItem().toString()); gui.resetTexts(); break;}
				case "mode": {modeBox.setSelectedIndex(Integer.parseInt(subparts[1])); if (modeBox.getSelectedIndex() == 1) { tabs.resetTabs(true); } else { tabs.resetTabs(false); } break;}
				case "xBox": {xSizeBox.setSelectedIndex(Integer.parseInt(subparts[1])); this.setNewGridSize(); break;}
				case "yBox": {ySizeBox.setSelectedIndex(Integer.parseInt(subparts[1])); this.setNewGridSize(); break;}
				}
			}
			partNum++;
		}		
	}

	
	public void export(String picType, String defFileName) {
        JFileChooser fileChooser = new JFileChooser();
        File defaultFile = new File(defFileName);             
        fileChooser.setSelectedFile(defaultFile);
                
        File file = new File(defFileName);
        if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
        	file = fileChooser.getSelectedFile();
        }
    	
        Dimension size = this.getSize();    	
        BufferedImage image = (BufferedImage) this.createImage(size.width, size.height);
        Graphics g = image.getGraphics();
        this.paint(g);
        g.dispose();
        try { ImageIO.write(image, picType, file); }
        catch (IOException e) { e.printStackTrace(); }
	}

	public void exportFile(String defFileName) {
		JFileChooser fileChooser = new JFileChooser();
        File defaultFile = new File(defFileName);             
        fileChooser.setSelectedFile(defaultFile);
                
        File file = new File(defFileName);
        if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
        	file = fileChooser.getSelectedFile();
        }
        
		try { 
			PrintWriter out = new PrintWriter(file); 
			out.println(inputText.getText()+"\r\n###\r\n"+inputArea.getText()+"\r\n###\r\n"+getSettings()); 
			out.close(); 
		} catch (FileNotFoundException e) { e.printStackTrace(); }
	}
	
	
	public void getFile() {
		JFileChooser fileChooser = new JFileChooser();
		File file = null;
		if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
	       	file = fileChooser.getSelectedFile();
	    }		
		if (file!=null) {
			try { inputText.read(new FileReader(file), null); } catch (IOException e) {	e.printStackTrace(); }
			
			if (inputText.getText().contains("###")) {
				String text = inputText.getText();
				String parts[] = text.split("###[\\r\\n]+");
				inputText.setText(parts[0]);
				inputArea.setText(parts[1]);
				useSettings(parts[2]);
				
			}
		}
	}

	public void stop() { }
	
}
	