/*******************************************************************************
 * 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 java.util.List;

import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.DeploymentDescriptor;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.PackageContent;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.PackageDescriptor;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.Resource;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.artifact.AdditionalContent;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.artifact.Artifact;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.ConfigurationUnit;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.ContentUnit;
import org.eclipse.cosmos.me.provisional.deployment.sdd.common.spi.contentunit.InstallableUnit;

public class Util {
	
	/**
	 * Find the ResourceType element pointed to by the given resourceRef
	 * @param resourceRef Reference matching the id of a ResourceType element
	 * @param deplDescriptor DeploymentDescriptor in which to look for the resourceRef
	 * @return ResourceType element associated with resourceRef, or null if resource doesn't exist
	 */
	public static Resource resolveResourceRef(String resourceRef) {
		// Loop through all ResourceTypes in this DeploymentDescriptor
		DeploymentDescriptor deplDescriptor = Aggregator.getDd1();
		
		Iterator resourceIter = deplDescriptor.getResources().iterator();
		while (resourceIter.hasNext()) {
			Resource resource = (Resource)resourceIter.next();
				
			// Is this the ResourceType we're looking for?
			if (resource.getResourceID().equalsIgnoreCase(resourceRef)) {
				return (resource);
			}
				
			// Check this Resource's HostedResources
			Resource retVal = checkHostedResources(resourceRef, resource);
			if (retVal != null) {
				return (retVal);
			}		
		}
		
		// Failed to find the referenced ResourceType
		return (null);
	}
	
	private static Resource checkHostedResources(String resourceRef, Resource hostingResource) {
		Iterator hostedResourcesIter = hostingResource.getHostedResources().iterator();
		Resource foundResource = null;
		
		// Check each of the HostedResources and its HostedResources
		while (hostedResourcesIter.hasNext()) {
			Resource resource = (Resource)hostedResourcesIter.next();
			
			// Check this ResourceType
			if (resource.getResourceID().equalsIgnoreCase(resourceRef)) {
				return (resource);
			}
			
			// Check the HostedResources for this ResourceType
			foundResource = checkHostedResources(resourceRef, resource);
		}
		
		return (foundResource);
	}
	
	/**
	 * Change any contentRefs pointing at oldId to point at newId
	 * @param oldId Look for contentRefs pointing to this id
	 * @param newId Change contentRefs to point to this id instead
	 */
	public static void updateContentRefs(String oldId, String newId) {
		/*
		 * checks each deployment descriptor
		 * contentRefs can appear in ArtifactType and AdditionalContentType
		 * ArtifactType is located in InstallationArtifactsType and ConfigurationArtifactsType
		 */
		
		Collection<DeploymentDescriptor> deploymentDescriptors = Aggregator.getAllDeploymentDescriptors();
		Iterator<DeploymentDescriptor> ddIter = deploymentDescriptors.iterator();
		
		while( ddIter.hasNext()){
			
			DeploymentDescriptor deplDescriptor = ddIter.next();
			ContentUnit contentUnit = deplDescriptor.getContentUnit();
	
			// If deployment descriptor content is a ConfigurationUnit look for ArtifactType
			if (contentUnit instanceof ConfigurationUnit) {
				ConfigurationUnit configUnit = (ConfigurationUnit)contentUnit;
				Artifact configArtifact = configUnit.getConfigurationArtifact();
	
				if(configArtifact != null){
					// Update the Artifact's id if it matches the old id
					if (!configArtifact.getContentReference().equals("") && configArtifact.getContentReference().equals(oldId)) {
						configArtifact.setContentReference(newId);
						// Update AdditionalContents
						updateAdditionalContentTypes(oldId, newId, configArtifact.getAdditionalContents());
					}
				}
			}
			
			// If deployment descriptor content is an InstallableUnit look for ArtifactType
			if (contentUnit instanceof InstallableUnit) {
				InstallableUnit installableUnit = (InstallableUnit)contentUnit;
				Artifact installArtifact = installableUnit.getInstallArtifact();
	
				// Inspect Install Artifact
				if(installArtifact != null){
					// Update the Artifact's id if it matches the old id
					if (installArtifact.getContentReference().equals("") && installArtifact.getContentReference().equals(oldId)) {
						installArtifact.setContentReference(newId);
						// Update AdditionalContents
						updateAdditionalContentTypes(oldId, newId, installArtifact.getAdditionalContents());
					}
				}
				
				Artifact updateArtifact = installableUnit.getUpdateArtifact();
				
				// Inspect Update Artifact
				if (updateArtifact != null) {
					// Update the Artifact's id if it matches the old id
					if (updateArtifact.getContentReference().equals("") && updateArtifact.getContentReference().equals(oldId)) {
						updateArtifact.setContentReference(newId);
						// Update AdditionalContents
						updateAdditionalContentTypes(oldId, newId, updateArtifact.getAdditionalContents());
					}
				}
	
				Artifact undoArtifact = installableUnit.getUndoArtifact();
				
				// Inspect Undo Artifact
				if (undoArtifact != null) {
					// Update the Artifact's id if it matches the old id
					if (undoArtifact.getContentReference().equals("") && undoArtifact.getContentReference().equals(oldId)) {
						undoArtifact.setContentReference(newId);
						// Update AdditionalContents
						updateAdditionalContentTypes(oldId, newId, undoArtifact.getAdditionalContents());					
					}
				}
				
				Artifact uninstallArtifact = installableUnit.getUninstallArtifact();
				
				// Inspect Uninstall Artifact
				if (uninstallArtifact != null) {
					// Update the Artifact's id if it matches the old id
					if (uninstallArtifact.getContentReference().equals("") && uninstallArtifact.getContentReference().equals(oldId)) {
						uninstallArtifact.setContentReference(newId);
						// Update AdditionalContents
						updateAdditionalContentTypes(oldId, newId, uninstallArtifact.getAdditionalContents());
					}
				}
				
				/* Not in current SPI code
				 * Artifact repairArtifact = installableUnit.getRepairArtifact();
				
				// Inspect Repair Artifact
				if (repairArtifact != null) {
					// Update the Artifact's id if it matches the old id
					if (repairArtifact.getContentReference().equals("") && repairArtifact.getContentReference().equals(oldId)) {
						repairArtifact.setContentReference(newId);
						// Update AdditionalContents
						updateAdditionalContentTypes(oldId, newId, repairArtifact.getAdditionalContents());
					}
				}		*/	
			}
		}
	}
	
	/*
	 * Update the contentRef on AdditionalContentTypes
	 */
	private static void updateAdditionalContentTypes(String oldId, String newId, Collection<AdditionalContent> additionalContent) {
		// Loop though all AdditionalContentTypes
		Iterator<AdditionalContent> contentIter = additionalContent.iterator();
		while (contentIter.hasNext()) {
			AdditionalContent content = contentIter.next();
			
			// Update the AddtionalContent's contentRef if it points to the old id
			if (!content.getContentReference().equals("") && content.getContentReference().equals(oldId)) {
				content.setContentReference(newId);
			}
		}
	}
	
	/**
	 * Find the ContentType element pointed to by the given contentRef
	 * @param contentRef Reference matching the id of a ContentType element
	 * @return ContentType element associated with contentRef, or null if content doesn't exist
	 */
	public static PackageContent resolveContentRef(String contentRef) {
		Collection<PackageDescriptor> pkgDescriptors = Aggregator.getAllPackageDescriptors();
		Iterator<PackageDescriptor> packageIter = pkgDescriptors.iterator();
		
		//loop through each package descriptor
		while(packageIter.hasNext()){
			PackageDescriptor pkgDescriptor = packageIter.next();
			if (pkgDescriptor!=null)
			{
				// Loop through all ContentTypes in this PackageDescriptor
				Iterator<PackageContent> contentsIter = pkgDescriptor.getPackageContents().iterator();
				while (contentsIter.hasNext()) {
					PackageContent packageContent = contentsIter.next();
						
					// Is this the ContentType we're looking for?
					if(packageContent.getContentID().equals(contentRef)){
						return packageContent;
					}
				}
			}
		}
		
		// Failed to find the referenced ContentType
		return (null);
	}
}
