/*
 * 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.editors.layout.outline;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.ContextMenuProvider;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartViewer;
import org.eclipse.gef.GraphicalEditPart;
import org.eclipse.gef.GraphicalViewer;
import org.eclipse.gef.RootEditPart;
import org.eclipse.gef.ui.actions.ActionRegistry;
import org.eclipse.gef.ui.actions.GEFActionConstants;
import org.eclipse.gef.ui.actions.UpdateAction;
import org.eclipse.gef.ui.parts.ContentOutlinePage;
import org.eclipse.gef.ui.parts.TreeViewer;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.actions.ActionFactory;
import org.eclipse.ui.part.IPageSite;

import org.maskat.core.layout.AbstractContainer;
import org.maskat.core.layout.DivSplit;
import org.maskat.core.layout.TabItem;
import org.maskat.ui.MaskatUIPlugin;
import org.maskat.ui.Messages;
import org.maskat.ui.editors.layout.LayoutGraphicalEditor;
import org.maskat.ui.editors.layout.editparts.ComboItemEditPart;
import org.maskat.ui.editors.layout.editparts.DivSplitEditPart;
import org.maskat.ui.editors.layout.editparts.IdDirectEditable;
import org.maskat.ui.editors.layout.editparts.SplitterEditPart;
import org.maskat.ui.editors.layout.editparts.TabEditPart;
import org.maskat.ui.editors.layout.editparts.TabFolderEditPart;
import org.maskat.ui.editors.layout.editparts.TabItemEditPart;
import org.maskat.ui.editors.layout.figures.SplitterFigure;
import org.maskat.ui.editors.layout.figures.TabFolderFigure;
import org.maskat.ui.editors.layout.models.TabDef;
import org.maskat.ui.editors.layout.tools.IdDirectEditmanger;
import org.maskat.ui.editors.layout.tools.TextCellEditorLocator;

public class LayoutOutLinePage extends ContentOutlinePage implements
	ISelectionChangedListener, IAdaptable {
	
	public static final String EDITOR_ID = MaskatUIPlugin.PLUGIN_ID
			+ ".outlinePage"; //$NON-NLS-1$	

	private LayoutGraphicalEditor editor;
	
	private EditNameAction directEdit;
	
	private ISelection selection = null;
	
	public LayoutOutLinePage(LayoutGraphicalEditor editor) {
		super(new TreeViewer());
		this.editor = editor;
	}

	public void init(IPageSite pageSite) {
		super.init(pageSite);
		ActionRegistry registry = (ActionRegistry) editor.getAdapter(ActionRegistry.class);
		IActionBars bars = pageSite.getActionBars();
		String delId = ActionFactory.DELETE.getId();
		String undoId = ActionFactory.UNDO.getId();
		String redoId = ActionFactory.REDO.getId();
		bars.setGlobalActionHandler(delId, registry.getAction(delId));
		bars.setGlobalActionHandler(undoId, registry.getAction(undoId));
		bars.setGlobalActionHandler(redoId, registry.getAction(redoId));
		bars.updateActionBars();
		directEdit = new EditNameAction();
	}

	private class EditNameAction extends Action {
		
		public EditNameAction() {
			super.setText(Messages.getString(
					"layout.cmd.rename.msg.title")); //$NON-NLS-1$
		}
		
		public boolean canEdit() {
			if (selection instanceof StructuredSelection) {
				StructuredSelection sel = (StructuredSelection) selection;
				if (sel != null && !sel.isEmpty() && sel.getFirstElement() instanceof EditPart) {
					OutLineTreeEditPart editPart = (OutLineTreeEditPart) sel.getFirstElement();
					if (editPart.getWidget() instanceof TreeItem) {
						GraphicalEditPart layoutEditpart = (GraphicalEditPart) editPart.getLayoutEditPart();
						if (layoutEditpart != null && !(layoutEditpart instanceof ComboItemEditPart) 
								&& layoutEditpart.getParent() != null &&
									layoutEditpart.getAdapter(IdDirectEditable.class) != null) {
							return true;
						}
					}
				}
			}
			return false;
		}

		public void run() {
			if (canEdit()) {
				StructuredSelection sel = (StructuredSelection) selection;
				OutLineTreeEditPart editPart = (OutLineTreeEditPart) sel.getFirstElement();				
				org.eclipse.swt.graphics.Rectangle rec = ((TreeItem) editPart.getWidget()).getBounds();
				Rectangle area = new Rectangle(rec.x, rec.y, rec.width, rec.height);
				GraphicalEditPart layoutEditpart = (GraphicalEditPart) editPart.getLayoutEditPart();
				if (layoutEditpart != null && !(layoutEditpart instanceof ComboItemEditPart) 
						&& layoutEditpart.getParent() != null && layoutEditpart.getAdapter(IdDirectEditable.class) != null) {
					new IdDirectEditmanger(layoutEditpart, (Composite) getViewer().getControl(), 
							new TextCellEditorLocator(area)).show();
				}			
			}
		}
	}
	
	public void createControl(Composite parent) {
		super.createControl(parent);
		EditPartViewer viewer = getViewer();
		GraphicalViewer gviewer = (GraphicalViewer) editor.getAdapter(GraphicalViewer.class);				
		viewer.setEditDomain(gviewer.getEditDomain());
		
		EditPart editPart = gviewer.getRootEditPart();
		viewer.setEditPartFactory(new OutLineTreeEditPartFactory(gviewer));
		
		ActionRegistry registry = (ActionRegistry) editor.getAdapter(ActionRegistry.class);
		ContextMenuProvider provider = new OutlineContextMenuProvider(viewer, registry);
		viewer.setContextMenu(provider);
		viewer.setContents(getRootModel(editPart));
		viewer.addSelectionChangedListener(this);
	}

	public void update() {
		GraphicalViewer gviewer = (GraphicalViewer) editor.getAdapter(GraphicalViewer.class);			
		getViewer().setContents(getRootModel(gviewer.getRootEditPart()));
	}
	
	private class OutlineContextMenuProvider extends ContextMenuProvider {
		private ActionRegistry actionRegistry;

		public OutlineContextMenuProvider(EditPartViewer viewer, ActionRegistry registry) {
			super(viewer);
			actionRegistry = registry;
		}

		public void buildContextMenu(IMenuManager menu) {
			updateDeleteActions(actionRegistry);
			GEFActionConstants.addStandardActionGroups(menu);
			IAction undoAction = actionRegistry.getAction(ActionFactory.UNDO.getId());
			menu.appendToGroup(GEFActionConstants.GROUP_EDIT, undoAction);
			IAction redoAction = actionRegistry.getAction(ActionFactory.REDO.getId());
			menu.appendToGroup(GEFActionConstants.GROUP_EDIT, redoAction);			
			menu.appendToGroup(GEFActionConstants.GROUP_EDIT, new Separator());
			IAction delAction = actionRegistry.getAction(ActionFactory.DELETE.getId());
			menu.appendToGroup(GEFActionConstants.GROUP_EDIT, delAction);

			if (directEdit.canEdit()) {
				menu.add(directEdit);
			}
		}
	}
	
	private void updateDeleteActions(ActionRegistry registry) {
		IAction delAction = registry.getAction(ActionFactory.DELETE.getId());
		if (delAction instanceof UpdateAction) {
			((UpdateAction) delAction).update();
		}
		IAction undoAction = registry.getAction(ActionFactory.UNDO.getId());
		if (undoAction instanceof UpdateAction) {
			((UpdateAction) undoAction).update();
		}
		IAction redoAction = registry.getAction(ActionFactory.REDO.getId());
		if (redoAction instanceof UpdateAction) {
			((UpdateAction) redoAction).update();
		}
	}
	
	private Object getRootModel(EditPart parentElement) {
		List partList = parentElement.getChildren();
		if (partList.size() > 0) {
			Object model = ((EditPart) partList.get(0)).getModel();
			AbstractContainer root = new AbstractContainer() {};
			root.addChild(model);
			return root;
		}
		return null;
	}
	
	public EditPartViewer getViewer() {
		return super.getViewer();
	}

	private EditPart beforeSelectionEditPart = null;
	private long beforeSelectionTime = 0;
	
	public void selectionChanged(SelectionChangedEvent event) {
		selection = event.getSelection();
		if (directEdit.canEdit()) {
			
		}
		
		if (selection instanceof StructuredSelection) {
			StructuredSelection sel = (StructuredSelection) selection;
			if (sel != null && !sel.isEmpty() && sel.getFirstElement() instanceof EditPart) {
				OutLineTreeEditPart editPart = (OutLineTreeEditPart) sel.getFirstElement();

				if (editPart.getLayoutEditPart() == null) {
					GraphicalViewer gviewer = (GraphicalViewer) editor.getAdapter(GraphicalViewer.class);
					List list = gviewer.getSelectedEditParts();
					if (list.size() == 1 && list.get(0) instanceof TabEditPart) {
						TabEditPart tabPart = (TabEditPart) list.get(0);
						TabDef def = (TabDef) tabPart.getModel();
						EditPart part = findOutLineEidtPart(getViewer().getRootEditPart(), def.getModel());
//						TabItem item = (TabItem) tabPart.getModel();
//						EditPart part = findOutLineEidtPart(getViewer().getRootEditPart(), item);
						if (part != null) {
							getViewer().select(part);
						}
					}
				}
				if (beforeSelectionEditPart == editPart && sel.size() == 1 &&
						System.currentTimeMillis() - beforeSelectionTime <= 200) {
					if (directEdit.canEdit()) {
						directEdit.run();
					}
				} else {
					selectedEditPart(editPart);
				}
				beforeSelectionEditPart = editPart;
				beforeSelectionTime = System.currentTimeMillis();
			}
		}
	}
	
	private EditPart findOutLineEidtPart(EditPart parent, Object model) {
		if (!(parent instanceof RootEditPart)) {
			if (parent.getModel() == model) {
				return parent;
			}
		}
		List partList = parent.getChildren();
		for (int i = 0; i < partList.size(); i++) {
			EditPart part = findOutLineEidtPart((EditPart) partList.get(i), model);
			if (part != null) {
				return part;
			}
		}
		return null;
	}
	
	private void selectedEditPart(OutLineTreeEditPart editPart) {
		ArrayList list = new ArrayList();
		
		EditPart p = editPart;
		while (p != null && !(p instanceof RootEditPart)) {
			list.add(p);
			p = p.getParent();
		}
		for (int i = list.size() - 1; i >= 0; i--) {
			OutLineTreeEditPart tree = (OutLineTreeEditPart) list.get(i);
			EditPart layoutEditPart = tree.getLayoutEditPart();
			
			if (layoutEditPart instanceof TabItemEditPart) {
				TabItem item = (TabItem) layoutEditPart.getModel();
//				TabEditPart tabPart = (TabEditPart) tree.getRelationEditPart();
///				TabDef def = (TabDef) tabPart.getModel();
///				TabItem item = (TabItem) tabPart.getModel();
				TabFolderEditPart tabFolder = (TabFolderEditPart) layoutEditPart.getParent();
				TabFolderFigure figure = (TabFolderFigure) tabFolder.getFigure();
				figure.setAllTabPageInvisible();
//				figure.showNamedTabPage(def.getName());
				figure.showNamedTabPage(item.getName());
				
			} else if (layoutEditPart instanceof DivSplitEditPart) {
				SplitterEditPart splitter = (SplitterEditPart) layoutEditPart.getParent();
				DivSplitEditPart divSplit = (DivSplitEditPart) layoutEditPart;
				DivSplit div = (DivSplit) divSplit.getModel();
				((SplitterFigure) splitter.getFigure()).showSplitPage(div.getIdx());
				splitter.doSelected(div.getIdx());
			}
		}
	}

	public Object getAdapter(Class adapter) {
		return editor.getAdapter(adapter);
	}
}
