/*
 * 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.beanwrapper;

import java.util.Iterator;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.viewers.TreeViewer;
import org.maskat.core.event.Bind;
import org.maskat.core.event.Source;
import org.maskat.ui.Messages;
import org.maskat.ui.views.properties.tabbed.command.AddTreeNodeCommand;
import org.maskat.ui.views.properties.tabbed.masterdetails.EventPropertiesMasterDetailsBlock;
import org.maskat.ui.views.properties.tabbed.treenodewrapper.AbstractTreeNode;
import org.maskat.ui.views.properties.tabbed.treenodewrapper.ITreeNode;

public class SourceNode extends AbstractTreeNode {
	
	private static final String MULTI_LABEL =
		Messages.getString("sourceNode.multiValueLabel"); //$NON-NLS-1$		

	private static final String SINGLE_LABEL =
		Messages.getString("sourceNode.singleValueLabel"); //$NON-NLS-1$		

	private static final String ADD_SOURCE_CHILD_NODE =
		Messages.getString("sourceNode.addSourceChildNode"); //$NON-NLS-1$

	private static final String ADD_SOURCE_BIND_NODE =
		Messages.getString("sourceNode.addSourceBindNode"); //$NON-NLS-1$

	private static final String ADD_VALIDATION =
		Messages.getString("sourceNode.addValidation"); //$NON-NLS-1$

	
	public SourceNode(Source source)
	{
		super(source);
	}

	protected void loadChildren() {
		Source source = (Source) maskatElement;
		if(source.getChildNode() != null) {
			addChild(new SourceChildNode(source));
		} else {
			Iterator iterator = ((Source) maskatElement).getTypedChildren(Bind.class);
			while (iterator!=null && iterator.hasNext()) {
				addChild(new SourceBind((Bind)iterator.next()));
			}
		}
		if(source.getType() != null) {
			addChild(new Validation(source));
		}
	}
	
	/**update the source bean when remove child*/
	public void removeChild(ITreeNode child) {
		super.removeChild(child);
		if (child instanceof Validation) {
			((Source) maskatElement).setType(null);
			((Source) maskatElement).setDesc(null);
			((Source) maskatElement).setMin(Source.MIN_DEFAULT);
			((Source) maskatElement).setMax(Source.MAX_DEFAULT);
			((Source) maskatElement).setRegexp(null);
		}else if (child instanceof SourceChildNode) {
			((Source) maskatElement).setChildNode(null);
			moveSourceBindNodes(child, this);
		}else if (child instanceof SourceBind) {
			((Source) maskatElement).removeChild(child.getModel());
		}
	}
	
	/**add the model relation when add child*/
	public void addChild(ITreeNode child) {
		super.addChild(child);
		if (child instanceof Validation) {
			if (((Source) maskatElement).getType() == null) {
				((Source) maskatElement).setType("");
			}
		}else if (child instanceof SourceChildNode) {
			if (((Source) maskatElement).getChildNode() == null) {
				((Source) maskatElement).setChildNode("");
			}
			moveSourceBindNodes(this, child);
			
			((Source) maskatElement).setFromkey(-1);
			
		}else if (child instanceof SourceBind) {
			maskatElement.addChild(child.getModel());
			if (containsChild(SourceChildNode.class)) {
				moveSourceBindNodes(this, getSourceChildNode());
			}
			
			((Source) maskatElement).setFromkey(-1);
		}
	}
	
	private ITreeNode getSourceChildNode() {
		Object[] children = getChildren();
		for (int i=0; i<children.length; i++) {
			if (children[i] instanceof SourceChildNode) {
				return (ITreeNode)children[i];
			}
		}
		return null;
	}
	
	private void moveSourceBindNodes(ITreeNode oldParent, ITreeNode newParent) {
		Object[] sourceBinds = oldParent.getChildren();
		for (int i=0; i<sourceBinds.length; i++) {
			if (sourceBinds[i] instanceof SourceBind) {
				oldParent.removeChild((ITreeNode)sourceBinds[i]);
				if (!sameBindExists(newParent, (ITreeNode)sourceBinds[i])) {
					newParent.addChild((ITreeNode)sourceBinds[i]);
				}
				//always add bind, cause maybe the bind was removed by oldParent.
				maskatElement.addChild(((ITreeNode)sourceBinds[i]).getModel());
			}
		}
	}
	
	private boolean sameBindExists(ITreeNode parent, ITreeNode child) {
		Object[] children = parent.getChildren();
		for (int i=0; i<children.length; i++) {
			if (((ITreeNode)children[i]).getModel() == child.getModel()) {
				return true;
			}
		}
		return false;
	}

	public String getDisplayText() {
		
		Source source = ((Source) maskatElement);
		
		if( source.getNode() == null  || source.getNode().length() == 0) {
			
			if (source.getChildNode() != null || source.getBindsIt() != null) { // && source.getBindsIt().hasNext()) ) {
				return MULTI_LABEL;
			} else {
				return SINGLE_LABEL;
			}
		} else if (source.getChildNode() != null || source.getBindsIt() != null) {
			return source.getNode() + " " + MULTI_LABEL;
		} else {
			return source.getNode() + " " + SINGLE_LABEL;
		}
	}
	
	public IMenuManager fillContextMenu(final TreeViewer treeViewer, IMenuManager manager) {
		final ITreeNode node = this;
		final Source source = (Source)maskatElement;
		if (!node.containsChild(SourceChildNode.class)) {
			manager.add(new Action(ADD_SOURCE_CHILD_NODE){
				public void run() {
					source.setChildNode("");
					ITreeNode childNode = new SourceChildNode(source);
					EventPropertiesMasterDetailsBlock.executeCommand(new AddTreeNodeCommand(treeViewer,node,childNode));
				}
			});
		}
		if (!node.containsChild(SourceChildNode.class)) {
			manager.add(new Action(ADD_SOURCE_BIND_NODE){
				public void run() {
					Bind bind = new Bind();
					ITreeNode childNode = new SourceBind(bind);
					EventPropertiesMasterDetailsBlock.executeCommand(new AddTreeNodeCommand(treeViewer,node,childNode));					
				}
			});	
		}
		if (!node.containsChild(Validation.class)) {
			manager.add(new Action(ADD_VALIDATION){
				public void run() {
					source.setType("");
					ITreeNode childNode = new Validation(source);
					EventPropertiesMasterDetailsBlock.executeCommand(new AddTreeNodeCommand(treeViewer,node,childNode));					
				}
			});
		}
		return super.fillContextMenu(treeViewer, manager);
	}
	
	public boolean isCopiable() {
		return true;
	}
	
	public boolean canPasteTo(ITreeNode parent) {
		return (parent != null && parent instanceof ParamTreeNode) ? true : false;
	}
}
