package surface;

import hu.swankey.ammo.common.script.AmmoScriptException;
import hu.swankey.ammo.common.yggdrasil.basics.YObject;
import hu.swankey.ammo.common.yggdrasil.ext.Command;
import hu.swankey.ammo.common.yggdrasil.ext.Universe;
import hu.swankey.ammo.common.yggdrasil.ext.World;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingWorker;

import background.Controller;
import client_engine.Commander;
import client_engine.IClientControllerListener;

public class CommandBar implements IClientControllerListener{
	

	private static final long serialVersionUID = 1L;	
    private static final int OPTIONS_BUTTON_WIDTH = 50;
    private static final String BUTTON_OPTIONS_OPEN = ">>";
    private static final String BUTTON_OPTIONS_CLOSE = "<<";
    private static final int TEXT_HEIGHT = 20;
    private static final int BUTTON_HEIGHT = 24;
    private static final String TITLE_ADD_COMMAND = "Add new command";
    private static final String NEW_COMMAND_NAME = "New Command";
    private static final String NO_UNIVERSE_SELECTED = "No universe selected";
    
//    private static final Color COLOR_SYNTAX = Color.RED;
//    private static final Color COLOR_BAD_COMMAND = Color.YELLOW;
    private static final String MSG_SYNTAX = " (Syntax error!)";
    private static final String MSG_EXCEPTION = " (Exception!)";

    private final Controller controller;
    
    private final HashMap<Command, CommandPanel> commandPanels = new HashMap<Command, CommandPanel>();
    private final HashMap<Command, CommandPanel> hiddenCommandPanels = new HashMap<Command, CommandPanel>();

    private final JPanel playPanel = new JPanel();
    private final JPanel editorPanel = new JPanel();
    
    private final JButton button_addNewCommand = new JButton(TITLE_ADD_COMMAND);

    private CommandBar(final Controller controller){
    	this.controller = controller;	
    	regenerate(controller.getUniverse());
    	
    	playPanel.setLayout(new BoxLayout(playPanel, BoxLayout.Y_AXIS));
    	editorPanel.setLayout(new BoxLayout(editorPanel, BoxLayout.Y_AXIS));
    	
        // "Add Command" Button:
        button_addNewCommand.setAlignmentX(Component.CENTER_ALIGNMENT);
        button_addNewCommand.setAlignmentY(Component.CENTER_ALIGNMENT);
        button_addNewCommand.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                controller.getUniverse().addCommand( Command.yclass().create(NEW_COMMAND_NAME) );
            }
        });    	
    }

	public static CommandBar createCommandBar(final Controller controller) {
	    final CommandBar commandBar = new CommandBar(controller);        
        controller.addListener(commandBar);        	    
	    return commandBar;
	};
	
    public JPanel getPlayPanel(){
    	return playPanel;
    }
    
    public JPanel getEditorPanel(){
    	return playPanel;
    }	    
	
//	private void addCommand(Command command){
//        CommandPanel commandPanel = CommandPanel.createCommandPanel( command, controller );
//        add(commandPanel, getComponentCount()-1);
//        
//        commands.put(command.getName(), command);
//        commandPanels.put(command, commandPanel);
//	}
	
	private static class CommandPanel extends JPanel {
		
		private static final long serialVersionUID = 1L;
		private final Command command;
		private final JButton commandButton;
		private final Commander commander;
		private final Controller controller;
		
		private CommandPanel(Controller controller, Command command){
			this.controller = controller;
			this.command = command;
			this.commander = controller.getCommander();
			commandButton = new JButton(command.getTitle());
		}
		
		public static CommandPanel createCommandPanel(final Command command, final Controller controller) { 	

	        final CommandPanel cp = new CommandPanel(controller, command);
	        final JPanel visiblePanel = new JPanel();
	        final JPanel optionsPanel = new JPanel();        
	        cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
	        cp.setFont( Font.decode(Font.MONOSPACED).deriveFont(Font.BOLD, 11) ); 
	        cp.add(visiblePanel);
	        cp.add(optionsPanel);
	        
	        // -- Options Panel ---
	        final JTextField commandText = new JTextField(command.getTitle());
	        final JTextField commandAliasText = new JTextField(command.getCommand(), 1);
	        optionsPanel.setFont(null);
	        optionsPanel.setLayout(new BoxLayout(optionsPanel, BoxLayout.Y_AXIS));
	        optionsPanel.setVisible(false);
	        optionsPanel.add(commandText);
	        optionsPanel.add(commandAliasText);        
	        

	        // -- Visible Panel --
	        final JButton optionsButton = new JButton(BUTTON_OPTIONS_OPEN);
	        visiblePanel.setLayout(new BoxLayout(visiblePanel, BoxLayout.X_AXIS));        
	        visiblePanel.setFont( null );
	        visiblePanel.add(cp.commandButton);
	        visiblePanel.add(optionsButton);
	        
	        // Command Button:
	        cp.commandButton.setFont( Font.decode(Font.MONOSPACED).deriveFont(Font.BOLD, 11) );	        
	        cp.commandButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, BUTTON_HEIGHT));
	        //cp.commandButton.setEnabled( controller.getCommander().isExecutable(command) );
	        cp.actualize();
	        cp.commandButton.addActionListener(new ActionListener() {
	            @Override
	            public void actionPerformed(ActionEvent evt) {
	            	try {
	            		
	            		SwingWorker swingworker = new SwingWorker<Void, Void>() {
	            		    @Override
	            		    public Void doInBackground() {
	            		        
	            		        try {
	            		            controller.getCommander().execute(command.getCommand());
	            		        } catch (Exception e) {
	            		            
	            		        }
	            		        
	            		    	return null;
	            		    }
	            		};
	            		
	            		swingworker.execute();
	            		
	            	} catch (AmmoScriptException e) {
	            		controller.printError(e);
	            	} catch (Exception e) {
	            		controller.reportError(e);
	            	}
	            }
	        });
	        
	        // Options Button:
	        optionsButton.setFont(null);
	        optionsButton.setMinimumSize(new Dimension(OPTIONS_BUTTON_WIDTH, BUTTON_HEIGHT));
	        optionsButton.setMaximumSize(new Dimension(OPTIONS_BUTTON_WIDTH, BUTTON_HEIGHT));        
	        optionsButton.addActionListener(new ActionListener() {

	            @Override
	            public void actionPerformed(ActionEvent evt) {
	                optionsPanel.setVisible(!optionsPanel.isVisible());
	                
	                if (!optionsPanel.isVisible()) {
	                	command.setCommand(commandAliasText.getText());
	                	command.setTitle(commandText.getText());
	                	
	                	cp.actualize();
	                	//cp.commandButton.setText(commandText.getText());
	                	//optionsButton.setText(BUTTON_OPTIONS_OPEN);
	                	//cp.commandButton.setEnabled( controller.getCommander().isValid(command) );
	                	
	                } else                 
	                	optionsButton.setText(BUTTON_OPTIONS_CLOSE);
	            }
	        });
	        
	        // Textfields:
	        commandText.setFont(null);
	        commandText.setMaximumSize(new Dimension(Integer.MAX_VALUE, TEXT_HEIGHT));
	        commandAliasText.setFont(null);
	        commandAliasText.setMaximumSize(new Dimension(Integer.MAX_VALUE, TEXT_HEIGHT));
	        
	        // Hotkey:
//	        JTextField jtext_hotkey = new JTextField();
//	        JComboBox jcombo_primary = new JComboBox();	        
//	        jtext_hotkey.setText("CTRL + A");
//	        jcombo_primary.setEditable(false);
//	        jcombo_primary.add( new JLabel("Character")  );
	        
//	        cp.add(jcombo_primary);
//	        cp.add(jtext_hotkey);
	        
	        
	        return cp;
	    }
		
		
		private void actualize(){
			
			try {
				int commandStatus = commander.getCommandStatus(command);
			
			
				switch (commandStatus) {
				case Commander.STATUS_OK:
					commandButton.setEnabled(true);
					commandButton.setForeground(null);
					commandButton.setText(command.getTitle());
					break;
				case Commander.STATUS_SYNTAX_ERROR:
					commandButton.setEnabled(false);
					commandButton.setText(command.getTitle() + MSG_SYNTAX);
					commander.getCommandStatus(command);
					break;
				case Commander.STATUS_UNEXPECTED_PRIMARY_CLASS:
				case Commander.STATUS_UNEXPECTED_SECONDARY_CLASS:
				case Commander.STATUS_PRIMARY_CLASS_NULL:
				case Commander.STATUS_SECONDARY_CLASS_NULL:
					commandButton.setEnabled(false);
					break;
				default:
					String msg;
					switch (commandStatus) {
					case Commander.STATUS_PRIMARY_CLASS_NOT_FOUND:
						msg = "Primary class not found.";
						break;
					case Commander.STATUS_SECONDARY_CLASS_NOT_FOUND:
						msg = "Secondary class not found.";
						break;
					default:
						msg = "Unknown error";
					}
					commandButton.setEnabled(false);
					//commandButton.setForeground(null);
					commandButton.setText(command.getTitle());
					controller.printToConsole("Invalid command(" + command.getTitle() + "): " + msg );
					break;
				}
				
			} catch (AmmoScriptException ex){
				commandButton.setEnabled(false);
				commandButton.setText(command.getTitle() + MSG_EXCEPTION);
				controller.printToConsole("Exception in command(" + command.getTitle() + "): " + ex.getMessage());
			} catch (Exception ex) {
				commandButton.setEnabled(false);
				commandButton.setText(command.getTitle() + MSG_EXCEPTION);
				controller.reportError(ex);
			}
			
//			if (command.getTitle().equals("Fire!!"))
//				//try {
//					commander.execute(command.getCommand());
//				} catch (Exception e) {
//					String status = (commandStatus == Commander.COMMAND_STATUS_INVALID ? "syntactically wrong" : "invalid");
//					controller.printToConsole(command.getName() + " is " + status + ": " + e.getMessage());
//					throw new RuntimeException(e);
//				}
				
			
			
			
//			if (valid) {
//				
//				commandButton.setForeground(null);
//				commandButton.setText(command.getTitle());
//			} else {
//				commandButton.setEnabled(true);
//				commandButton.setForeground(COLOR_PROBLEM);
//				commandButton.setText(command.getTitle() + MSG_SYNTAX);
//			}
			
			
				
			
			// VALID & RUNNABLE -> normál			
			// VALID & !RUNNABLE -> szürke
			// !VALID -> piros

			
			
			
			
			
//			commandButton.setText(command.getTitle());
			
			
			
//			try {			
//							
//				
//				//commandButton.setForeground(null);
//			} catch (AmmoScriptSyntaxException e){
//				//commandButton.setEnabled(true);
//				
//				
//				controller.printError(e);
//				//System.out.println("Ilyen is vansdf");
//			} //catch (AmmoScriptRuntimeException e){
////				//controller.printToConsole("");
////				System.out.println("Ilyen is van: ");
////				e.printStackTrace();
////				
////			}
		}
		
	}


	@Override
	public void primaryElementChanged(YObject newElement) {
		actualizeButtons();
	}

	@Override
	public void secondaryElementChanged(YObject newElement) {
		actualizeButtons();
	}

	@Override
	public void selectedWorldChanged(World world) {
	}

	@Override
	public void cursorChanged(Dimension cursor) {
		actualizeButtons();
	}

	@Override
	public void selectedUniverseChanged(Universe universe) {
		regenerate(universe);
	}	
	
	private void regenerate(Universe universe){
		
		playPanel.removeAll();
		editorPanel.removeAll();
		commandPanels.clear();
		
		if (universe != null){
			for(YObject commandE: universe.getCommandContainer().getElements()){
				CommandPanel commandPanel = CommandPanel.createCommandPanel((Command)commandE, controller);
				commandPanels.put((Command)commandE, commandPanel);
				playPanel.add(commandPanel.commandButton);
				editorPanel.add(commandPanel);
			}
			editorPanel.add(button_addNewCommand);
		}
		else {
			JLabel label = new JLabel(NO_UNIVERSE_SELECTED);
			label.setAlignmentX(Component.CENTER_ALIGNMENT);
	        label.setAlignmentY(Component.CENTER_ALIGNMENT);
			playPanel.add( label );
			editorPanel.add( label );
		}
	}
	
	public JButton addHiddenCommand(String title, String code, String primary, String secondary){
		Command command = Command.yclass().create(title, code, primary, secondary);
		CommandPanel commandPanel = CommandPanel.createCommandPanel(command, controller);
		hiddenCommandPanels.put(command, commandPanel);
		
		return commandPanel.commandButton;
	}
	
	private void actualizeButtons(){
		for(CommandPanel commandPanel: commandPanels.values())
			commandPanel.actualize();
		
		for(CommandPanel commandPanel: hiddenCommandPanels.values())
			commandPanel.actualize();		
	}

}
