/*
 * Copyright (c) 2006-2008 Maskat Project.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Maskat Project - initial API and implementation
 */
package org.maskat.ui.views.properties.tabbed.masterdetails;

import java.util.Iterator;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.ExpandableComposite;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;

import org.maskat.core.MaskatElement;
import org.maskat.core.event.Component;
import org.maskat.core.event.Event;
import org.maskat.core.event.EventDef;
import org.maskat.core.event.Header;
import org.maskat.ui.Messages;
import org.maskat.ui.views.properties.tabbed.beanwrapper.HeaderTreeNode;
import org.maskat.ui.views.properties.tabbed.command.MockCommand;
import org.maskat.ui.views.properties.tabbed.treenodewrapper.ITreeNode;

public class HeaderDetailsPage extends AbstractMaskatDetailsPage {

	private static final String SECTION_TEXT = Messages
			.getString("headerDetails.sectionText"); //$NON-NLS-1$

	private static final String SECTION_DESCRIPTION = Messages
			.getString("headerDetails.description"); //$NON-NLS-1$

	private static final String DIALOG_TITLE = Messages
			.getString("headerDetails.optionDialog.title"); //$NON-NLS-1$

	private static final String DIALOG_MESSAGE = Messages
			.getString("headerDetails.optionDialog.message"); //$NON-NLS-1$

	private static final String[] DIALOG_OPTIONS = new String[] {
			Messages.getString("headerDetails.optionDialog.option1"), //$NON-NLS-1$
			Messages.getString("headerDetails.optionDialog.option2") }; //$NON-NLS-1$

	private static final String[] DIALOG_OPTIONS_EXPLANATIONS = new String[] {
			Messages.getString("headerDetails.optionDialog.explanation1"), //$NON-NLS-1$
			Messages.getString("headerDetails.optionDialog.explanation2") }; //$NON-NLS-1$

	private Text nameText;

	private Text valueText;

	private Button globalButton;

	private Header header;

	private boolean lastStateGlobalButton = false;

	private Event event;

	public HeaderDetailsPage(TreeViewer masterBlockTreeViewer) {
		this.masterBlockTreeViewer = masterBlockTreeViewer;
	}

	public void createContents(Composite parent) {
		TableWrapLayout layout = new TableWrapLayout();
		layout.topMargin = 0;
		layout.leftMargin = 5;
		layout.rightMargin = 5;
		layout.bottomMargin = 5;
		parent.setLayout(layout);

		FormToolkit toolkit = managedForm.getToolkit();

		Section headerSection = toolkit.createSection(parent,
				ExpandableComposite.TITLE_BAR | Section.DESCRIPTION);
		headerSection.setText(SECTION_TEXT);
		headerSection.setDescription(SECTION_DESCRIPTION);
		TableWrapData tableWrapData = new TableWrapData(TableWrapData.FILL,
				TableWrapData.TOP);
		tableWrapData.grabHorizontal = true;
		headerSection.setLayoutData(tableWrapData);

		Composite headerComposite = toolkit.createComposite(headerSection);
		headerComposite.setLayout(new GridLayout(3, false));

		toolkit.createLabel(headerComposite, Messages
				.getString("headerDetails.nameLabel")); //$NON-NLS-1$
		toolkit.createLabel(headerComposite, ":");
		nameText = toolkit.createText(headerComposite, "", SWT.SINGLE
				| SWT.BORDER);
		nameText.setLayoutData(new GridData(SWT.FILL, 0, true, false));

		toolkit.createLabel(headerComposite, Messages
				.getString("headerDetails.valueLabel")); //$NON-NLS-1$
		toolkit.createLabel(headerComposite, ":");
		valueText = toolkit.createText(headerComposite, "", SWT.SINGLE
				| SWT.BORDER);
		valueText.setLayoutData(new GridData(SWT.FILL, 0, true, false));

		globalButton = toolkit.createButton(headerComposite, Messages
				.getString("headerDetails.globalCheck"), SWT.CHECK);
		GridData data = new GridData();
		data.horizontalSpan = 3;
		globalButton.setLayoutData(data);

		nameText.addKeyListener(new KeyAdapter() {

			private int oldCaretPosition;

			public void keyReleased(KeyEvent e) {
				if (!nameText.getText().equals("")) {
					if (header.getName() == null
							|| !header.getName().equals(nameText.getText())) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "name", nameText
										.getText());
					}
				} else {
					if (header.getName() != null) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "name", null);
					}
				}
				oldCaretPosition = nameText.getCaretPosition();
				updateTreeViewer();
				nameText.setSelection(oldCaretPosition);
			}
		});

		nameText.addFocusListener(new FocusAdapter() {

			public void focusLost(FocusEvent e) {
				if (!nameText.getText().equals("")) {
					if (header.getName() == null
							|| !header.getName().equals(nameText.getText())) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "name", nameText
										.getText());
					}
				} else {
					if (header.getName() != null) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "name", null);
					}
				}
			}
		});

		valueText.addKeyListener(new KeyAdapter() {

			private int oldCaretPosition;

			public void keyReleased(KeyEvent e) {
				if (!valueText.getText().equals("")) {
					if (header.getValue() == null
							|| !header.getValue().equals(valueText.getText())) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "value",
								valueText.getText());
					}
				} else {
					if (header.getValue() != null) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "value", null);
					}
				}
				oldCaretPosition = valueText.getCaretPosition();
				updateTreeViewer();
				valueText.setSelection(oldCaretPosition);
			}
		});

		valueText.addFocusListener(new FocusAdapter() {

			public void focusLost(FocusEvent e) {
				if (!valueText.getText().equals("")) {
					if (header.getValue() == null
							|| !header.getValue().equals(valueText.getText())) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "value",
								valueText.getText());
					}
				} else {
					if (header.getValue() != null) {
						EventPropertiesMasterDetailsBlock.setEventProperty(masterBlockTreeViewer,
								HeaderTreeNode.class, header, "value", null);
					}
				}
			}

		});

		globalButton.addSelectionListener(new SelectionAdapter() {

			public void widgetSelected(SelectionEvent e) {
				updateHeaderType(globalButton.getSelection());
				super.widgetSelected(e);
			}
		});

		headerSection.setClient(headerComposite);
	}

	private void updateHeaderType(boolean selection) {

		if (lastStateGlobalButton != selection) {
			if (lastStateGlobalButton == true) // make header local
			{
				int headerToLocalSelection = showOptionsDialog();
				if (headerToLocalSelection == OptionMessageDialog.OPTION1_SELECTED) {
					// just for this event
					copyHeaderIntoThisEvent();
					setDirtyFlag(true);
					EventPropertiesMasterDetailsBlock.executeCommand(new MockCommand());
				} else if (headerToLocalSelection == OptionMessageDialog.OPTION2_SELECTED) {
					// for all events
					copyHeaderIntoEachEvent();
					setDirtyFlag(true);
					EventPropertiesMasterDetailsBlock.executeCommand(new MockCommand());
				}
			} else { // make header global
				makeHeaderGlobal();
				EventPropertiesMasterDetailsBlock.executeCommand(new MockCommand());			}
		}
		updateTreeViewer();
	}

	private void makeHeaderGlobal() {
		MaskatElement headerParent = event.getParent();

		//TODO should remove the same header from all events?
		event.removeChild(header);

		if (headerParent instanceof EventDef) {
			((EventDef) headerParent).addChild(header);
		}
		if (headerParent instanceof Component) {
			((EventDef) headerParent.getParent()).addChild(header);
		}
	}

	private void copyHeaderIntoEachEvent() {
		MaskatElement headerParent = header.getParent();
		EventDef eventDef = null;
		String headerName = header.getName();
		String headerValue = header.getValue();

		if (headerParent instanceof EventDef) {
			eventDef = (EventDef) headerParent;

			Iterator eventIterator = eventDef.getAllEvents();

			Event tmpEvent = null;

			if (eventIterator != null) {
				while (eventIterator.hasNext()) {
					tmpEvent = (Event) eventIterator.next();
					if (tmpEvent != this.event) {
						Header newHeader = new Header();
						newHeader.setName(headerName);
						newHeader.setValue(headerValue);
						tmpEvent.addChild(newHeader);
					}
				}
			}

			Iterator componentIterator = eventDef.getAllComponents();

			if (componentIterator != null) {
				while (componentIterator.hasNext()) {
					MaskatElement component = (MaskatElement) componentIterator
							.next();

					eventIterator = component.getTypedChildren(Event.class);

					if (eventIterator != null) {
						while (eventIterator.hasNext()) {
							tmpEvent = (Event) eventIterator.next();
							if (tmpEvent.getType().equals("remote")
									&& tmpEvent != event) {
								Header newHeader = new Header();
								newHeader.setName(headerName);
								newHeader.setValue(headerValue);
								tmpEvent.addChild(newHeader);
							}
						}
					}
				}
			}

			eventDef.removeChild(header);

			this.event.addChild(header);

		}
	}

	private void copyHeaderIntoThisEvent() {
		MaskatElement headerParent = header.getParent();

		if (headerParent instanceof EventDef) {
			((EventDef) headerParent).removeChild(header);
		}
		if (headerParent instanceof Component) {
			((Component) headerParent).removeChild(header);
		}

		this.event.addChild(header);
	}

	protected void initializeInterface() {
		if (header.getName() != null) {
			nameText.setText(header.getName());
		} else {
			nameText.setText("");
		}

		if (header.getValue() != null) {
			valueText.setText(header.getValue());
		} else {
			valueText.setText("");
		}

		MaskatElement parent = header.getParent();
		if (parent instanceof Event) {
			lastStateGlobalButton = false;

		} else {
			lastStateGlobalButton = true;
		}

		globalButton.setSelection(lastStateGlobalButton);

		setStaleFlag(false);
	}

	public void setHeader(Header header) {
		this.header = header;
	}

	public void update() {
		if (header.getName() != null) {
			nameText.setText(header.getName());
		} else {
			nameText.setText("");
		}

		if (header.getValue() != null) {
			valueText.setText(header.getValue());
		} else {
			valueText.setText("");
		}

		MaskatElement parent = header.getParent();
		if (parent instanceof Event) {
			lastStateGlobalButton = false;
			globalButton.setSelection(false);
		} else {
			lastStateGlobalButton = true;
			globalButton.setSelection(true);
		}

		setDirtyFlag(false);
	}

	private void updateTreeViewer() {
		ITreeNode treeNode = EventPropertiesMasterDetailsBlock.getTreeNode(
				header, HeaderTreeNode.class);
		if (treeNode != null) {
			masterBlockTreeViewer.update(treeNode, null);
			masterBlockTreeViewer.setSelection(
					new StructuredSelection(treeNode), true);
		}
	}

	public void setEvent(Event event) {
		this.event = event;
	}

	private int showOptionsDialog() {
		return OptionMessageDialog
				.open(
						"HeaderDetails.GlobalToLocal",
						Display.getCurrent().getActiveShell(),
						DIALOG_TITLE,
						null,
						DIALOG_MESSAGE,
						DIALOG_OPTIONS,
						DIALOG_OPTIONS_EXPLANATIONS,
						MessageDialog.QUESTION,
						new String[] {
								Messages
										.getString("headerDetails.optionDialog.ok"), //$NON-NLS-1$
								Messages
										.getString("headerDetails.optionDialog.cancel") }, 0); //$NON-NLS-1$
	}
}
