/******************************************************************************
 * Copyright (c) 2006, Intalio Inc.
 * 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:
 *     Intalio Inc. - initial API and implementation
 *******************************************************************************/

/** 
 * Date          	Author             Changes 
 * 27 Oct 2006   	BIlchyshyn         Created
 **/

package org.eclipse.stp.bpmn.tools;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.gef.EditPart;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.stp.bpmn.Activity;
import org.eclipse.stp.bpmn.ActivityType;
import org.eclipse.stp.bpmn.diagram.edit.parts.Activity2EditPart;
import org.eclipse.stp.bpmn.diagram.edit.parts.ActivityEditPart;
import org.eclipse.stp.bpmn.diagram.edit.parts.PoolEditPart;
import org.eclipse.stp.bpmn.diagram.edit.parts.SubProcessEditPart;

public class EdgeConnectionValidator implements ConnectionValidator {
	public boolean canStart(EditPart sourceEditPart) {
		if (sourceEditPart instanceof ActivityEditPart) {
			EObject element = ((Node) sourceEditPart.getModel()).getElement();
			int activityType = ((Activity) element).getActivityType().getValue();
			
			//sequence connection can't start from end events
			switch (activityType) {
            case ActivityType.EVENT_END_COMPENSATION:
            case ActivityType.EVENT_END_EMPTY:
            case ActivityType.EVENT_END_ERROR:
            case ActivityType.EVENT_END_MESSAGE:
            case ActivityType.EVENT_END_TERMINATE:
            	return false;
            case ActivityType.GATEWAY_DATA_BASED_EXCLUSIVE:
            case ActivityType.GATEWAY_DATA_BASED_INCLUSIVE:
            case ActivityType.GATEWAY_EVENT_BASED_EXCLUSIVE:
            case ActivityType.GATEWAY_PARALLEL:
            	if ((((ActivityEditPart) sourceEditPart).getSourceConnections().size() > 0)
                        && (((ActivityEditPart) sourceEditPart).getTargetConnections().size() > 1)) {
                    /*
                     * the gateway is marging and it can't have
                     * more than 1 outgoing sequence edge
                     */
                    return false;
                }
            default:
                break;
            }
		}
		
		return true;
	}
	
	public boolean canEnd(EditPart targetEditPart) {
		if (targetEditPart instanceof ActivityEditPart) {
			EObject element = ((Node) targetEditPart.getModel()).getElement();
			int activityType = ((Activity) element).getActivityType().getValue();
			
			//sequence connections can't end on start events
			switch (activityType) {
			case ActivityType.EVENT_START_EMPTY:
            case ActivityType.EVENT_START_MESSAGE:
            case ActivityType.EVENT_START_RULE:
            	return false;
            case ActivityType.GATEWAY_DATA_BASED_EXCLUSIVE:
            case ActivityType.GATEWAY_DATA_BASED_INCLUSIVE:
            case ActivityType.GATEWAY_EVENT_BASED_EXCLUSIVE:
            case ActivityType.GATEWAY_PARALLEL:
            	if ((((ActivityEditPart) targetEditPart).getSourceConnections().size() > 1)
                        && (((ActivityEditPart) targetEditPart).getTargetConnections().size() > 0)) {
                    /*
                     * the gateway is forking and it can't have
                     * more than 1 incoming sequence edge
                     */
                    return false;
                }
            default:
                break;
            }
		} else if (targetEditPart instanceof Activity2EditPart) {
			return false;
		}
		
		return true;
	}
	
	public boolean canConnect(EditPart source, EditPart target) {
		if (source.equals(target)) {
			return false;
		}
		if (!canEnd(target)) {
			return false;
		}	
		if (!canStart(source)) {
			return false;
		}
		if (source instanceof Activity2EditPart) {
			if (!getGraph(source).equals(getGraph(target)) && !(getGraph(getGraph(source)).equals(getGraph(target)))) {
				return false;
			}
			if (getGraph(source).equals(target)) {
				return false;
			}
		} else if (!getGraph(source).equals(getGraph(target))) {
			return false;
		}
		
		return true;
	}
	
	protected EditPart getGraph(EditPart ep) {
    	if (ep instanceof PoolEditPart) {
			return ep;
		}
    	
    	EditPart parent = ep.getParent();
    	
    	while (!(parent instanceof PoolEditPart)) {
    		if (parent instanceof SubProcessEditPart) {
				break;
			}
			parent = parent.getParent();
		}
    	
    	return parent;
    }
}
