package lu.tudor.santec.gecamed.formeditor.gui.controller;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

import javax.swing.AbstractAction;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;

import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialog;
import lu.tudor.santec.gecamed.core.gui.widgets.GECAMedBaseDialogImpl;
import lu.tudor.santec.gecamed.formeditor.gui.component.ScriptLink;
import lu.tudor.santec.gecamed.formeditor.gui.model.ScriptEditorModel;
import lu.tudor.santec.gecamed.formeditor.gui.view.ScriptEditorView;
import lu.tudor.santec.i18n.Translatrix;

public class ScriptEditorController implements ActionListener, 
												CaretListener, 
												WindowListener {
	
	/**
	 * @author Jens Ferring
	 * 
	 * This Controller listens to the formula editor. It saves and resets (load last saved settings) the formula
	 * or closes the editor. It is only an actionListener, because all actions are performed by buttons.
	 * In addition it is an MouseAdapter where the component-keys of the form editor are registered, to make them 
	 * draggable. That enables the possibility to drag the components into the editor panel, so the programmer doesn't 
	 * have to write the keys.
	 */
	
	// the action
	public static final String SAVE_BUTTON 				= "save";
	public static final String SAVE_ALL_BUTTON 			= "save_all";
	public static final String RESET_BUTTON 			= "reset";
//	public static final String RESET_ALL_BUTTON 		= "reset_all";
//	public static final String CLOSE_BUTTON 			= "close";
	public static final String UNDO_BUTTON 				= "undo";
	public static final String DO_BUTTON 				= "redo";
	public static final String SEARCH_BUTTON 			= "search";
	public static final String REPLACE_BUTTON 			= "replace";
	public static final String REPLACE_ALL_BUTTON 		= "replace_all";	
	public static final String ADD_NEW_FUNCTION_BUTTON 	= "add_func";
	public static final String REMOVE_FUNCTION_BUTTON 	= "del_func";
	public static final String RENAME_FUNCTION_BUTTON 	= "ren_func";
//	public static final String SELECT_COMPONENT 		= "sel_comp";
	public static final String EXPANDED_MODUS 			= "exp_mod";
	
	private ScriptEditorModel model;
	private ScriptEditorView view;
	
	public ScriptEditorController (ScriptEditorModel model) {
		this.model = model;
		view = model.getView();
	}
	
	/**
	 * Depending on the actionCommand of the pressed button, this method will execute a specific task.
	 */
	public void actionPerformed(ActionEvent e) {
		int selection = view.getSelected();
		boolean setSelection = true;
		if (e.getSource() instanceof ScriptLink) {
			// a script link was clicked
			model.select((ScriptLink)e.getSource());
		} else if (e.getActionCommand().equals(SAVE_BUTTON)) {
			// save the formula of the currently selected tab in the currently selected component
			model.saveSelectedScript();
			if (model.isSaved()) {
				view.enableAllButtons(false);
			}
		} else if (e.getActionCommand().equals(SAVE_ALL_BUTTON)) {
			// save the formula of all tabs in the currently selected component
			model.saveAllScripts();
			view.enableAllButtons(false);
		} else if (e.getActionCommand().equals(RESET_BUTTON)) {
			// reload the last saved formula of the currently selected component for the currently selected tab
			model.resetSelectedScript();
			if (model.isSaved()) {
				view.enableAllButtons(false);
			}
		} else if (e.getActionCommand().equals(SEARCH_BUTTON)) {
			// searches the TextArea for the string entered in the search field
			view.search();
			setSelection = false;
		} else if (e.getActionCommand().equals(REPLACE_BUTTON)) {
			// replaces the selected string with the string entered in the replace field
			view.replace();
		} else if (e.getActionCommand().equals(REPLACE_ALL_BUTTON)) { 
			// searches for all strings like the seleceted and replaces them all with the string in the replace field
			view.replaceAll();
		} else if (e.getActionCommand().equals(UNDO_BUTTON)) {
			// Annuls the last action
			view.undo();
		} else if (e.getActionCommand().equals(DO_BUTTON)) {
			// restores the last annulled action
			view.redo();
		} else if (e.getActionCommand().equals(ADD_NEW_FUNCTION_BUTTON)) {
			// calls the method, to create and add a function
			model.addFunction();
		} else if (e.getActionCommand().equals(REMOVE_FUNCTION_BUTTON)) {
			// calls the method to remove the currently selected function
			model.removeFunction();
		} else if (e.getActionCommand().equals(RENAME_FUNCTION_BUTTON)) {
			// calls the method to rename the currently selected function
			model.renameFunction();
		}
		if (setSelection)
			view.setSelected(selection);
	}
	
	
	public AbstractAction getCloseAction () {
		return new AbstractAction() {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				windowClosing(null);
			}
		};
	}
	
	
	/**
	 * makes the component- & function-keys draggable
	 */
//	public void mousePressed (MouseEvent e) {
//		if (e.getButton() == MouseEvent.BUTTON1) {
//			JComponent c = (JLabel)e.getSource();
//			TransferHandler handler = c.getTransferHandler();
//			handler.exportAsDrag(c, e, TransferHandler.COPY);
//		}
//	}
	
	/**
	 * If something is entered into the script editor, this method is called. It 
	 * marks the currently selected ScriptLink as "not saved".
	 */
	//@Override
	public void caretUpdate(CaretEvent e) {
		/* ======================================== */
		ScriptLink link = model.getCurrentlySelectedLink();
		int type = link.getType();
		int index = model.getScriptIndex(link);
//		link.setScript(editor.getScript());
		if (!model.isSaved(link)) {
			view.markAsNotSaved(model.getCurrentlySelectedLink());
		} else {
			view.markAsSaved(type, index);
		}
		/* ======================================== */
	}
	
	/**
	 * This is the itemListener of the componentBox, where the component elements can be switched
	 */
//	//@Override
//	public void itemStateChanged(ItemEvent e) {
//		if (model.canUpdate()
//				&& e.getItem() != null) {
//			model.selectItemFromComboBox(e.getItem().toString());
//		}
//	}

	
	/**
	 * This method is called, when the window should be closed, but so the default close operation is set to 
	 * DO_NOTHING_ON_CLOSE, nothing will happen. This method makes something happen. 
	 * At first it checks, if the changes are stored. 
	 * If they are stored, the editor is closed. Otherwise a dialog appears, that asks the user, if he / she wants 
	 * to save before closing or cancel. If cancel, the window will stay visible, otherwise it will be closed
	 */
	public void windowClosing(WindowEvent e) {
		// are the changes in the editor saved?
		if (view.getCloseWithoutSaving()
				|| model.isSaved()) {
			
			// changes are already saved -> close the editor
			view.hideEditor();
//			super.setVisible(false);
		} else {
			/*
			 * The entered text in the formula editor isn't equal to the string value of the formula attribute
			 * of the currently selected component. That means, the formula hasn't been saved.
			 * Therefore a yes-no-cancel-dialog will be opened, asking if the user wants to save the formula or
			 * exit without saving.
			 */
			int yncValue = GECAMedBaseDialogImpl.showMessageDialog(view, 
					Translatrix.getTranslationString("formeditor.save_changes_title"), 
					Translatrix.getTranslationString("formeditor.save_changes"), 
					GECAMedBaseDialogImpl.YES_NO_CANCEL_BUTTON_MODE);
			
			if (yncValue == GECAMedBaseDialog.YES_OPTION) {
				// save the changes and exit
				model.saveAllScripts();
//				super.setVisible(false);
				view.hideEditor();
			} else if (yncValue == GECAMedBaseDialog.NO_OPTION) {
				// exit without saving
				model.resetAllScripts();
				view.hideEditor();
//				super.setVisible(false);
			} else {
				// cancel - return to the editor and don't close the window
				return;
			}
		}
	}

	// not needed WindowListener-methods
	public void windowActivated(WindowEvent arg0) {}
	public void windowClosed(WindowEvent arg0) {}
	public void windowDeactivated(WindowEvent arg0) {}
	public void windowDeiconified(WindowEvent arg0) {}
	public void windowIconified(WindowEvent arg0) {}
	public void windowOpened(WindowEvent arg0) {}
}
