/*******************************************************************************
 * Copyright (c) 2008 SAS Institute 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:
 *     SAS Institute Inc. - initial API and implementation
 ******************************************************************************/
package org.eclipse.cosmos.me.provisional.deployment.sdd.tooling.btg.aggregator;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.DeploymentDescriptor;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.Resource;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.InstallableUnit;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.LocalizationUnit;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.ConfigurationUnit;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.variable.ParameterGroup;



public class ConfigurationUnitType {
	  /*<ConfigurationUnitType>

	  <xsd:complexType name="ConfigurationUnitType">
	    <xsd:sequence>
	      <xsd:element name="Identity" type="sdd-common:IdentityType" minOccurs="0"/>
	      <xsd:element name="Condition" type="sdd-dd:ConditionType" minOccurs="0"/>
	      <xsd:element name="Variables" type="sdd-dd:VariablesType" minOccurs="0"/>
	      <xsd:element name="Requirements" type="sdd-dd:RequirementsType" minOccurs="0"/>
	      <xsd:element name="Completion" type="sdd-dd:CompletionType" minOccurs="0" maxOccurs="unbounded"/>
	      <xsd:element name="ResultingChange" type="sdd-dd:ResultingChangeType" minOccurs="0" maxOccurs="unbounded"/>
	      <xsd:element name="Artifacts" type="sdd-dd:ConfigurationArtifactsType"/>
	      <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
	    </xsd:sequence>
	    <xsd:attribute name="id" type="xsd:ID" use="required"/>
	    <xsd:attribute name="targetResourceRef" type="xsd:IDREF" use="required"/>
	    <xsd:anyAttribute namespace="##other" processContents="lax"/>
	  </xsd:complexType>

	  Type 	Element 	Attribute 	Data Type 	Compare?
	  <ConfigurationUnitType> 				
	  		id 	xsd:ID 	Throw Away
	  		targetResourceRef 	xsd:IDREF 	Yes
	  		any 	namespace="##other" 	 ?
	  	Identity 		<IdentityType> 	Merge
	  	Condition 		<ConditionType> 	Merge
	  	Variables 		<VariablesType> 	Merge
	  	Requirements 		<RequirementsType> 	Merge
	  	Completion 		<CompletionType> 	Merge
	  	ResultingChange 		<ResultingChangeType> 	Yes
	  	Artifacts 		<ConfigurationArtifactsType> 	No
	  	any 		namespace="##other" 	 ?
	 */
	
	public static boolean equals(ConfigurationUnit dd1, ConfigurationUnit dd2)
	{
		if (ResourceType.equals(Util.resolveResourceRef(dd1.getTargetResourceReference()),Util.resolveResourceRef(dd2.getTargetResourceReference())))
		{
			if ((dd1.getResultingChanges()==null)&&(dd2.getResultingChanges()!=null))
				return false;
			if ((dd2.getResultingChanges()==null)&&(dd1.getResultingChanges()!=null))
				return false;
			if (ResultingChangeType.equals(dd1.getResultingChanges(), dd2.getResultingChanges()))		
				return true;
		}
		return false;
	}
	
	public static ConfigurationUnit merge(ConfigurationUnit dd1, ConfigurationUnit dd2)
	{
		
		dd1.setIdentityData(IdentityType.merge(dd1.getIdentityData(), dd2.getIdentityData()));
		dd1.setCompletion(CompletionType.merge(dd1.getCompletion(), dd2.getCompletion()));
		dd1.setConditionalDerivedVariables(ConditionalDerivedVariablesType.merge(dd1.getConditionalDerivedVariables(), dd2.getConditionalDerivedVariables()));
		dd1.setConfigurationArtifact(ArtifactType.merge(dd1.getConfigurationArtifact(), dd2.getConfigurationArtifact()));
		//not setting contentunitID
		dd1.setDerivedVariables(DerivedVariableType.merge(dd1.getDerivedVariables(), dd2.getDerivedVariables()));
		ParameterGroup params = ParameterGroupType.merge(dd1.getParameterGroups(), dd2.getParameterGroups());
		ArrayList <ParameterGroup> myParams = new ArrayList <ParameterGroup> ();
		myParams.add(params);
		dd1.setParameterGroups(myParams);		
		dd1.setRequirements(RequirementType.merge(dd1.getRequirements(), dd2.getRequirements()));
		dd1.setResourceProperties(ResourcePropertyType.merge(dd1.getResourceProperties(), dd2.getResourceProperties()));
				
		return dd1;
	}

	public static Collection<ConfigurationUnit> merge(Collection<ConfigurationUnit> configurationUnits1, Collection<ConfigurationUnit> configurationUnits2)
	{
		Collection <ConfigurationUnit> configurationUnitsToRemove = new ArrayList <ConfigurationUnit> ();
		Iterator <ConfigurationUnit> configurationUnitIter1 = configurationUnits1.iterator();		
		//iterate through the configurationUnits
		while (configurationUnitIter1.hasNext())
		{
			ConfigurationUnit configurationUnit1 = (ConfigurationUnit) configurationUnitIter1.next();
			Iterator <ConfigurationUnit> configurationUnitIter2 = configurationUnits2.iterator();
			while (configurationUnitIter2.hasNext())
			{
				ConfigurationUnit configurationUnit2 = (ConfigurationUnit) configurationUnitIter2.next();
				//if you find a match that hasn't been found, note it
				//one of the equals needs to be deleted with its children merged over
				if (configurationUnitsToRemove.contains(configurationUnit2)==false)
				{
					if (equals(configurationUnit1, configurationUnit2))
					{  //merge hosted configurationUnits, types and description groups
						configurationUnitsToRemove.add(configurationUnit2);				
						
						configurationUnit1 = merge(configurationUnit1,configurationUnit2);
						
					}
				}
					
			}
		}
		
		configurationUnits2.removeAll(configurationUnitsToRemove);
		//remove all of the matches that were found
		
		Collection <ConfigurationUnit> finalConfigurationUnits = new ArrayList <ConfigurationUnit> ();
		//create and return a new collection with all of the remaining items
		finalConfigurationUnits.addAll(configurationUnits1);
		finalConfigurationUnits.addAll(configurationUnits2);		
		
		return finalConfigurationUnits;
		
	}
	
}
