/*******************************************************************************
 * Copyright (c) 2013 Red Hat, Inc. and others
 * 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:
 *     Red Hat, Inc. - initial API and implementation
 *******************************************************************************/
package org.eclipse.equinox.internal.p2.operations;

import java.util.*;
import java.util.Map.Entry;
import org.eclipse.core.runtime.*;
import org.eclipse.equinox.internal.p2.director.ProfileChangeRequest;
import org.eclipse.equinox.p2.engine.*;
import org.eclipse.equinox.p2.engine.query.IUProfilePropertyQuery;
import org.eclipse.equinox.p2.metadata.*;
import org.eclipse.equinox.p2.metadata.expression.ExpressionUtil;
import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
import org.eclipse.equinox.p2.planner.IPlanner;
import org.eclipse.equinox.p2.planner.IProfileChangeRequest;
import org.eclipse.equinox.p2.query.*;

public class RequestFlexer {
	final String INCLUSION_RULES = "org.eclipse.equinox.p2.internal.inclusion.rules"; //$NON-NLS-1$
	final String INCLUSION_OPTIONAL = "OPTIONAL"; //$NON-NLS-1$
	final String INCLUSION_STRICT = "STRICT"; //$NON-NLS-1$
	final String EXPLANATION_ENABLEMENT = "org.eclipse.equinox.p2.director.explain"; //$NON-NLS-1$

	IPlanner planner;

	private boolean allowInstalledUpdate = false;
	private boolean allowInstalledRemoval = false;
	private boolean allowDifferentVersion = false;
	private boolean allowPartialInstall = false;

	private boolean ensureProductPresence = true;
	private boolean honorSharedSettings = true;

	private ProvisioningContext provisioningContext;

	Set<IRequirement> requirementsForElementsBeingInstalled = new HashSet<IRequirement>();
	Set<IRequirement> requirementsForElementsAlreadyInstalled = new HashSet<IRequirement>();
	Map<IRequirement, Map<String, String>> propertiesPerRequirement = new HashMap<IRequirement, Map<String, String>>();
	Map<IRequirement, List<String>> removedPropertiesPerRequirement = new HashMap<IRequirement, List<String>>();

	IProfile profile;

	private boolean foundDifferentVersionsForElementsToInstall = false;
	private boolean foundDifferentVersionsForElementsInstalled = false;
	private Set<IInstallableUnit> futureOptionalIUs;

	public RequestFlexer(IPlanner planner) {
		this.planner = planner;
	}

	public void setAllowInstalledElementChange(boolean allow) {
		allowInstalledUpdate = allow;
	}

	public void setAllowInstalledElementRemoval(boolean allow) {
		allowInstalledRemoval = allow;
	}

	public void setAllowDifferentVersion(boolean allow) {
		allowDifferentVersion = allow;
	}

	public void setAllowPartialInstall(boolean allow) {
		allowPartialInstall = allow;
	}

	public void setProvisioningContext(ProvisioningContext context) {
		provisioningContext = context;
	}

	public void setEnsureProduct(boolean productPresent) {
		ensureProductPresence = productPresent;
	}

	public IProfileChangeRequest getChangeRequest(IProfileChangeRequest request, IProfile prof, IProgressMonitor monitor) {
		this.profile = prof;
		SubMonitor sub = SubMonitor.convert(monitor, 2);
		IProfileChangeRequest loosenedRequest = computeLooseRequest(request, sub.newChild(1));
		if (canShortCircuit(request)) {
			return null;
		}
		IProvisioningPlan intermediaryPlan = resolve(loosenedRequest, sub.newChild(1));
		if (!intermediaryPlan.getStatus().isOK())
			return null;
		if (intermediaryPlan.getAdditions().query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).isEmpty() && intermediaryPlan.getRemovals().query(QueryUtil.ALL_UNITS, new NullProgressMonitor()).isEmpty())
			//No changes, we can't return anything
			return null;
		if (!productContainmentOK(intermediaryPlan)) {
			return null;
		}
		IProfileChangeRequest effectiveRequest = computeEffectiveChangeRequest(intermediaryPlan, loosenedRequest, request);
		if (isRequestUseless(effectiveRequest))
			return null;
		return effectiveRequest;
	}

	private boolean isRequestUseless(IProfileChangeRequest effectiveRequest) {
		if (effectiveRequest.getAdditions().isEmpty() && effectiveRequest.getRemovals().isEmpty())
			return true;
		if (effectiveRequest.getRemovals().containsAll(effectiveRequest.getAdditions()))
			return true;
		return false;
	}

	private boolean canShortCircuit(IProfileChangeRequest originalRequest) {
		//Case where the user is asking to install only some of the requested IUs but there is only one IU to install. 
		if (allowPartialInstall && !allowInstalledUpdate && !allowDifferentVersion && !allowInstalledRemoval)
			if (originalRequest.getAdditions().size() == 1)
				return true;

		//When we can find a different version of the IU but the only version available is the one the user is asking to install
		if (allowDifferentVersion && !allowPartialInstall && !allowInstalledRemoval && !allowInstalledUpdate)
			if (!foundDifferentVersionsForElementsToInstall)
				return true;

		if (allowInstalledUpdate && !allowDifferentVersion && !allowPartialInstall && !allowInstalledRemoval)
			if (!foundDifferentVersionsForElementsInstalled)
				return true;

		if (!allowPartialInstall && !allowInstalledUpdate && !allowDifferentVersion && !allowInstalledRemoval)
			return true;

		return false;
	}

	//From the loosened request and the plan resulting from its resolution, create a new profile change request representing the delta between where the profile currently is 
	// and the plan returned.
	//To perform this efficiently, this relies on a traversal of the requirements that are part of the loosened request.  
	private IProfileChangeRequest computeEffectiveChangeRequest(IProvisioningPlan intermediaryPlan, IProfileChangeRequest loosenedRequest, IProfileChangeRequest originalRequest) {
		IProfileChangeRequest finalChangeRequest = planner.createChangeRequest(profile);
		// We have the following two variables because a IPCRequest can not be muted
		Set<IInstallableUnit> iusToAdd = new HashSet<IInstallableUnit>();
		Set<IInstallableUnit> iusToRemove = new HashSet<IInstallableUnit>();

		for (IRequirement beingInstalled : requirementsForElementsBeingInstalled) {
			IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(beingInstalled.getMatches());
			IQueryResult<IInstallableUnit> matches = intermediaryPlan.getFutureState().query(QueryUtil.createLatestQuery(query), null);
			IInstallableUnit replacementIU = null;
			if (!matches.isEmpty()) {
				replacementIU = matches.iterator().next();
				iusToAdd.add(replacementIU);
				adaptIUPropertiesToNewIU(beingInstalled, replacementIU, finalChangeRequest);
			}
		}

		for (IRequirement alreadyInstalled : requirementsForElementsAlreadyInstalled) {
			IQuery<IInstallableUnit> query = QueryUtil.createMatchQuery(alreadyInstalled.getMatches());
			IQueryResult<IInstallableUnit> matches = intermediaryPlan.getFutureState().query(QueryUtil.createLatestQuery(query), null);
			IInstallableUnit potentialRootChange = null;
			if (!matches.isEmpty())
				potentialRootChange = matches.iterator().next();

			IQueryResult<IInstallableUnit> iuAlreadyInstalled = profile.available(query, new NullProgressMonitor());

			if (!iuAlreadyInstalled.isEmpty()) {//This deals with the case where the root has not changed
				if (potentialRootChange != null && iuAlreadyInstalled.toUnmodifiableSet().contains(potentialRootChange))
					continue;
			}
			iusToRemove.addAll(iuAlreadyInstalled.toUnmodifiableSet());
			if (potentialRootChange != null) {
				if (!iusToAdd.contains(potentialRootChange)) {//So we don't add the same IU twice for addition
					iusToAdd.add(potentialRootChange);
					adaptIUPropertiesToNewIU(alreadyInstalled, potentialRootChange, finalChangeRequest);
				}
			}
		}

		iusToRemove.addAll(originalRequest.getRemovals());

		//Remove entries that are both in the additions and removals (since this is a no-op)
		HashSet<IInstallableUnit> commons = new HashSet<IInstallableUnit>(iusToAdd);
		if (commons.retainAll(iusToRemove)) {
			iusToAdd.removeAll(commons);
			iusToRemove.removeAll(commons);
		}

		//Finish construction of the IPCR
		finalChangeRequest.addAll(iusToAdd);
		finalChangeRequest.removeAll(iusToRemove);
		if (originalRequest.getExtraRequirements() != null)
			finalChangeRequest.addExtraRequirements(originalRequest.getExtraRequirements());
		return finalChangeRequest;
	}

	private void adaptIUPropertiesToNewIU(IRequirement beingInstalled, IInstallableUnit newIU, IProfileChangeRequest finalChangeRequest) {
		Map<String, String> associatedProperties = propertiesPerRequirement.get(beingInstalled);
		if (associatedProperties != null) {
			Set<Entry<String, String>> entries = associatedProperties.entrySet();
			for (Entry<String, String> entry : entries) {
				finalChangeRequest.setInstallableUnitProfileProperty(newIU, entry.getKey(), entry.getValue());
			}
		}
		List<String> removedProperties = removedPropertiesPerRequirement.get(beingInstalled);
		if (removedProperties != null) {
			for (String toRemove : removedProperties) {
				finalChangeRequest.removeInstallableUnitProfileProperty(newIU, toRemove);
			}
		}
	}

	//Create a request where the original requirements are "loosened" according to flags specified in this instance
	//The resulting profile change request uses the requirements specified using p2QL and those appear in the extraRequirements.
	private IProfileChangeRequest computeLooseRequest(IProfileChangeRequest originalRequest, IProgressMonitor monitor) {
		IProfileChangeRequest loosenedRequest = planner.createChangeRequest(profile);
		SubMonitor sub = SubMonitor.convert(monitor, 2);
		loosenUpOriginalRequest(loosenedRequest, originalRequest, sub.newChild(1));
		loosenUpInstalledSoftware(loosenedRequest, originalRequest, sub.newChild(1));
		return loosenedRequest;
	}

	private boolean removalRequested(IInstallableUnit removalRequested, IProfileChangeRequest request) {
		return request.getRemovals().contains(removalRequested);
	}

	private IProvisioningPlan resolve(IProfileChangeRequest temporaryRequest, IProgressMonitor monitor) {
		SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
		String explainPropertyBackup = null;
		try {
			temporaryRequest.setProfileProperty("_internal_user_defined_", "true"); //$NON-NLS-1$//$NON-NLS-2$
			if (provisioningContext != null) {
				explainPropertyBackup = provisioningContext.getProperty(EXPLANATION_ENABLEMENT);
				provisioningContext.setProperty(EXPLANATION_ENABLEMENT, Boolean.FALSE.toString());
			}
			return planner.getProvisioningPlan(temporaryRequest, provisioningContext, subMonitor.split(1));
		} finally {
			if (provisioningContext != null) {
				if (explainPropertyBackup == null)
					provisioningContext.getProperties().remove(EXPLANATION_ENABLEMENT);
				else
					provisioningContext.setProperty(EXPLANATION_ENABLEMENT, explainPropertyBackup);
			}
		}
	}

	//Loosen the request originally emitted.
	//For example if the user said "install A 1.0", then a new Requirement is added saying (install A 1.0 or install A 2.0), this depending on the configuration flags 
	private void loosenUpOriginalRequest(IProfileChangeRequest newRequest, IProfileChangeRequest originalRequest, IProgressMonitor monitor) {
		//First deal with the IUs that are being added
		Collection<IInstallableUnit> requestedAdditions = originalRequest.getAdditions();
		SubMonitor subMonitor = SubMonitor.convert(monitor, requestedAdditions.size());
		for (IInstallableUnit addedIU : requestedAdditions) {
			SubMonitor iterationMonitor = subMonitor.split(1);
			Collection<IInstallableUnit> potentialUpdates = allowDifferentVersion ? findAllVersionsAvailable(addedIU, iterationMonitor) : new ArrayList<IInstallableUnit>();
			foundDifferentVersionsForElementsToInstall = (foundDifferentVersionsForElementsToInstall || (potentialUpdates.size() == 0 ? false : true));
			potentialUpdates.add(addedIU); //Make sure that we include the IU that we were initially trying to install

			Collection<IRequirement> newRequirement = new ArrayList<IRequirement>(1);
			IRequirement req = createORRequirement(potentialUpdates, allowPartialInstall || isRequestedInstallationOptional(addedIU, originalRequest));
			newRequirement.add(req);
			newRequest.addExtraRequirements(newRequirement);
			requirementsForElementsBeingInstalled.addAll(newRequirement);
			rememberIUProfileProperties(addedIU, req, originalRequest, false);
		}

		//Deal with the IUs requested for removal
		newRequest.removeAll(originalRequest.getRemovals());

		//Deal with extra requirements that could have been specified
		if (originalRequest.getExtraRequirements() != null)
			newRequest.addExtraRequirements(originalRequest.getExtraRequirements());
	}

	//This keeps track for each requirement created (those created to loosen the constraint), of the original IU and the properties associated with it in the profile
	//This is used for more easily construct the final profile change request
	private void rememberIUProfileProperties(IInstallableUnit iu, IRequirement req, IProfileChangeRequest originalRequest, boolean includeProfile) {
		Map<String, String> allProperties = new HashMap<String, String>();
		if (includeProfile) {
			Map<String, String> tmp = new HashMap<String, String>(profile.getInstallableUnitProperties(iu));
			List<String> propertiesToRemove = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToRemove().get(iu);
			if (propertiesToRemove != null) {
				for (String toRemove : propertiesToRemove) {
					tmp.remove(toRemove);
				}
			}
			allProperties.putAll(tmp);
		}

		Map<String, String> propertiesInRequest = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToAdd().get(iu);
		if (propertiesInRequest != null)
			allProperties.putAll(propertiesInRequest);

		propertiesPerRequirement.put(req, allProperties);

		List<String> removalInRequest = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToRemove().get(iu);
		if (removalInRequest != null)
			removedPropertiesPerRequirement.put(req, removalInRequest);
	}

	private boolean isRequestedInstallationOptional(IInstallableUnit iu, IProfileChangeRequest originalRequest) {
		Map<String, String> match = ((ProfileChangeRequest) originalRequest).getInstallableUnitProfilePropertiesToAdd().get(iu);
		if (match == null)
			return false;
		return INCLUSION_OPTIONAL.equals(match.get(INCLUSION_RULES));
	}

	private Collection<IInstallableUnit> findAllVersionsAvailable(IInstallableUnit iu, IProgressMonitor monitor) {
		Collection<IInstallableUnit> allVersions = new HashSet<IInstallableUnit>();
		SubMonitor sub = SubMonitor.convert(monitor, 2);
		allVersions.addAll(findIUsWithSameId(iu, sub.newChild(1)));
		allVersions.addAll(findUpdates(iu, sub.newChild(1)));
		return allVersions;
	}

	private Collection<IInstallableUnit> findIUsWithSameId(IInstallableUnit iu, IProgressMonitor monitor) {
		SubMonitor sub = SubMonitor.convert(monitor, 2);
		IQueryable<IInstallableUnit> metadata = provisioningContext.getMetadata(sub.newChild(1));
		return metadata.query(QueryUtil.createIUQuery(iu.getId()), sub.newChild(1)).toUnmodifiableSet();
	}

	private Collection<IInstallableUnit> findUpdates(IInstallableUnit iu, IProgressMonitor monitor) {
		SubMonitor subMonitor = SubMonitor.convert(monitor, 1);
		Collection<IInstallableUnit> availableUpdates = new HashSet<IInstallableUnit>();
		IQueryResult<IInstallableUnit> updatesAvailable = planner.updatesFor(iu, provisioningContext, subMonitor.split(1));
		for (Iterator<IInstallableUnit> iterator = updatesAvailable.iterator(); iterator.hasNext();) {
			availableUpdates.add(iterator.next());
		}
		return availableUpdates;
	}

	//Create an OR expression that is matching all the entries from the given collection
	private IRequirement createORRequirement(Collection<IInstallableUnit> findUpdates, boolean optional) {
		StringBuffer expression = new StringBuffer();
		Object[] expressionParameters = new Object[findUpdates.size() * 2];
		int count = 0;
		for (IInstallableUnit iu : findUpdates) {
			expression.append("(id == $").append(count * 2).append(" && version == $").append(count * 2 + 1).append(')'); //$NON-NLS-1$//$NON-NLS-2$
			if (findUpdates.size() > 1 && count < findUpdates.size() - 1)
				expression.append(" || "); //$NON-NLS-1$
			expressionParameters[count * 2] = iu.getId();
			expressionParameters[count * 2 + 1] = iu.getVersion();
			count++;
		}
		IMatchExpression<IInstallableUnit> iuMatcher = ExpressionUtil.getFactory().<IInstallableUnit> matchExpression(ExpressionUtil.parse(expression.toString()), expressionParameters);
		return MetadataFactory.createRequirement(iuMatcher, null, optional ? 0 : 1, 1, true);
	}

	//Loosen up the IUs that are already part of the profile
	//Given how we are creating our request, this needs to take into account the removal from the original request as well as the change in inclusion 
	private IProfileChangeRequest loosenUpInstalledSoftware(IProfileChangeRequest request, IProfileChangeRequest originalRequest, IProgressMonitor monitor) {
		if (!allowInstalledRemoval && !allowInstalledUpdate)
			return request;
		Set<IInstallableUnit> allRoots = getRoots();

		for (IInstallableUnit existingIU : allRoots) {
			Collection<IInstallableUnit> potentialUpdates = allowInstalledUpdate ? findUpdates(existingIU, monitor) : new HashSet<IInstallableUnit>();
			foundDifferentVersionsForElementsInstalled = (foundDifferentVersionsForElementsInstalled || (potentialUpdates.size() == 0 ? false : true));
			potentialUpdates.add(existingIU);
			Collection<IRequirement> newRequirement = new ArrayList<IRequirement>(1);
			//when the element is requested for removal or is installed optionally we make sure to mark it optional, otherwise the removal woudl fail
			IRequirement req = createORRequirement(potentialUpdates, allowInstalledRemoval || removalRequested(existingIU, originalRequest) || isOptionallyInstalled(existingIU, originalRequest));
			newRequirement.add(req);
			request.addExtraRequirements(newRequirement);
			requirementsForElementsAlreadyInstalled.addAll(newRequirement);
			request.remove(existingIU);
			rememberIUProfileProperties(existingIU, req, originalRequest, true);
		}

		return request;
	}

	private Set<IInstallableUnit> getRoots() {
		Set<IInstallableUnit> allRoots = profile.query(new IUProfilePropertyQuery(INCLUSION_RULES, IUProfilePropertyQuery.ANY), null).toSet();
		if (!honorSharedSettings)
			return allRoots;
		IQueryResult<IInstallableUnit> baseRoots = profile.query(new IUProfilePropertyQuery("org.eclipse.equinox.p2.base", Boolean.TRUE.toString()), null);
		allRoots.removeAll(baseRoots.toUnmodifiableSet());
		return allRoots;
	}

	//This return whether or not the given IU is installed optionally or not.
	//This also take into account the future state
	private boolean isOptionallyInstalled(IInstallableUnit existingIU, IProfileChangeRequest request) {
		return computeFutureStateOfInclusion((ProfileChangeRequest) request).contains(existingIU);
	}

	//Given the change request, this returns the collection of optional IUs 
	private Set<IInstallableUnit> computeFutureStateOfInclusion(ProfileChangeRequest profileChangeRequest) {
		if (futureOptionalIUs != null)
			return futureOptionalIUs;

		futureOptionalIUs = profileChangeRequest.getProfile().query(new IUProfilePropertyQuery(INCLUSION_RULES, INCLUSION_OPTIONAL), null).toSet();

		Set<Entry<IInstallableUnit, List<String>>> propertiesBeingRemoved = profileChangeRequest.getInstallableUnitProfilePropertiesToRemove().entrySet();
		for (Entry<IInstallableUnit, List<String>> propertyRemoved : propertiesBeingRemoved) {
			if (propertyRemoved.getValue().contains(INCLUSION_RULES)) {
				futureOptionalIUs.remove(propertyRemoved.getKey());
			}
		}

		Set<Entry<IInstallableUnit, Map<String, String>>> propertiesBeingAdded = profileChangeRequest.getInstallableUnitProfilePropertiesToAdd().entrySet();
		for (Entry<IInstallableUnit, Map<String, String>> propertyBeingAdded : propertiesBeingAdded) {
			String inclusionRule = propertyBeingAdded.getValue().get(INCLUSION_RULES);
			if (inclusionRule == null) {
				continue;
			}
			if (INCLUSION_STRICT.equals(inclusionRule)) {
				futureOptionalIUs.remove(propertyBeingAdded.getKey());
			}
			if (INCLUSION_OPTIONAL.equals(inclusionRule)) {
				futureOptionalIUs.add(propertyBeingAdded.getKey());
			}
		}
		return futureOptionalIUs;
	}

	private boolean productContainmentOK(IProvisioningPlan intermediaryPlan) {
		if (!ensureProductPresence)
			return true;
		if (!hasProduct())
			return true;
		//At this point we know we had a product installed and we want to make sure there is one in the resulting solution
		if (!intermediaryPlan.getFutureState().query(QueryUtil.createIUProductQuery(), new NullProgressMonitor()).isEmpty())
			return true;
		//Support for legacy identification of product using the lineUp.
		if (!intermediaryPlan.getFutureState().query(QueryUtil.createIUPropertyQuery("lineUp", "true"), new NullProgressMonitor()).isEmpty()) //$NON-NLS-1$//$NON-NLS-2$
			return true;
		return false;
	}

	private boolean hasProduct() {
		if (!profile.available(QueryUtil.createIUProductQuery(), new NullProgressMonitor()).isEmpty()) {
			return true;
		}
		//Support for legacy identification of product using the lineUp.
		if (!profile.available(QueryUtil.createIUPropertyQuery("lineUp", "true"), new NullProgressMonitor()).isEmpty()) //$NON-NLS-1$//$NON-NLS-2$
			return true;
		return false;
	}

}
