/*******************************************************************************
 * 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.ReferencedPackage;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.Resource;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.CompositeInstallable;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.CompositeUnit;
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.contentunit.ResultingResource;



public class ReferencedPackageType {
	
	
	
	public static Collection <ReferencedPackage> merge(Collection <ReferencedPackage> referencedPackages1, Collection <ReferencedPackage> referencedPackages2)
	{
		Collection <ReferencedPackage> referencedPackagesToRemove = new ArrayList <ReferencedPackage> ();
		Iterator <ReferencedPackage> referencedPackageIter1 = referencedPackages1.iterator();		
		//iterate through the referencedPackages
		while (referencedPackageIter1.hasNext())
		{
			ReferencedPackage referencedPackage1 = (ReferencedPackage) referencedPackageIter1.next();
			Iterator <ReferencedPackage> referencedPackageIter2 = referencedPackages2.iterator();
			while (referencedPackageIter2.hasNext())
			{
				ReferencedPackage referencedPackage2 = (ReferencedPackage) referencedPackageIter2.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 (referencedPackagesToRemove.contains(referencedPackage2)==false)
				{
					if (equals(referencedPackage1, referencedPackage2))
					{  //merge hosted referencedPackages, types and description groups
						referencedPackagesToRemove.add(referencedPackage2);						
						referencedPackage1 = merge(referencedPackage1,referencedPackage2);
						
					}
				}
					
			}
		}
		
		referencedPackages2.removeAll(referencedPackagesToRemove);
		//remove all of the matches that were found
		
		Collection <ReferencedPackage> finalReferencedPackages = new ArrayList <ReferencedPackage> ();
		//create and return a new collection with all of the remaining items
		finalReferencedPackages.addAll(referencedPackages1);
		finalReferencedPackages.addAll(referencedPackages2);		
		
		return finalReferencedPackages;
	}
	
	/*
	 *   <ReferencedPackageType>

		<xsd:complexType name="ReferencedPackageType">
		  <xsd:sequence>
		    <xsd:element name="Condition" type="sdd-dd:ConditionType" minOccurs="0"/>
		    <xsd:element name="RequiredContentSelection" type="sdd-dd:RequiredContentSelectionType" minOccurs="0"/>
		    <xsd:element name="Arguments" type="sdd-dd:ArgumentListType" minOccurs="0"/>
		    <xsd:element name="OutputVariables" type="sdd-dd:OutputVariableListType" minOccurs="0"/>
		    <xsd:element name="Requirements" type="sdd-dd:RequirementsType" minOccurs="0"/>
		    <xsd:element name="ResultingResourceMap" type="sdd-dd:ResultingResourceMapType" minOccurs="0" maxOccurs="unbounded"/>
		    <xsd:element name="ResultingChangeMap" type="sdd-dd:ResultingChangeMapType" minOccurs="0" maxOccurs="unbounded"/>
		    <xsd:element name="RequiredResourceMap" type="sdd-dd:ResourceMapType" minOccurs="0" maxOccurs="unbounded"/>
		    <xsd:element name="Languages" type="sdd-dd:LanguagesType" minOccurs="0"/>
		    <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
		  </xsd:sequence>
		  <xsd:attribute name="id" type="xsd:ID" use="required"/>
		  <xsd:attribute name="contentRef" type="xsd:token" use="required"/>
		  <xsd:attribute name="weight" type="xsd:positiveInteger" use="optional"/>
		  <xsd:attribute name="operation" type="sdd-dd:OperationType" use="optional"/>
		  <xsd:anyAttribute namespace="##other" processContents="lax"/>
		</xsd:complexType>

		Type 	Element 	Attribute 	Data Type 	Compare?
		<ReferencedPackageType> 				
			id 	xsd:ID 	Throw Away
			contentRef 	xsd:token 	Yes
			weight 	xsd:positiveInteger 	Merge
			operation 	<OperationType> 	Yes
			any 	namespace="##other" 	 ?
			Condition 		<ConditionType> 	Yes
			RequiredContentSelection 		<RequiredContentSelectionType> 	Merge
			Arguments 		<ArgumentListType> 	Merge
			OutputVariables 		<OutputVariableListType> 	Merge
			Requirements 		<RequirementsType> 	Merge
			ResultingResourceMap 		<ResultingResourceMapType> 	Merge
			ResultingChangeMap 		<ResultingChangeMapType> 	Merge
			RequiredResourceMap 		<ResourceMapType> 	Merge
			Languages 		<LanguagesType> 	Merge
			any 		namespace="##other" 	 ? 
	 */
	
	private static ReferencedPackage merge(ReferencedPackage referencedPackage1, ReferencedPackage referencedPackage2)
	{
		if ((referencedPackage1.getWeight()==null)&&(referencedPackage2.getWeight()!=null))
			referencedPackage1.setWeight(referencedPackage2.getWeight());
		if ((referencedPackage1.getWeight()!=null)&&(referencedPackage2.getWeight()!=null))
			if (referencedPackage1.getWeight().compareTo(referencedPackage2.getWeight())<0)
				referencedPackage1.setWeight(referencedPackage2.getWeight());
		
		referencedPackage1.setRequiredFeatures(ContentSelectionFeatureType.merge(referencedPackage1.getRequiredFeatures(), referencedPackage2.getRequiredFeatures()));
		
		//argumenttype isn't made available from spi.
		
		referencedPackage1.setOutputVariables(OutputVariableType.merge(referencedPackage1.getOutputVariables(), referencedPackage2.getOutputVariables()));
		referencedPackage1.setRequirements(RequirementType.merge(referencedPackage1.getRequirements(), referencedPackage2.getRequirements()));
		referencedPackage1.setResultingResourceMaps(ResultingResourceMapType.merge(referencedPackage1.getResultingResourceMaps(), referencedPackage2.getResultingResourceMaps()));
		referencedPackage1.setResultingChangeMaps(ResultingChangeMapType.merge(referencedPackage1.getResultingChangeMaps(), referencedPackage2.getResultingChangeMaps()));
		referencedPackage1.setRequiredResourceMaps(ResourceMapType.merge(referencedPackage1.getRequiredResourceMaps(), referencedPackage2.getRequiredResourceMaps()));		
		referencedPackage1.setLanguages(LanguageType.merge(referencedPackage1.getLanguages(), referencedPackage2.getLanguages()));
		
		
		return referencedPackage1;
	}

	public static boolean equals(ReferencedPackage rp1, ReferencedPackage rp2)
	{
		if (ContentType.equals(Util.resolveContentRef(rp1.getContentReference()),Util.resolveContentRef(rp2.getContentReference())))
		{
			if ((rp1.getOperation()==null)&&(rp2.getOperation()!=null))
				return false;
			if ((rp1.getOperation()!=null)&&(rp2.getOperation()==null))
				return false;
			if ((rp1.getOperation()!=null)&&(rp2.getOperation()!=null))
				if (StringType.equals(rp1.getOperation(), rp2.getOperation()))
					return true;
				else return false;
			
			return true;
		}
		return false;
				
			
	}

	
}
