//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 IBM Corporation and others.
// 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:
// IBM Corporation - initial implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.authoring.ui.properties;

import java.io.File;
import java.util.Iterator;

import org.eclipse.epf.authoring.ui.AuthoringUIImages;
import org.eclipse.epf.authoring.ui.AuthoringUIResources;
import org.eclipse.epf.authoring.ui.editors.MethodElementEditor;
import org.eclipse.epf.authoring.ui.forms.MethodFormToolkit;
import org.eclipse.epf.authoring.ui.richtext.IMethodRichText;
import org.eclipse.epf.authoring.ui.richtext.IMethodRichTextEditor;
import org.eclipse.epf.common.utils.StrUtil;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.edit.command.IActionManager;
import org.eclipse.epf.library.util.ResourceHelper;
import org.eclipse.epf.richtext.RichTextListener;
import org.eclipse.epf.uma.BreakdownElement;
import org.eclipse.epf.uma.BreakdownElementDescription;
import org.eclipse.epf.uma.ContentDescription;
import org.eclipse.epf.uma.UmaPackage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.events.HyperlinkAdapter;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ImageHyperlink;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;


/**
 * The breakdown element documentation section
 * 
 * @author Shilpa Toraskar
 * @author Kelvin Low
 * @since 1.0
 */
public class BreakdownElementDocumentSection extends AbstractSection {

	// controls
	protected Text prefixText;

	protected Text briefDescText;

	protected FormToolkit toolkit;

	protected Section documentSection;

	protected Composite documentComposite;

	protected Composite expandDocumentComposite;

	protected IMethodRichTextEditor ctrl_document_expanded;

	protected IMethodRichText usageGuidance;

	protected IMethodRichText keyConsiderations;

	protected Text ctrl_document_expanded_Text;

	protected ImageHyperlink expandDocumentLink;

	protected Label expandDocumentLabel;

	protected boolean expandFlag = false;

	protected boolean expandFlagText = false;

	protected IMethodRichText activeControl;

	protected Text activeControlText;

	// element
	protected BreakdownElement element;

	// action manager
	protected IActionManager actionMgr;

	// modify listener
	protected ModifyListener modelModifyListener;

	protected ModifyListener contentModifyListener;

	protected String contentElementPath;

	protected String type = ""; //$NON-NLS-1$

	protected String contentElementName = ""; //$NON-NLS-1$

	protected int heightHint = 40;

	private Listener usageGuidanceListener = new Listener() {
		public void handleEvent(Event e) {
			element = (BreakdownElement) getElement();
			IMethodRichText control = expandFlag ? ctrl_document_expanded
					: usageGuidance;
			if (!control.getModified()) {
				return;
			}
			String oldContent = ((BreakdownElementDescription) element
					.getPresentation()).getUsageGuidance();
			if (((MethodElementEditor) getEditor()).mustRestoreValue(
					usageGuidance, oldContent)) {
				return;
			}
			String newContent = control.getText();
			if (!newContent.equals(oldContent)) {
				actionMgr.doAction(IActionManager.SET, element
						.getPresentation(), UmaPackage.eINSTANCE
						.getBreakdownElementDescription_UsageGuidance(),
						newContent, -1);
			}
		}
	};

	private Listener keyConsiderationsListener = new Listener() {
		public void handleEvent(Event e) {
			element = (BreakdownElement) getElement();
			IMethodRichText control = expandFlag ? ctrl_document_expanded
					: keyConsiderations;
			if (!control.getModified()) {
				return;
			}
			String oldContent = ((ContentDescription) element.getPresentation())
					.getKeyConsiderations();
			if (((MethodElementEditor) getEditor()).mustRestoreValue(
					keyConsiderations, oldContent)) {
				return;
			}
			String newContent = control.getText();
			if (!newContent.equals(oldContent)) {
				actionMgr.doAction(IActionManager.SET, element
						.getPresentation(), UmaPackage.eINSTANCE
						.getContentDescription_KeyConsiderations(), newContent,
						-1);
			}
		}
	};

	protected void init() {
		// get BreakdownElement object
		element = (BreakdownElement) getElement();

		// get toolkit
		toolkit = getWidgetFactory();

		// get action manager
		actionMgr = EPFPropertySheetPage.getActionManager();

		// set content element path
		String libPath = LibraryService.getInstance().getCurrentMethodLibraryPath();
		contentElementPath = libPath + File.separator
				+ ResourceHelper.getElementPath(element);
	}

	/**
	 * @see org.eclipse.wst.common.ui.properties.ITabbedPropertySection#createControls(Composite,
	 *      TabbedPropertySheetPage)
	 */
	public void createControls(Composite parent,
			TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		init();

		parent.setLayout(new GridLayout());
		parent.setLayoutData(new GridData(GridData.FILL_BOTH));

		// create Docment section
		createDocumentSection(parent);

		// add listeners
		addListeners();

		// update controls
		updateControls();
	}

	protected void addListeners() {

		prefixText.addFocusListener(new FocusAdapter() {
			public void focusGained(FocusEvent e) {
				((MethodElementEditor) getEditor()).setCurrentFeatureEditor(e.widget,
						UmaPackage.eINSTANCE.getBreakdownElement_Prefix());
			}

			public void focusLost(FocusEvent e) {
				element = (BreakdownElement) getElement();
				String oldContent = element.getPrefix();
				if (((MethodElementEditor) getEditor()).mustRestoreValue(
						prefixText, oldContent)) {
					return;
				}
				String newContent = StrUtil.getPlainText(prefixText.getText());
				if (!newContent.equals(oldContent)) {
					boolean status = actionMgr.doAction(IActionManager.SET,
							element, UmaPackage.eINSTANCE
									.getBreakdownElement_Prefix(), newContent,
							-1);
					if (status) {
						prefixText.setText(newContent);
					}
				}
			}
		});

		briefDescText.addFocusListener(new FocusAdapter() {
			public void focusGained(FocusEvent e) {
				((MethodElementEditor) getEditor()).setCurrentFeatureEditor(e.widget,
						UmaPackage.eINSTANCE.getMethodElement_BriefDescription());
			}

			public void focusLost(FocusEvent e) {
				element = (BreakdownElement) getElement();
				String oldContent = element.getBriefDescription();
				if (((MethodElementEditor) getEditor()).mustRestoreValue(
						briefDescText, oldContent)) {
					return;
				}
				String newContent = StrUtil.getPlainText(briefDescText
						.getText());
				if (!newContent.equals(oldContent)) {
					boolean status = actionMgr.doAction(IActionManager.SET,
							element, UmaPackage.eINSTANCE
									.getMethodElement_BriefDescription(),
							newContent, -1);
					if (status) {
						briefDescText.setText(newContent);
					}
				}
			}
		});

		BreakdownElement element = getElement();
		
		usageGuidance.setModalObject(element);
		usageGuidance.setModalObjectFeature(UmaPackage.eINSTANCE.getBreakdownElementDescription_UsageGuidance());
		usageGuidance.addListener(SWT.Deactivate, usageGuidanceListener);
		
		keyConsiderations.setModalObject(element);
		keyConsiderations.setModalObjectFeature(UmaPackage.eINSTANCE.getContentDescription_KeyConsiderations());
		keyConsiderations
				.addListener(SWT.Deactivate, keyConsiderationsListener);
	}

	protected void createDocumentSection(Composite composite) {
		int horizontalSpan = 2;

		// create document section
		documentSection = FormUI
				.createSection(
						toolkit,
						composite,
						PropertiesResources.Process_DocumentInformationTitle, //$NON-NLS-1$
						PropertiesResources.bind(PropertiesResources.Process_documentInformationDescription, PropertiesUtil.getTypeLower(element))); 

		// create document composite
		documentComposite = FormUI.createComposite(toolkit, documentSection, 3,
				false);

		// prefix
		FormUI.createLabel(toolkit, documentComposite, PropertiesResources.Process_prefix, horizontalSpan); //$NON-NLS-1$
		prefixText = FormUI.createText(toolkit, documentComposite, heightHint);

		// brief description
		FormUI.createLabel(toolkit, documentComposite, PropertiesResources.Process_briefDescription, horizontalSpan); //$NON-NLS-1$
		briefDescText = FormUI.createText(toolkit, documentComposite,
				heightHint);

		// create usage guidance
		ImageHyperlink link = FormUI.createImageHyperLink(toolkit,
				documentComposite, AuthoringUIImages.IMG_COLLAPSED,
				AuthoringUIResources.openRTE); 
		link
				.setData(
						"Title", PropertiesResources.Process_usageGuidance); 
		addHyperLinkListener(link);

		FormUI.createLabel(toolkit, documentComposite, PropertiesResources.Process_usageGuidance); //$NON-NLS-1$
		usageGuidance = FormUI.createRichText(toolkit, documentComposite,
				heightHint, contentElementPath, element);
		link.setHref(usageGuidance);

		// create key considerations
		link = FormUI.createImageHyperLink(toolkit, documentComposite,
				AuthoringUIImages.IMG_COLLAPSED, AuthoringUIResources.openRTE); //$NON-NLS-1$
		link
				.setData(
						"Title", PropertiesResources.BreakdownElement_keyConsiderations); 
		addHyperLinkListener(link);

		FormUI.createLabel(toolkit, documentComposite, PropertiesResources.BreakdownElement_keyConsiderations); //$NON-NLS-1$
		keyConsiderations = FormUI.createRichText(toolkit, documentComposite,
				heightHint, contentElementPath, element);
		link.setHref(keyConsiderations);

		// create expanded composite
		expandDocumentComposite = FormUI.createComposite(toolkit,
				documentSection, 2, true);

		// Hyperlink desc
		expandDocumentLink = FormUI.createImageHyperLink(toolkit,
				expandDocumentComposite, AuthoringUIImages.IMG_EXPANDED,
				AuthoringUIResources.closeRTE); 
		addHyperLinkListener(expandDocumentLink);

		// expand label
		expandDocumentLabel = toolkit.createLabel(expandDocumentComposite, ""); //$NON-NLS-1$
	}

	protected void addHyperLinkListener(ImageHyperlink link) {
		link.addHyperlinkListener(new HyperlinkAdapter() {
			public void linkActivated(HyperlinkEvent e) {
				toggle(e);
			}
		});
	}

	protected IMethodRichTextEditor toggle(HyperlinkEvent e) {
		IMethodRichText ctrl = (IMethodRichText) e.getHref();
		if (ctrl_document_expanded == null) {
			ctrl_document_expanded = MethodFormToolkit.createRichTextEditor(
					toolkit, expandDocumentComposite,
					"", SWT.MULTI | SWT.WRAP, contentElementPath, element); //$NON-NLS-1$
			{
				GridData gridData = new GridData(GridData.FILL_BOTH);
				gridData.heightHint = 400;
				gridData.horizontalSpan = 2;
				ctrl_document_expanded.setLayoutData(gridData);
			}

			ctrl_document_expanded.addModifyListener(contentModifyListener);
		}

		if (expandFlag) {
			documentComposite.setVisible(true);
			documentSection.setClient(documentComposite);

			expandDocumentComposite.setVisible(false);

			ctrl = getActiveRichTextControl();
			ctrl.setText(ctrl_document_expanded.getText());

			for (Iterator i = ctrl.getListeners(); i.hasNext();) {
				RichTextListener listener = (RichTextListener) i.next();
				ctrl_document_expanded.removeListener(listener.getEventType(),
						listener.getListener());
			}

			if (ctrl_document_expanded.getModified()) {
				((MethodElementEditor) getEditor())
						.saveModifiedRichText(ctrl_document_expanded);
			}

			ctrl.setFocus();
		} else {
			// expanded
			documentComposite.setVisible(false);
			documentSection.setClient(expandDocumentComposite);

			expandDocumentComposite.setVisible(true);

			setActiveRichTextControl(ctrl);
			ctrl_document_expanded.setText(ctrl.getText());
			ctrl_document_expanded.setModalObject(ctrl.getModalObject());
			ctrl_document_expanded.setModalObjectFeature(ctrl
					.getModalObjectFeature());

			for (Iterator i = ctrl.getListeners(); i.hasNext();) {
				RichTextListener listener = (RichTextListener) i.next();
				ctrl_document_expanded.addListener(listener.getEventType(),
						listener.getListener());
			}

			expandDocumentLabel.setText((String) ((ImageHyperlink) e
					.getSource()).getData("Title")); //$NON-NLS-1$
		}

		documentSection.layout(true);

		// set editable
		if (ctrl_document_expanded != null)
			ctrl_document_expanded.setEditable(editable);

		expandFlag = !expandFlag;
		return ctrl_document_expanded;
	}

	/*
	 * @see org.eclipse.wst.common.ui.properties.view.ITabbedPropertySection#refresh()
	 */
	public void refresh() {
		try {
			if (getElement() instanceof BreakdownElement) {
				((MethodElementEditor) getEditor()).saveModifiedRichText();

				element = (BreakdownElement) getElement();
				BreakdownElementDescription content = (BreakdownElementDescription) element
						.getPresentation();

				// update section name
				documentSection
						.setDescription(PropertiesResources.bind(PropertiesResources.Process_documentInformationDescription, PropertiesUtil.getTypeLower(element))); 

				if (modelModifyListener != null) {
					prefixText.removeModifyListener(modelModifyListener);
					briefDescText.removeModifyListener(modelModifyListener);
				}

				if (contentModifyListener != null) {
					usageGuidance.removeModifyListener(contentModifyListener);
					keyConsiderations
							.removeModifyListener(contentModifyListener);
				}

				modelModifyListener = getEditor().createModifyListener(element);
				contentModifyListener = getEditor().createModifyListener(
						element.getPresentation());

				if (modelModifyListener != null
						&& modelModifyListener instanceof MethodElementEditor.ModifyListener) {
					((MethodElementEditor.ModifyListener) modelModifyListener)
							.setElement(element);
					((MethodElementEditor.ModifyListener) modelModifyListener)
							.setDisable(true);
				}

				if (contentModifyListener != null
						&& contentModifyListener instanceof MethodElementEditor.ModifyListener) {
					((MethodElementEditor.ModifyListener) contentModifyListener)
							.setElement(element.getPresentation());
					((MethodElementEditor.ModifyListener) contentModifyListener)
							.setDisable(true);
				}

				prefixText.setText(element.getPrefix());
				briefDescText.setText(element.getBriefDescription());

				usageGuidance.setText(content.getUsageGuidance());
				keyConsiderations.setText(content.getKeyConsiderations());

				if (expandFlag) {
					if (expandDocumentLabel.getText().equals(
							PropertiesResources.Process_usageGuidance)) //$NON-NLS-1$
					{
						ctrl_document_expanded.setText(content
								.getUsageGuidance());
						ctrl_document_expanded.setSelection(0);
						ctrl_document_expanded.setModalObject(content);
						ctrl_document_expanded
								.setModalObjectFeature(UmaPackage.eINSTANCE
										.getBreakdownElementDescription_UsageGuidance());
					} else if (expandDocumentLabel
							.getText()
							.equals(
									PropertiesResources.BreakdownElement_keyConsiderations)) //$NON-NLS-1$
					{
						ctrl_document_expanded.setText(content
								.getKeyConsiderations());
						ctrl_document_expanded.setModalObject(content);
						ctrl_document_expanded
								.setModalObjectFeature(UmaPackage.eINSTANCE
										.getContentDescription_KeyConsiderations());
					}
				}

				updateControls();

				if (modelModifyListener instanceof MethodElementEditor.ModifyListener) {
					((MethodElementEditor.ModifyListener) modelModifyListener)
							.setDisable(false);
				}
				if (contentModifyListener instanceof MethodElementEditor.ModifyListener) {
					((MethodElementEditor.ModifyListener) contentModifyListener)
							.setDisable(false);
				}

				prefixText.addModifyListener(modelModifyListener);
				briefDescText.addModifyListener(modelModifyListener);

				usageGuidance.setModalObject(content);
				usageGuidance.setModalObjectFeature(UmaPackage.eINSTANCE
						.getBreakdownElementDescription_UsageGuidance());
				usageGuidance.addModifyListener(contentModifyListener);

				keyConsiderations.setModalObject(content);
				keyConsiderations.setModalObjectFeature(UmaPackage.eINSTANCE
						.getContentDescription_KeyConsiderations());
				keyConsiderations.addModifyListener(contentModifyListener);
			}
		} catch (Exception ex) {
			logger
					.logError(
							"Error refreshing breakdown element documentation section", ex); //$NON-NLS-1$
		}
	}

	protected void updateControls() {
		prefixText.setEditable(editable);
		briefDescText.setEditable(editable);
		usageGuidance.setEditable(editable);
		keyConsiderations.setEditable(editable);
	}

	/**
	 * Sets the active "unexpanded" rich text control.
	 */
	private void setActiveRichTextControl(IMethodRichText ctrl) {
		activeControl = ctrl;
	}

	/**
	 * Returns the active "unexpanded" rich text control.
	 */
	private IMethodRichText getActiveRichTextControl() {
		return activeControl;
	}

}