/*
 * This Umple file modify the following classes:
 * UmpleInternalParser,
 * Transition,
 * Guard,
 * Method,
 * StateMachine
 * State
 * Transition
 * Event
 * MethodParameter
 * Action
 *  */


namespace cruise.umple.compiler;

//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class UmpleInternalParser
{

//----------------------------------------------------------------------------  
//---------------------------------Start--------------------------------------
//----------------------------------------------------------------------------   
  private void copyStateMachinesFromTraiToClass(UmpleClass inClass) {
    Map<UmpleTrait, List<StateMachine>> traiStateMachine = new HashMap<UmpleTrait, List<StateMachine>>();
		Map<UmpleTrait, List<StateMachine>> tempTraiStateMachine = new HashMap<UmpleTrait, List<StateMachine>>();
		for (UmpleTrait uTrait : inClass.getExtendsTraits()) {
			tempTraiStateMachine = gatherStateMachinesFromTrait(uTrait,inClass.getGeneralTPAppliedByName(uTrait.getName()),inClass);
			CheckSMFromTraitIsNotAvaialbleInOtherTraits(traiStateMachine, tempTraiStateMachine, inClass);
			if ( ! getParseResult().getWasSuccess() ) return;
			if (!CheckSMFromTraitIsNotAvaialbleInClass(inClass,tempTraiStateMachine)) return;
			AddStateMachineMapToAnother(traiStateMachine,tempTraiStateMachine);
		}
		for (UmpleTrait t1 : traiStateMachine.keySet()) {
			if (traiStateMachine.get(t1)!=null){
				for (StateMachine sMachine : traiStateMachine.get(t1)) {
					sMachine.setUmpleClass(inClass);
	    		inClass.addStateMachine(sMachine);		
				}
			}
		}
  }
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
  private Map<UmpleTrait, List<StateMachine>> gatherStateMachinesFromTrait (UmpleTrait inTrait,GeneralTPApplied inGTPApplied, UmpleClass inClass) 
  {
    Map<UmpleTrait, List<StateMachine>> traiStateMachine = new HashMap<UmpleTrait, List<StateMachine>>(); 
  	Map<UmpleTrait, List<StateMachine>> tempTraiStateMachine = new HashMap<UmpleTrait, List<StateMachine>>();
  	//----------------------------------------------------------------------------------------
		if (!checkValidityOfSMTemplateSignature(inGTPApplied,inTrait)) return traiStateMachine;
  	//----------------------------------------------------------------------------------------
  	List<StateMachine> lSMachine = new ArrayList<StateMachine>();	  
  	for (StateMachine sMachine : inTrait.getStateMachines()) {
  	 	StateMachine stTemp = ApplyTypeParametersToStateMachine(sMachine,inGTPApplied,inClass, inTrait);
  		if (stTemp!=null)	{
  			ApplyTypeParametersToEventsOfStateMachines(stTemp, inGTPApplied);
  			lSMachine.add(stTemp);
  			}
  	}
  	if (lSMachine.size()>0)traiStateMachine.put(inTrait,lSMachine);
  	//----------------------------------------------------------------------------------------
  	for (UmpleTrait uTrait : inTrait.getExtendsTraits()) {
  		tempTraiStateMachine = gatherStateMachinesFromTrait(uTrait,inTrait.getGeneralTPAppliedByName(uTrait.getName()),inClass);	 
  		if ( ! getParseResult().getWasSuccess() ) return traiStateMachine;
  		if (!CheckSMFromTraitIsNotAvaialbleInOtherTraits(traiStateMachine,tempTraiStateMachine,inTrait)) return traiStateMachine;
  		AddStateMachineMapToAnother(traiStateMachine,tempTraiStateMachine);
  	}
  	return traiStateMachine;
  }
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------  
  private boolean checkValidityOfSMTemplateSignature(GeneralTPApplied inGTPApplied, UmpleTrait inTrait) {
    if (inGTPApplied!=null){
	  	for (StateMachineTemplateSignature smTSignature : inGTPApplied.getStateMachineTemplateSignatures()) {
	  		//checks that the event exists in one of the state machines.
	  		if (smTSignature.getStateMachine().equals("")){
	  			Method method1 = smTSignature.getMethodTemplateSignature().getMethod();
	  			boolean find = false;
	  			for (StateMachine stMachine : inTrait.getStateMachines()){
	  				Event event = stMachine.getEventByMethod(method1);	 				
		 				if(event!=null)			{
		 					find = true;
		 					break;
		 				}
	  			}
	 				if(find==false){
  	 				getParseResult().addErrorMessage(new ErrorMessage(232,inTrait.getPosition(0),inTrait.getName(),method1.getSignature()));	
		 				return false;
	 				}
	  		} else {
		  		StateMachine sm = inTrait.getStateMachine(smTSignature.getStateMachine());
		 			if ( sm == null ){
		 				getParseResult().addErrorMessage(new ErrorMessage(230,inTrait.getPosition(0),inTrait.getName(),smTSignature.getStateMachine()));	
		 				return false;
		 			} if (smTSignature.getMethodTemplateSignature()!=null){
		 				Method method1 = smTSignature.getMethodTemplateSignature().getMethod();
		 				Event event = sm.getEventByMethod(method1);	
		 				if(event==null){
	  	 				getParseResult().addErrorMessage(new ErrorMessage(231,inTrait.getPosition(0),inTrait.getName(),smTSignature.getStateMachine(),method1.getSignature()));	
			 				return false;
		 				}
		 				
		 			}	else {
						 StateMachine smTemp = sm;
						 State tState=null;
						 for (String s : smTSignature.getStates()){
							 tState = smTemp.findState(s, false);
							 if (tState==null){
								 getParseResult().addErrorMessage(new ErrorMessage(230,inTrait.getPosition(0),inTrait.getName(),s));	
				 		 		 return false;
							 } else
								 if(tState.hasNestedStateMachines()){
		 						 smTemp = tState.getNestedStateMachine(0);
		 					 }
						 }				
		 			}
	  		}
	  	}	 
	  	return true;
  	} else return true;
	}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------  

	private StateMachine ApplyTypeParametersToStateMachine(StateMachine inSMachine, GeneralTPApplied inGTPApplied, UmpleClass inClass, UmpleTrait inTrait){
  	StateMachine newSt = inSMachine.clone();
    String track=null;
    String mapped=null;
    Map<String, String> nameMapping = new HashMap<String, String>();
  		if (inGTPApplied!=null){
  			for (StateMachineTemplateSignature smTSignature : inGTPApplied.getStateMachineTemplateSignatures()) {
  				if (smTSignature.getModifier().equals("-")) return null;
  			 	if (smTSignature.getStateMachine().equals("")) break;
  			 	mapped = nameMapping.get(smTSignature.getStateMachine());
  			 	if (mapped==null) mapped = smTSignature.getStateMachine();
  			 	track = smTSignature.getStateMachine();
  			 	if (newSt.getName().equals(mapped)){
    		  	if (smTSignature.getMethodTemplateSignature()!=null){
  						changeEventName(newSt,smTSignature);
  						continue;
  				 	}
  				if (smTSignature.numberOfStates()<=0) {
  					newSt.setName(smTSignature.getAlias());
  					for (State s : newSt.getStates()) s.setStateMachine(newSt);
  					nameMapping.put(track, smTSignature.getAlias());
	 				}else { 
  					StateMachine smTemp = newSt;
  					State tState=null;
  					for (String s : smTSignature.getStates()){
  						track = track+"."+s;
  						mapped = nameMapping.get(track);
  						if (mapped==null) mapped = s;
  						tState = smTemp.findState(mapped, false);
 							if(tState.hasNestedStateMachines()){
		 						smTemp = tState.getNestedStateMachine(0);
		 					}
  					}
  					if (smTemp!=null) {
  						tState.setName(smTSignature.getAlias());	
  						if (tState.hasNestedStateMachines()) {
  							smTemp.setName(smTSignature.getAlias());
  						}
  						nameMapping.put(track, smTSignature.getAlias());
  					}
  				} 					
				}
			}
  		//This code is used to make sure the * pattern for renaming events name applies to all state machines.
  		for (StateMachineTemplateSignature smTSignature : inGTPApplied.getStateMachineTemplateSignatures()) {
  	  	if (smTSignature.getStateMachine().equals("")){
    			if (smTSignature.getMethodTemplateSignature()!=null){
  					changeEventName(newSt,smTSignature);
  					continue;
  				}
  			}
  		}
   	}
  	return newSt;
	}

  
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------  
	private boolean CheckSMFromTraitIsNotAvaialbleInClass(UmpleClass inClass, Map<UmpleTrait, List<StateMachine>> inTempTraiStateMachine){
  	for (UmpleTrait uTrait : inTempTraiStateMachine.keySet()) {
  		List<StateMachine> tListBeRemoved = new ArrayList<StateMachine>();
    	for (StateMachine tSMachine : inTempTraiStateMachine.get(uTrait)) {
				Map<StateMachine,String> listBeRemoved = new HashMap<StateMachine, String>();
				for(StateMachine cSMachine : inClass.getStateMachines()){
					if (compareStateMachineName(cSMachine, tSMachine)){
						getParseResult().addErrorMessage(new ErrorMessage(226,inClass.getPosition(0),tSMachine.getName(),uTrait.getName(),"class",inClass.getName()));
						return false;
					}else {
						if (cSMachine.getName().equals(tSMachine.getName())){
							if (!cSMachine.getStartState().getName().equals(tSMachine.getStartState().getName())){
								listBeRemoved.put(mergeTwoStateMachineWithTheSameNameDifferentInitialState(cSMachine,tSMachine),cSMachine.getName());
								tListBeRemoved.add(tSMachine);
							} else {
							addExtraStatesAndTransitions(cSMachine, tSMachine);	
							}
						}
					}
				}
				for(Map.Entry<StateMachine,String> entry : listBeRemoved.entrySet() ) {
					inClass.removeStateMachine(inClass.getStateMachine(entry.getValue()));
					inClass.addStateMachine(entry.getKey());
				}		
			}
			for(StateMachine stMachine : tListBeRemoved){
				inTempTraiStateMachine.get(uTrait).remove(stMachine);
			}
		}
		return true;
  }
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
	private boolean CheckSMFromTraitIsNotAvaialbleInOtherTraits(Map<UmpleTrait, List<StateMachine>> inTraiStateMachine, Map<UmpleTrait, List<StateMachine>> inTempTraiStateMachine, UmpleClassifier inUmpleClassifier){
  	if (inTraiStateMachine.size()==0){
  		for(UmpleTrait tUTrait : inTempTraiStateMachine.keySet()){
  			inTraiStateMachine.put(tUTrait, inTempTraiStateMachine.get(tUTrait));
  		}
  		return true;
  	}
  	for(UmpleTrait tUTrait : inTempTraiStateMachine.keySet()){
  		List<StateMachine> mustBeRemoved =new ArrayList<StateMachine>();
	 		for (StateMachine tSMachine : inTempTraiStateMachine.get(tUTrait)) {
				for(UmpleTrait uTrait : inTraiStateMachine.keySet()){
					Map<StateMachine,StateMachine> listBeRemoved = new HashMap<StateMachine, StateMachine>();
					for (StateMachine sMachine : inTraiStateMachine.get(uTrait)) {
						if (compareStateMachineName(sMachine, tSMachine)){
							if (inUmpleClassifier instanceof UmpleTrait){
								if (uTrait.equals(((UmpleTrait)inUmpleClassifier)) ){
									getParseResult().addErrorMessage(new ErrorMessage(226,inUmpleClassifier.getPosition(0),sMachine.getName(),tUTrait.getName(),"trait",inUmpleClassifier.getName()));
									return false;
								}	else if(!tUTrait.equals(uTrait)) {
									getParseResult().addErrorMessage(new ErrorMessage(227,inUmpleClassifier.getPosition(0),sMachine.getName(),tUTrait.getName(),"trait",inUmpleClassifier.getName(),uTrait.getName()));
									return false;
								}															
							} else if(inUmpleClassifier instanceof UmpleClass){
								if(!tUTrait.equals(uTrait)){
									getParseResult().addErrorMessage(new ErrorMessage(227,inUmpleClassifier.getPosition(0),sMachine.getName(),tUTrait.getName(),"class",inUmpleClassifier.getName(),uTrait.getName()));
									return false;
								}
							}
						} else {
							if (sMachine.getName().equals(tSMachine.getName())){
								if (!sMachine.getStartState().getName().equals(tSMachine.getStartState().getName())){
									listBeRemoved.put(mergeTwoStateMachineWithTheSameNameDifferentInitialState(sMachine,tSMachine),sMachine);
									mustBeRemoved.add(tSMachine);
								} else {
									addExtraStatesAndTransitions(sMachine, tSMachine);
									mustBeRemoved.add(tSMachine);
								}
							}
						}	
					}
					for(Map.Entry<StateMachine,StateMachine> entry : listBeRemoved.entrySet() ) {
						inTraiStateMachine.get(uTrait).remove(entry.getValue());
						inTraiStateMachine.get(uTrait).add(entry.getKey());
					}
				}
			}
	 		for (StateMachine stMachine : mustBeRemoved){
	 			inTempTraiStateMachine.get(tUTrait).remove(stMachine);
	 		}
		}
		return true;
  }
//---------------------------------end----------------------------------------
//---------------------------------------------------------------------------- 
//---------------------------------Start--------------------------------------
	private StateMachine mergeTwoStateMachineWithTheSameNameDifferentInitialState(StateMachine inSMachine1, StateMachine inSMachine2) {
  	StateMachine newStateMachine = new StateMachine(inSMachine1.getName());
 		newStateMachine.addState(inSMachine1.getName());
 		newStateMachine.getState(0).setIsStartState(true);							
 		inSMachine1.setName(inSMachine1.getStartState().getName());
 		newStateMachine.getState(0).addNestedStateMachine(inSMachine1);
 		inSMachine2.setName(inSMachine2.getStartState().getName());
 		newStateMachine.getState(0).addNestedStateMachine(inSMachine2);
 		return newStateMachine;
 	}
//---------------------------------end----------------------------------------
//---------------------------------------------------------------------------- 
//---------------------------------Start--------------------------------------
	private void AddStateMachineMapToAnother(Map<UmpleTrait, List<StateMachine>> inTraitStateMachine,	Map<UmpleTrait, List<StateMachine>> inTempTraiStateMachine) {
	  for (UmpleTrait uTrait : inTempTraiStateMachine.keySet()) {
			if (inTraitStateMachine.containsKey(uTrait)){
				if (inTempTraiStateMachine.get(uTrait).size()>0)
					for (StateMachine st : inTempTraiStateMachine.get(uTrait)){
						if (!inTraitStateMachine.get(uTrait).contains(st)){
							inTraitStateMachine.get(uTrait).add(st);
						}
					}
			} else{
				inTraitStateMachine.put(uTrait, inTempTraiStateMachine.get(uTrait));
			}	
		}
	}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
   private boolean compareStateMachineName(StateMachine inSMachine1, StateMachine inSMachine2){
    if(inSMachine1.getName().equals(inSMachine2.getName()) && inSMachine1.numberOfStates()==inSMachine2.numberOfStates()){
	    	if (!inSMachine1.getStartState().getName().equals(inSMachine2.getStartState().getName())){
	    		UmpleClassifier uClassifier = inSMachine1.getUmpleClass();
	      	if (uClassifier==null) {
	      		uClassifier = inSMachine1.getUmpleTrait();
	      		getParseResult().addErrorMessage(new ErrorMessage(228,uClassifier.getPosition(0),inSMachine1.getName(),"tait", uClassifier.getName()));
	      	} else {
	      		getParseResult().addErrorMessage(new ErrorMessage(228,uClassifier.getPosition(0),inSMachine1.getName(),"class", uClassifier.getName()));
	      	}
	    	}
		  	return compareStatesAndTransitions(inSMachine1,inSMachine2);
		  	
		} else{
			return false;
		}
  }
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
  private boolean compareStatesAndTransitions(StateMachine inSMachine1, StateMachine inSMachine2) {
	  for (State state : inSMachine2.getStates()) {
		  State mainState = inSMachine1.findState(state.getName());
		  if (mainState ==null){
			  return false;
		  }
		  for(Transition trans : state.getTransitions() ){
			  boolean find = false;
			  for(Transition mainlTrans : mainState.getTransitions() ){
				  if (trans.isEqualToTransition(mainlTrans)){ find = true; }
			  }
			  if(!find) return false;
		  }
	  }
	  return true;
   }
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
  private void addExtraStatesAndTransitions(StateMachine inSMachine1, StateMachine inSMachine2) {
    for (State state : inSMachine2.getStates()) {
		  State mainState = inSMachine1.findState(state.getName());
		  if (mainState==null){
		  	state.setStateMachine(inSMachine1);
			  changeTransitionNextState(inSMachine1.findState(state.getName()),inSMachine1);
		  } else {
		  	for (int i = 0; i < state.numberOfTransitions(); i++) {
					Transition tTransition = state.getTransition(i); 		  		
				  boolean find = false;
				  for(Transition mainlTrans : mainState.getTransitions() ){
					  if (tTransition.isEqualToTransition(mainlTrans)){ find = true; }
				  }
				  if(!find) {			
				  	State nextState = inSMachine1.findState(tTransition.getNextState().getName());
						if(nextState==null){
							tTransition.getNextState().setStateMachine(inSMachine1);
						  changeTransitionNextState(inSMachine1.findState(tTransition.getNextState().getName()),inSMachine1);
							nextState = inSMachine1.findState(tTransition.getNextState().getName());													
						}
						
						tTransition.setFromState(mainState);
						tTransition.setNextState(nextState);
						if (i>0) i--;
				  }
				}
				if (state.getNestedStateMachines().size()>0){
		  		if (mainState.getNestedStateMachines().size()<=0){
		  			mainState.addNestedStateMachine(state.getNestedStateMachine(0));
		  		} else {
		  			if (!mainState.getNestedStateMachine(0).getStartState().getName().equals(state.getNestedStateMachine(0).getStartState().getName())){
		  				mainState.addNestedStateMachine(mergeTwoStateMachineWithTheSameNameDifferentInitialState(mainState.getNestedStateMachine(0), state.getNestedStateMachine(0))); 
		  			} else {
		  				addExtraStatesAndTransitions(mainState.getNestedStateMachine(0),state.getNestedStateMachine(0));
		  			}
		  		}
		  	}				
		  }  
	  }
  }
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
  private void changeTransitionNextState(State inState, StateMachine inSMachine) {
		for (Transition transition : inState.getTransitions() ) {
			State nextState = inSMachine.findState(transition.getNextState().getName());
			if(nextState==null){
				transition.getNextState().setStateMachine(inSMachine);
				changeTransitionNextState(transition.getNextState(),inSMachine);
				nextState = inSMachine.findState(transition.getNextState().getName());
				transition.setNextState(nextState);
			} else {
				transition.setNextState(nextState);
			}
		}
	}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------
  private void changeEventName(StateMachine inStateMachine, StateMachineTemplateSignature inSMTSignature) {
  	for (Transition t : inStateMachine.getAllTransitions()){
    	Method m = new Method("",t.getEvent().getName(),"",false);
  		m.setMethodParameters(t.getEvent().getParams());
  		if (compareTwoMethdos(m, inSMTSignature.getMethodTemplateSignature().getMethod())){
  			t.getEvent().setName(inSMTSignature.getAlias());
  		}
    }	
	}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------




//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------

}


//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class Transition{

//----------------------------------------------------------------------------  
//---------------------------------Start--------------------------------------
//----------------------------------------------------------------------------		
	//Please maintain this method if you're going to add new features to Transitions.
	//This code manually creates a clone of a Transitions.	
  Transition clone(State inFromState, State inNextState){
  	Transition transition = new Transition(inFromState, inNextState);
  	transition.setAutoTransition(getAutoTransition());
  	transition.setIsInternal(getIsInternal());
  	transition.setPosition(getPosition());
  	transition.setEvent(getEvent().clone());
  	if (getAction()!=null) transition.setAction(getAction().clone());
  	transition.setGuard(getGuard());
  	return  transition;
  }	
//----------------------------------------------------------------------------  
//---------------------------------Start--------------------------------------
//----------------------------------------------------------------------------	
  boolean isEqualToTransition(Transition inTransition){
  	if (inTransition.equals(null)) return false;
    if (!getEvent().equals(inTransition.getEvent())) return false;
    if (getAutoTransition()!=inTransition.getAutoTransition()) return false;
	  if (getEvent().numberOfParams() != inTransition.getEvent().numberOfParams()) return false;
	  for (int i = 0; i < inTransition.getEvent().numberOfParams(); i++) {
		  if (!getEvent().getParam(i).getType().equals(inTransition.getEvent().getParam(i).getType())) return false;
	  }
	  
	  if (getGuard()!=null){
		  if (!getGuard().isEqualToGuard(inTransition.getGuard())) return false; 
	  } else {
	  	if (inTransition.getGuard()!=null) 	return false;
	  }

	  if (getAction()!=null){
	  	//Please the following equals API is generated automatically.It must be checked always and make sure it's correct.
		  if (!getAction().equals(inTransition.getAction())) return false; 
	  } else {
	  	if (inTransition.getAction()!=null) 	return false;
	  }
    return true;
	}
}


//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  

class Guard{
	depend java.util.Iterator;

//----------------------------------------------------------------------------  
//---------------------------------Start--------------------------------------
//----------------------------------------------------------------------------	
	//TODO inserted by Vahda [Nov 30, 2015,4:49:56 PM]: please provide a comprehensive comparison
  //This comparison just supports sequential comparing of boolean operations. If the order is changed then it'll show false.
  boolean isEqualToGuard(Guard inGuard) {
  	if (inGuard==null) return false;
		if (getNumberOfElements()!=inGuard.getNumberOfElements()) return false;
		Iterator<ConstraintVariable> main = iterator();
		Iterator<ConstraintVariable> compareTo = inGuard.iterator();
		while(main.hasNext()&& compareTo.hasNext()){
			ConstraintVariable mCV = main.next();
			ConstraintVariable cCV = compareTo.next();
			if (mCV.getType()!=cCV.getType()) return false;
			if (mCV instanceof ConstraintOperator && cCV instanceof ConstraintOperator) {
				ConstraintOperator new_name1 = (ConstraintOperator) mCV;
				ConstraintOperator new_name2 = (ConstraintOperator) cCV;
			  if (!new_name1.getValue().equals(new_name2.getValue())) return false;
			}
			if (mCV instanceof ConstraintNamed && cCV instanceof ConstraintNamed) {
				ConstraintNamed new_name1 = (ConstraintNamed) mCV;
				ConstraintNamed new_name2 = (ConstraintNamed) cCV;
			  if (!new_name1.getName().equals(new_name2.getName())) return false;
			}
			if (mCV instanceof ConstraintLiteral && cCV instanceof ConstraintLiteral) {
				ConstraintLiteral new_name1 = (ConstraintLiteral) mCV;
				ConstraintLiteral new_name2 = (ConstraintLiteral) cCV;
			  if (!new_name1.getValue().equals(new_name2.getValue())) return false;
			}
			
		}
  	return true;
  	}
}


//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class Method {
//----------------------------------------------------------------------------  
//---------------------------------Start--------------------------------------
//----------------------------------------------------------------------------
	void setMethodParameters(List<MethodParameter> parameters){
		methodParameters = parameters;
 	}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------   
	String getSignature(){
    String result = getType()+" "+getName()+"(";
 			for(MethodParameter p : getMethodParameters()){
	 			result=result+p.getType()+",";
 			} 	
 			
 			if (result.endsWith(",") )result =result.substring(0, result.length()-1); 
 			result=result+")";
 		  return result;
 		}
//---------------------------------end----------------------------------------
//----------------------------------------------------------------------------   
//---------------------------------Start--------------------------------------   		
boolean compareWithTheMethod(Method inMethod){
    if (getName().equals(inMethod.getName())){
		 // if(method1.getType().equals(method2.getType())){
			  Integer numberOfParams = getMethodParameters().size();
			  if ( numberOfParams== inMethod.getMethodParameters().size()) {
		          boolean allSame = true;
		          for (int i = 0; i < numberOfParams; i++)
		          {
		            if(!getMethodParameter(i).getType().equals(inMethod.getMethodParameter(i).getType()))
		            {
		              allSame = false;
		              break;
		            }
		          }
		          if(allSame)
		          {
		            return true;
		          }
		     }
		 // }  
      }
	  return false;
  } 		
}


//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class StateMachine{
	
	//Please maintain this method if you're going to add new features to state machines.
	//This code manually creates a clone of a state machine.  
  public StateMachine clone(){
    StateMachine stM = new StateMachine(getName());
  	stM.setContainsDeepHistoryState(getContainsDeepHistoryState());
  	stM.setContainsHistoryState(getContainsHistoryState());
  	stM.setParentState(getParentState());
  	stM.setPooled(getPooled());
  	stM.setQueued(getQueued());
  	stM.setRecentSearchDepth(getRecentSearchDepth());
  	stM.setUmpleClass(getUmpleClass());
  	stM.setUmpleTrait(getUmpleTrait());
  	for (State st : getStates()) {
  			stM.addState(st.clone(stM));
		}
  	for (Transition transition : getAllTransitions()) {
  		State FromState = stM.findState(transition.getFromState().getName(),false);
			State NextState = stM.findState(transition.getNextState().getName(),false);
			transition.clone(FromState, NextState);
  	}  	  		
  	return  stM;
  }	
	
	public Event getEventByMethod(Method inMethod) {
	  if (inMethod == null)
    {
      return null;
    }
    for (State aState : states)
    {
      for (int i=0; i<aState.numberOfTransitions(); i++)
      {
        Transition aTransition = aState.getTransition(i);
        Event e = aTransition.getEvent();
        if (e != null )
        {
        	Method m = new Method("",e.getName(),"",false);
        	m.setMethodParameters(e.getParams());
        	if (m.compareWithTheMethod(inMethod))  return e;
        }
      }
    }
    return null;
	}
}
//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class State{
//Please maintain this method if you're going to add new features to states.
	//This code manually creates a clone of a state.
	State clone(StateMachine inStateMachine){
    State st = new State(getName(), inStateMachine);
  	st.setFinalState(getFinalState());
  	st.setIsDeepHistoryState(getIsDeepHistoryState());
  	st.setIsHistoryState(getIsHistoryState());
  	st.setIsInternal(getIsInternal());
  	st.setIsStartState(getIsStartState());
  	st.setIsVisited(getIsVisited());
  	st.setPosition(getPosition());
  	for (int i = 0; i < getNestedStateMachines().size(); i++) {
			StateMachine stMTemp = nestedStateMachines.get(i).clone();
			st.addNestedStateMachine(stMTemp);
		}
  	for (Action action : actions) {
			st.addAction(action.clone());
		}
  	return st;
  }
}


//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class Event{

	//Please maintain this method if you're going to add new features to Events.
	//This code manually creates a clone of a Events.	
  Event clone(){
  	Event e = new Event(getName());
  	e.setAutoTransition(getAutoTransition());
  	e.setIsInternal(getIsInternal());
  	e.setIsTimer(getIsTimer());
  	e.setTimerInSeconds(getTimerInSeconds());
  	e.setUnspecified(getUnspecified());
  	for (MethodParameter mp : getParams()){
  		e.addParam(mp.clone());
  	}
  	return e;
  }	
}
//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class MethodParameter{
	
	//Please maintain this method if you're going to add new features to MethodParameters.
	//This code manually creates a clone of a MethodParameters.
	MethodParameter clone(){
		MethodParameter mp = new MethodParameter(getName(),getType(),getModifier(),getValue(),getIsAutounique());
		mp.isAutounique = getIsAutounique();
		mp.isList = getIsList();
		mp.isDerived = getIsDerived();
		mp.isLazy = getIsLazy();
		return mp;
  }
}
//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class Action{
	
	//Please maintain this method if you're going to add new features to Actions.
	//This code manually creates a clone of a Actions.
	Action clone(){
  	Action action = new Action(getActionCode());
  	action.setActionType(getActionType());
  	action.setPosition(getPosition());
  	action.setEndPosition(getEndPosition());
  	return action;
  }
	
}

//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
class Guard{
	//Please maintain this method if you're going to add new features to Guards.
	//This code manually creates a clone of a Guards.
  public Guard clone(){
  	Guard guard  = new Guard();
  	//TODO: if we want to cover changing names of variables used in guard, I must modify this section to create new objects.
  	return guard;
  }
}
//************************************************************************************* 
//************************************NEW CLASS****************************************
//*************************************************************************************  
