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

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.GregorianCalendar;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;

import lu.tudor.santec.gecamed.core.gui.GECAMedColors;
import lu.tudor.santec.gecamed.core.gui.GECAMedIconNames;
import lu.tudor.santec.gecamed.core.gui.GECAMedModule;
import lu.tudor.santec.gecamed.core.gui.IconFetcher;
import lu.tudor.santec.gecamed.core.gui.widgets.ModuleHeader;
import lu.tudor.santec.gecamed.formeditor.gui.FormEditorModule;
import lu.tudor.santec.gecamed.formeditor.gui.component.EditableComponent;
import lu.tudor.santec.gecamed.formeditor.gui.component.ScriptLink;
import lu.tudor.santec.gecamed.formeditor.gui.controller.ScriptEditorController;
import lu.tudor.santec.gecamed.formeditor.gui.model.ScriptEditorModel;
import lu.tudor.santec.i18n.Translatrix;

import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
import org.fife.ui.rtextarea.RTextScrollPane;
import org.fife.ui.rtextarea.SearchEngine;
import org.jdesktop.swingx.JXTaskPane;
import org.jdesktop.swingx.JXTaskPaneContainer;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.toedter.calendar.JDateChooser;

public class ScriptEditorView extends JFrame {
	/**
	 * @author Jens Ferring
	 * 
	 * This is the formula editor view. It creates an TextArea, where the formula can be typed in.
	 * The dialog has a border Layout. The TextArea for the formula lies in the center of the border layout.
	 * The formula will be saved in the EditableComponent. There are 3 buttons to save and reset the 
	 * formula and to close the editor. They are in the south of the border layout.
	 * In east of the border layout are the component key, that can be dragged into the 
	 */
	private static final long serialVersionUID = 1L;
	
	/*
	 * The colors for the links depending on the status of the link
	 */
	private static final Color DEFAULT_COLOR = new Color (100, 100, 100, 255);
	private static final Color NOT_SAVED_COLOR = new Color(140, 0, 0, 255);
	private static final Color HAS_SAVED_CODE_COLOR = new Color(0, 0, 0, 255);
//	private static final Color SELECTED_COLOR = Color.orange;
	
	// the model containing the data
	private ScriptEditorModel model;
	// the editor, where you can enter the script
	private RSyntaxTextArea editor;
	// the scroll pane on which the editor is placed
	private RTextScrollPane editorScrollPane;
	// the pane which contains the links. Every position in the array is one pane
	private JPanel[] linkPanel = new JPanel[ScriptEditorModel.SCRIPT_SIZE];
	// the buttons to remove and rename the currently selected function
	private JButton removeFunctionBtn;
	private JButton renameFunctionBtn;
	
	// the title bar of the script editor
	private ModuleHeader scriptEditorHeader;
	// the text in this TextField will be searched for
	private JTextField searchFld;
	// the text in this TextField will replace the selected text
	private JTextField replaceFld;
	// the save button, that saves the selected script
	private JButton saveBtn;
	// the save all button, that saves all scripts
	private JButton saveAllBtn;
	// the button, to reload the last saved script
	private JButton reloadBtn;
	
	/*
	 *  this ComboBox contains all EditableComponents. The here selected component will also be selected 
	 *  in the form-editor. The listener methods of the selected component are shown in the script-editor.
	 */
	private JComboBox componentBox;
	private JCheckBox expandedModusChB = new JCheckBox(Translatrix.getTranslationString("formeditor.expanded_modus"), false);
	
	private boolean closeWithoutSaving;
	
	private JTextArea errorArea;
	
//	private boolean contextMenuIsOpen = false;
	
	public ScriptEditorView (Window owner, ScriptEditorModel model) {
//		super(owner, "Script editor", false);
		super(Translatrix.getTranslationString("formeditor.script_editor"));
		
		this.setSize(
				(int)(owner.getWidth() * (3.0/4.0)), 
				(int)(owner.getHeight() * (2.0/3.0)));
		
		this.setLocation(
				owner.getX() + (owner.getWidth() - this.getWidth()) / 2, 
				owner.getY() + (owner.getHeight() - this.getHeight()) / 2);
		
		setIconImage(IconFetcher.getMediumIcon(FormEditorModule.class, FormEditorModule.SCRIPTEDITOR_ICON).getImage());
//		this.model = new ScriptEditorModel(globalModel, this);
//		this.setBackground(new Color(180, 180, 255, 255));
		this.model = model;
		/* 
		 * HIDE_ON_CLOSE because that makes it possible to override the closing operation
		 * and prevent the dialog from shutting down, without saving the changes 
		 */
		this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); //HIDE_ON_CLOSE); //DISPOSE_ON_CLOSE);
		
//		this.setLayout(new BorderLayout());
		this.setLayout(new FormLayout("f:265px, f:1px:g", "f:p, f:1px:g, f:75px"));
	}
	
	/**
	 * initializes the components after the Frame was built
	 */
	public void init () {
		/*
		 * initialize the task panels
		 */
		this.setBackground(GECAMedColors.c_GECAMedBackground);
		
		CellConstraints cc = new CellConstraints();
		
		JXTaskPaneContainer westTaskPaneContainer = new JXTaskPaneContainer();
		westTaskPaneContainer.setOpaque(false);
//		JXTaskPaneContainer eastTaskPaneContainer = new JXTaskPaneContainer();
//		eastTaskPaneContainer.setOpaque(false);
		JXTaskPane[] taskPanes = new JXTaskPane[ScriptEditorModel.SCRIPT_SIZE];
		ScriptEditorController controller = new ScriptEditorController(model);
		this.addWindowListener(controller);
		
		/* **********  KEY-STROKES  ********** */
		// ESC - exit
		((JPanel) this.getContentPane()).getInputMap(
					JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
					.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel");
		((JPanel) this.getContentPane()).getActionMap().put("cancel", controller.getCloseAction());
		
		// CTRL + S - save
		((JPanel) this.getContentPane()).getInputMap(
				JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
				.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.CTRL_DOWN_MASK, true), "save");
		((JPanel) this.getContentPane()).getActionMap().put("save", new AbstractAction() {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				model.saveSelectedScript();
				if (model.isSaved()) {
					enableAllButtons(false);
				}
				/* ---------------------------------------- */
			}
		});
		
		// ALT GR + A - save all
		((JPanel) this.getContentPane()).getInputMap(
				JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
				.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, KeyEvent.ALT_GRAPH_DOWN_MASK, true), "saveAll");
		((JPanel) this.getContentPane()).getActionMap().put("saveAll", new AbstractAction() {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				model.saveAllScripts();
				enableAllButtons(false);
				/* ---------------------------------------- */
			}
		});
		
		// F3 - search
		((JPanel) this.getContentPane()).getInputMap(
				JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
				.put(KeyStroke.getKeyStroke("F3"), "search");
		((JPanel) this.getContentPane()).getActionMap().put("search", new AbstractAction() {
			private static final long serialVersionUID = 1L;

			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				searchFld.requestFocus();
				searchFld.setSelectionStart(0);
				searchFld.setSelectionEnd(searchFld.getText().length());
				/* ---------------------------------------- */
			}
		});
		
		
//		// CTRL + Z - undo
//		((JPanel) this.getContentPane()).getInputMap(
//				JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
//				.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK, true), "undo");
//		((JPanel) this.getContentPane()).getActionMap().put("undo", new AbstractAction() {
//			private static final long serialVersionUID = 1L;
//
//			public void actionPerformed(ActionEvent e) {
//				/* ---------------------------------------- */
//				ScriptEditorView.this.undo();
//				/* ---------------------------------------- */
//			}
//		});
//		
//		
//		// CTRL + Y - redo
//		((JPanel) this.getContentPane()).getInputMap(
//				JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
//				.put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, KeyEvent.CTRL_DOWN_MASK, true), "redo");
//		((JPanel) this.getContentPane()).getActionMap().put("redo", new AbstractAction() {
//			private static final long serialVersionUID = 1L;
//
//			public void actionPerformed(ActionEvent e) {
//				/* ---------------------------------------- */
//				ScriptEditorView.this.redo();
//				/* ---------------------------------------- */
//			}
//		});
		/* **************************************** */
		
		componentBox = new JComboBox();
		componentBox.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				/* ---------------------------------------- */
				if (// model.canUpdate() && 
						componentBox.getSelectedIndex() >= 0) {
//					model.selectItemFromComboBox(componentBox.getSelectedItem().toString());
					model.update(componentBox.getSelectedItem().toString());
				}
				/* ---------------------------------------- */
			}
		});
		
		/*
		 * insert into the linkPanels all dynamic components.
		 * This panel will be entered into a JXTaskPane where other, fix 
		 * components can be added to.
		 */
		JPanel[] upperTaskPanels = new JPanel[taskPanes.length];
		for (int type = 0; type < ScriptEditorModel.SCRIPT_SIZE; type++) {
			taskPanes[type] = new JXTaskPane ();
			taskPanes[type].getContentPane().setBackground(GECAMedColors.c_GECAMedDarkerBackground);
			upperTaskPanels[type] = new JPanel(new FormLayout("0px", "0px"));
			upperTaskPanels[type].setOpaque(false);
			taskPanes[type].add(upperTaskPanels[type]);
			linkPanel[type] = new JPanel(new GridLayout(0, 1));	
			linkPanel[type].setOpaque(false);
			taskPanes[type].add(linkPanel[type]);
			if (type < 3) {
				// the links for the scripts
				westTaskPaneContainer.add(taskPanes[type]);
//			} else {
//				// keys of the components, available variables etc.
//				eastTaskPaneContainer.add(taskPanes[type]);
			}
		}
		new JDateChooser().setDate(new GregorianCalendar().getTime());
		/*
		 * add components into the panels
		 */
		taskPanes[ScriptEditorModel.INIT_SCRIPT].setIcon(IconFetcher.getMiniIcon(FormEditorModule.class, FormEditorModule.INITSCRIPT_ICON));
		taskPanes[ScriptEditorModel.INIT_SCRIPT].setTitle(Translatrix.getTranslationString("formeditor.init_method")+":");
		model.changeScripts(ScriptEditorModel.INIT_SCRIPT);
		// component keys must be set before the listener-methods, because, the listener-methods check the component-keys
//		taskPanes[ScriptEditorModel.COMPONENT_KEYS].setIcon(IconFetcher.getMiniIcon(GECAMedIconNames.class, GECAMedIconNames.PASSWORD));
//		taskPanes[ScriptEditorModel.COMPONENT_KEYS].setTitle(Translatrix.getTranslationString("formeditor.component_keys")+":");
		model.changeScripts(ScriptEditorModel.COMPONENT_KEYS);
		taskPanes[ScriptEditorModel.LISTENER_METHOD].setIcon(IconFetcher.getMiniIcon(FormEditorModule.class, FormEditorModule.LISTENER_METHOD_ICON));
		taskPanes[ScriptEditorModel.LISTENER_METHOD].setTitle(Translatrix.getTranslationString("formeditor.listener_methods")+":");
		model.changeScripts(ScriptEditorModel.LISTENER_METHOD);
		taskPanes[ScriptEditorModel.FUNCTION].setIcon(IconFetcher.getMiniIcon(FormEditorModule.class, FormEditorModule.FUNCTION_ICON));
		taskPanes[ScriptEditorModel.FUNCTION].setTitle(Translatrix.getTranslationString("formeditor.functions")+":");		
		model.changeScripts(ScriptEditorModel.FUNCTION);
//		taskPanes[ScriptEditorModel.FUNCTION_SHORTCUT].setIcon(IconFetcher.getMiniIcon(FormEditorModule.class, FormEditorModule.FUNCTION_ICON));
//		taskPanes[ScriptEditorModel.FUNCTION_SHORTCUT].setTitle(Translatrix.getTranslationString("formeditor.functions")+":");		
		model.changeScripts(ScriptEditorModel.FUNCTION_SHORTCUT);
		
		// the buttons, to add and to remove a new function to / from the list
		JPanel p = new JPanel (new FormLayout("1dlu, l:35px, 2dlu, l:35px, 2dlu, l:35px, p:g", "1dlu, 35px, 1dlu"));
		p.setOpaque(false);
		JButton b = new JButton (IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.ADD, 32));//"add a new function");
		b.setActionCommand(ScriptEditorController.ADD_NEW_FUNCTION_BUTTON);
		b.addActionListener(controller);
		b.setToolTipText(Translatrix.getTranslationString("formeditor.add_function"));
		p.add(b, cc.xy(2, 2));
		removeFunctionBtn = new JButton (IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.REMOVE, 32));
		removeFunctionBtn.setActionCommand(ScriptEditorController.REMOVE_FUNCTION_BUTTON);
		removeFunctionBtn.addActionListener(controller);
		removeFunctionBtn.setToolTipText(Translatrix.getTranslationString("formeditor.remove_function"));
		p.add(removeFunctionBtn, cc.xy(4, 2));
		renameFunctionBtn = new JButton (IconFetcher.getScaledIcon(FormEditorModule.class, "rename.png", 32));
		renameFunctionBtn.setActionCommand(ScriptEditorController.RENAME_FUNCTION_BUTTON);
		renameFunctionBtn.addActionListener(controller);
		renameFunctionBtn.setToolTipText(Translatrix.getTranslationString("formeditor.rename_function"));
		p.add(renameFunctionBtn, cc.xy(6, 2));
		
		taskPanes[ScriptEditorModel.FUNCTION].add(p);
		model.changeScripts(ScriptEditorModel.FUNCTION);
		
		// create the expanded-modus CheckBox
		p = upperTaskPanels[ScriptEditorModel.LISTENER_METHOD];
		p.setOpaque(false);
		p.setLayout(new BorderLayout());
		expandedModusChB.setActionCommand(ScriptEditorController.EXPANDED_MODUS);
		expandedModusChB.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				model.setExtendedModus(expandedModusChB.isSelected());
			}
		});
		expandedModusChB.setOpaque(false);
//		expandedModusChB.setBackground(GECAMedColors.c_GECAMedDarkerBackground);
		p.add(expandedModusChB);
		
		
		// create the panel in the WEST, where the script-links are put to (surrounded with a ScrollPane) 
		p = new JPanel(new BorderLayout());
		p.setOpaque(false);
		p.add(componentBox, BorderLayout.NORTH);
		p.add(westTaskPaneContainer, BorderLayout.CENTER);
		
		// add the panel in the WEST
//		JPanel limitedPanel = new JPanel (new FormLayout("min(100dlu;p)", "f:p:g"));
//		limitedPanel.setOpaque(false);
//		limitedPanel.add(p, cc.xy(1, 1));
		JScrollPane scrollPane = new JScrollPane(p);
		scrollPane.getVerticalScrollBar().setUnitIncrement(16);
		scrollPane.setBackground(GECAMedColors.c_GECAMedBackground);
		scrollPane.getViewport().setOpaque(false);
		scrollPane.getViewport().setBackground(GECAMedColors.c_GECAMedBackground);
		scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		this.add(scrollPane, cc.xywh(1, 2, 1, 2));
		
//		// add the panel in the EAST 
//		limitedPanel = new JPanel (new FormLayout("min(100dlu;p)", "f:p:g"));
//		limitedPanel.setOpaque(false);
//		limitedPanel.add(eastTaskPaneContainer, cc.xy(1, 1));
//		scrollPane = new JScrollPane(limitedPanel);
//		scrollPane.setOpaque(false);
//		scrollPane.getViewport().setBackground(GECAMedColors.c_GECAMedBackground);
//		this.add(scrollPane, BorderLayout.EAST);
		
		// add the panel and the TextArea in the center
		editorScrollPane = new RTextScrollPane();
		editorScrollPane.setLineNumbersEnabled(true);
//		editorScrollPane.setOpaque(false);
		editorScrollPane.setBackground(GECAMedColors.c_GECAMedBackground);
		this.add(editorScrollPane, cc.xy(2, 2));
		
		
		/* ---------------------------------------- */
		// add the error text area
		/* ---------------------------------------- */
		
		errorArea = new JTextArea();
		errorArea.setEditable(false);
		errorArea.setOpaque(false);
		errorArea.setLineWrap(true);
		errorArea.setWrapStyleWord(true);
		
		JScrollPane sp = new JScrollPane(errorArea);
			sp.getVerticalScrollBar().setUnitIncrement(16);
		this.add(sp, cc.xy(2, 3));
		
		/* ---------------------------------------- */
		
		
		/* NORTH
		 * the buttons to save, reset and close are add in the north. The ActionCommand tells the Controller
		 * what to, if the button triggers an event. 
		 */
		JButton checkCodeBtn = new JButton("", GECAMedModule.getScaledIcon(GECAMedIconNames.ERROR, 32));
		checkCodeBtn.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				model.checkScript();
			}
		});
		checkCodeBtn.setToolTipText(Translatrix.getTranslationString("formeditor.check_code"));
		
		saveBtn = new JButton(IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.SAVE, 32));// ("save formula");
		saveBtn.addActionListener(controller);
		saveBtn.setActionCommand(ScriptEditorController.SAVE_BUTTON);
		saveBtn.setToolTipText(Translatrix.getTranslationString("formeditor.save"));
		ModuleHeader.addEffect(saveBtn);
		
		saveAllBtn = new JButton(IconFetcher.getScaledIcon(FormEditorModule.class, FormEditorModule.SAVE_ALL_ICON, 32)); //"save all");
		saveAllBtn.addActionListener(controller);
		saveAllBtn.setActionCommand(ScriptEditorController.SAVE_ALL_BUTTON);
		saveAllBtn.setToolTipText(Translatrix.getTranslationString("formeditor.save_all"));
		ModuleHeader.addEffect(saveAllBtn);
		
		reloadBtn = new JButton(IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.RELOAD, 32)); //"reset formula");
		reloadBtn.addActionListener(controller);
		reloadBtn.setActionCommand(ScriptEditorController.RESET_BUTTON);
		reloadBtn.setToolTipText(Translatrix.getTranslationString("formeditor.reset"));
		ModuleHeader.addEffect(reloadBtn);
		
		JButton undoBtn = new JButton(IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.UNDO, 32));
		undoBtn.addActionListener(controller);
		undoBtn.setActionCommand(ScriptEditorController.UNDO_BUTTON);
		undoBtn.setToolTipText(Translatrix.getTranslationString("formeditor.undo"));
		ModuleHeader.addEffect(undoBtn);
		
		JButton redoBtn = new JButton(IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.DO, 32));
		redoBtn.addActionListener(controller);
		redoBtn.setActionCommand(ScriptEditorController.DO_BUTTON);
		redoBtn.setToolTipText(Translatrix.getTranslationString("formeditor.redo"));
		ModuleHeader.addEffect(redoBtn);
		
//		JButton resetAllBtn = new JButton("reset all");
//		resetAllBtn.addActionListener(controller);
//		resetAllBtn.setActionCommand(ScriptEditorController.RESET_ALL_BUTTON);
		
//		JButton closeBtn = new JButton("close editor");
//		closeBtn.addActionListener(controller);
//		closeBtn.setActionCommand(ScriptEditorController.CLOSE_BUTTON);
		
		searchFld = new JTextField ();
		searchFld.addActionListener(controller);
		searchFld.setActionCommand(ScriptEditorController.SEARCH_BUTTON);
		JButton searchBtn = new JButton (IconFetcher.getScaledIcon(GECAMedModule.class, GECAMedIconNames.SEARCH, 32));
		searchBtn.addActionListener(controller);
		searchBtn.setActionCommand(ScriptEditorController.SEARCH_BUTTON);
		searchBtn.setToolTipText(Translatrix.getTranslationString("formeditor.search"));
		ModuleHeader.addEffect(searchBtn);
		
		replaceFld = new JTextField ();
		JButton replaceBtn = new JButton(IconFetcher.getScaledIcon(FormEditorModule.class, FormEditorModule.REPLACE_ICON, 32));
		replaceBtn.addActionListener(controller);
		replaceBtn.setActionCommand(ScriptEditorController.REPLACE_BUTTON);
		replaceBtn.setToolTipText(Translatrix.getTranslationString("formeditor.replace"));
		ModuleHeader.addEffect(replaceBtn);
		
		JButton replaceAllBtn = new JButton (IconFetcher.getScaledIcon(FormEditorModule.class, FormEditorModule.REPLACE_ALL_ICON, 32));
		replaceAllBtn.addActionListener(controller);
		replaceAllBtn.setActionCommand(ScriptEditorController.REPLACE_ALL_BUTTON);
		replaceAllBtn.setToolTipText(Translatrix.getTranslationString("formeditor.replace_all"));
		ModuleHeader.addEffect(replaceAllBtn);
		
		// the panel for the buttons is created. The buttons are ordered next to each other
//		JPanel formulaEditorButtonPnl = new JPanel(new FormLayout("2dlu, 35px, 2dlu, " + // save button
//																		"35px, 2dlu, " + // save all button 
//																		"35px, 2dlu, " + // reset button
//																		"35px, 2dlu, " + // undo button
//																		"35px, 2dlu, " + // redo button
//																		"50dlu, 1dlu, " + // search field
//																		"35px, 2dlu, " + // search button
//																		"50dlu, 1dlu, " + // replace field
//																		"35px, 2dlu, " + // replace button
//																		"35px, 2dlu, " + // replace all button
//																		"35px", 
//																		"1dlu, 35px, 1dlu")); // height
////		formulaEditorButtonPnl.setOpaque(true);
//		formulaEditorButtonPnl.setBackground(GECAMedColors.c_GECAMedBackground);
//		
////		JPanel formulaEditorButtonPnl = new JPanel (new GridLayout(1, 0));
//		formulaEditorButtonPnl.add(saveBtn, cc.xy(2, 2));
//		formulaEditorButtonPnl.add(saveAllBtn, cc.xy(4, 2));
//		formulaEditorButtonPnl.add(resetBtn, cc.xy(6, 2));
//		formulaEditorButtonPnl.add(undoBtn, cc.xy(8, 2));
//		formulaEditorButtonPnl.add(redoBtn, cc.xy(10, 2));
//		formulaEditorButtonPnl.add(searchFld, cc.xy(12, 2));
//		formulaEditorButtonPnl.add(searchBtn, cc.xy(14, 2));
//		formulaEditorButtonPnl.add(replaceFld, cc.xy(16, 2));
//		formulaEditorButtonPnl.add(replaceBtn, cc.xy(18, 2));
//		formulaEditorButtonPnl.add(replaceAllBtn, cc.xy(20, 2));
//		this.add(formulaEditorButtonPnl, cc.xyw(1, 1, 2));
		
		scriptEditorHeader = new ModuleHeader(
				Translatrix.getTranslationString("formeditor.script_editor"), 
				FormEditorModule.getScaledIcon(FormEditorModule.SCRIPTEDITOR_ICON, 32),
				Color.WHITE);
				// new Color(156, 179, 225));
				// new Color(196, 228, 255));

		scriptEditorHeader.addButton(checkCodeBtn);
		scriptEditorHeader.addButton(undoBtn);
		scriptEditorHeader.addButton(redoBtn);
		scriptEditorHeader.addButton(searchFld);
		scriptEditorHeader.addButton(searchBtn);
		scriptEditorHeader.addButton(replaceFld);
		scriptEditorHeader.addButton(replaceBtn);
		scriptEditorHeader.addButton(replaceAllBtn);
		scriptEditorHeader.addButton(reloadBtn);
		scriptEditorHeader.addButton(saveBtn);
		scriptEditorHeader.addButton(saveAllBtn);
		
		searchFld.setPreferredSize(new Dimension(100, 20));
		replaceFld.setPreferredSize(new Dimension(100, 20));
		
		this.add(scriptEditorHeader, cc.xyw(1, 1, 2));
		
		
		// select the init-script for initialization
//		model.select((ScriptLink)model.getScriptAt(ScriptEditorModel.INIT_SCRIPT, 0));
		
		/*
		 * at last, the dialog is formated
		 */
		model.select((ScriptLink)model.getScriptAt(ScriptEditorModel.INIT_SCRIPT, 0));
		enableAllButtons(false);
		
		this.setResizable(true);
//		super.setVisible(true);
	}
	
	/**
	 * adds links of the array with the specified type into the panel with
	 * the specified type
	 */
	public void setScriptLinks(int type) {
		// remove old links
		linkPanel[type].removeAll();
		// add new links
		ArrayList<JComponent> scriptLinks = model.getScriptAt(type);
		int index;
		if (type == ScriptEditorModel.LISTENER_METHOD
				&& !expandedModusChB.isSelected()) {
			index = EditableComponent.SUPER_LISTENER_METHOD_SIZE;
		} else {
			index = 0;
			if (type != ScriptEditorModel.LISTENER_METHOD) {
				Collections.sort(scriptLinks, new Comparator<JComponent>() {
					public int compare(JComponent o1, JComponent o2) {
						if (o1 == null || o2 == null) {
							return 0;
						}
						if (o1 instanceof JLabel) {
							return ((JLabel)o1).getText().compareToIgnoreCase(
									((JLabel)o2).getText());
						} else if (o1 instanceof ScriptLink) {
							return ((ScriptLink)o1).getKey().compareToIgnoreCase(
									((ScriptLink)o2).getKey());
						} else 
							return o1.getName().compareToIgnoreCase(o2.getName());
					}			
				});
			}
		}
		for ( ; index < scriptLinks.size(); index++) {
			if (type < 3) {
				/* 
				 * if it is the last component of the function scripts, it's the JButton,
				 * to create a new function
				 */
				ScriptLink link = (ScriptLink)model.getScriptAt(type, index);
				if (model.isSaved(link)) {
					markAsSaved(type, index);
				} else {
					markAsNotSaved(link);
				}
//				if (((ScriptLink)model.getScriptAt(type, index)).getScript().length() == 0) {
//					scriptLinks.get(index).setForeground(DEFAULT_COLOR);
//				} else {
//					scriptLinks.get(index).setForeground(HAS_SAVED_CODE_COLOR);
//				}
			}
			// add the component to the panel
			linkPanel[type].add(scriptLinks.get(index));
		}
		this.validate();
	}
	
	/**
	 * the consigned value is marked as "not saved" by changing the font-color
	 */
	public void markAsNotSaved (ScriptLink link) {
		link.setForeground(NOT_SAVED_COLOR);
		
		saveBtn.setEnabled(true);
		reloadBtn.setEnabled(true);
		saveAllBtn.setEnabled(true);
		scriptEditorHeader.setColor(Color.YELLOW);
	}
	
	/**
	 * the consigned value is marked as "saved with text" or "saved without text" 
	 * by changing the font-color
	 */
	public void markAsSaved (int type, int index) {
		if (((ScriptLink)model.getScriptAt(type, index)).getScript().length() == 0) {
			model.getScriptAt(type, index).setForeground(DEFAULT_COLOR);
		} else if (model.isSaved(type, index)) {
			model.getScriptAt(type, index).setForeground(HAS_SAVED_CODE_COLOR);
		}
		
		enableButtons(false);
	}
	
	/**
	 * adds a ScriptLink to the panel with the specified type
	 */
	public void addScriptLink(int type, ScriptLink link) {
		linkPanel[type].add(link);
		this.validate();
	}

	public void redo () {
		editor.redoLastAction();
	}
	public void undo () {
		editor.undoLastAction();
	}
	
	/**
	 * finds the string entered in the search field in the TextArea
	 */
	public boolean search () {
		boolean searched = false;
		while (true) {
			/* SearchEngine.find(JTextArea textArea, String searchedString, 
			 * 		boolean forward, boolean matchCase, boolean wholeWord, 
			 * 		boolean regularExpression) : boolean
			 */
			if (SearchEngine.find(editor, searchFld.getText(), true, false, false, false)) {
				return true;
			} else {
				if (searched) {
					return false;
				} else {
					searched = true;
					editor.setSelectionStart(0);
					editor.setSelectionEnd(0);
				}
			}
		}
	}	
	
	/**
	 * replace the current selection with the string in the replace field
	 */
	public void replace () {
		if (editor.getSelectedText() != null
				&& editor.getSelectedText().length() != 0) {
			int selection = editor.getSelectionStart();
			/* SearchEngine.replace(JTextArea textArea, String searchedString, 
			 * 		String replacingString, boolean forward, boolean matchCase, 
			 * 		boolean wholeWord, boolean regularExpression) : boolean
			 */
			boolean replaced = SearchEngine.replace(editor, editor.getSelectedText(), replaceFld.getText(), true, false, false, false);
			editor.setSelectionStart(selection);
			if (replaced) {
				editor.setSelectionEnd(selection + replaceFld.getText().length());
			}
		}
	}
	
	/**
	 * replace all Strings that are like the current selection with the string in the replace field
	 */
	public void replaceAll () {
		/*
		 * The replaceAll method of the SerachEngine doesn't work properly.
		 * That's why I created a own replace all function out of the existing search and replace method. 
		 */
//		if (editor.getSelectedText() != null
//				&& !editor.getSelectedText().length() == 0) {
//			int selection = editor.getSelectionStart();
//			SearchEngine.replaceAll(editor, editor.getSelectedText(), replaceFld.getText(), true, true, false);	
//			editor.setSelectionStart(selection);
//			editor.setSelectionEnd(selection);		
//		}
		if (editor != null
				&& editor.getSelectedText() != null
				&& !editor.getSelectedText().equals(replaceFld.getText())) {
			
			int startPosition = editor.getSelectionStart();
			boolean wrapted = false;
			int currentPosition;
			while (search()) {
				
				currentPosition = editor.getSelectionStart();
				if (!wrapted) {
					wrapted = currentPosition <= startPosition;
				} 
				if (!wrapted) {
					if (currentPosition >= startPosition) {
						break;
					}
				}
				
				replace();
			}
		}
	}
	
	public void addToComponentBox (String componentKey) {
//		ComboBoxElement e = new ComboBoxElement(componentKey, componentKey);
		componentBox.addItem(componentKey);
	}
	
	public void selectInComponentBox (EditableComponent component) {
		/* ======================================== */
		if (component != null
				&& componentBox.getComponentCount() > 0) {
			componentBox.setSelectedItem(component.getKey());
			
//			for (int index = 0; index < componentBox.getItemCount(); index++) {
//				/* ---------------------------------------- */
//				if ((componentBox.getItemAt(index)).equals(component.getKey())) {
//					componentBox.setSelectedIndex(index);
////					model.selectItemFromComboBox(component.getKey());
//					return;
//				}
//				/* ---------------------------------------- */
//			}
		}
		
//		componentBox.setSelectedIndex(-1);
		if (componentBox.getSelectedIndex() == -1) {
			model.changeScripts(ScriptEditorModel.LISTENER_METHOD);
		}
		/* ======================================== */
	}
	
	public void removeAllFromComponentBox () {
		componentBox.removeAllItems();
	}
	
	public boolean isComponentBoxEmpty () {
		return (componentBox.getItemCount() <= 0);
	}
	
	public String getSelectedKey ()
	{
		return (String) componentBox.getSelectedItem();
	}
	
	public void hideEditor() {
		setVisible(false);
		setVisible(true);
		setVisible(false);
	}
	
	public void closeWithoutSaving () {
		closeWithoutSaving = true;
		this.hideEditor();
	}
	
	public boolean getCloseWithoutSaving () {
		return closeWithoutSaving;
	}
	
	/*********************************************
	 ************* GETTER AND SETTER *************
	 ********************************************/
	
	/**
	 * the text of the editor can be changed / returned by this methods
	 */
	public void setEditor (RSyntaxTextArea newEditor) {
		/* ======================================== */
		if (editorScrollPane != null) {
			/* ---------------------------------------- */
			this.editor = newEditor;
			editorScrollPane.setViewportView(editor);
			this.editor.addCaretListener(new ScriptEditorController(model));
			
//			editor.setPopupMenu(model.getRightClickMenu());
//			model.buildRightClickMenu();
			/* ---------------------------------------- */
		}
		/* ======================================== */
	}
	
	public RSyntaxTextArea getEditor () {
		/* ======================================== */
		return editor;
		/* ======================================== */
	}
	
	public void setErrorMsg (String text, boolean isError) {
		if (isError) {
			errorArea.setForeground(Color.RED);
		} else {
			errorArea.setForeground(Color.BLACK);
		}
		errorArea.setText(text);
	}
	
	public int getSelected () {
		return editor.getSelectionStart();
	}
	public void setSelected (int selection) {
		editor.setSelectionStart(selection);
		editor.setSelectionEnd(selection);
	}
	public void setFunctionButtonsEnabled (boolean enabled) {
		/* ======================================== */
		if (renameFunctionBtn != null 
				&& removeFunctionBtn != null) {
			/* ---------------------------------------- */
			renameFunctionBtn.setEnabled(enabled);
			removeFunctionBtn.setEnabled(enabled);
			/* ---------------------------------------- */
		}
		/* ======================================== */
	}
	public boolean isExtendedModus () {
		return expandedModusChB.isSelected();
	}
	
	public void enableButtons (boolean enable) {
		if (saveBtn != null) {
			saveBtn.setEnabled(enable);
			reloadBtn.setEnabled(enable);
			if (enable) {
				scriptEditorHeader.setColor(Color.YELLOW);
			}
		}
	}

	public void enableAllButtons(boolean b) {
		enableButtons(b);
		if (!b) {
			scriptEditorHeader.setColor(Color.WHITE);
		}
		
		saveAllBtn.setEnabled(b);
	}
}