/*!
**********************************************************************
@file WizardPayload.js

Copyright 2003-2006 Adobe Systems Incorporated.                     
All Rights Reserved.                                                
                                                                    
NOTICE: All information contained herein is the property of Adobe   
Systems Incorporated.                                                                                                                    

***********************************************************************
*/

/*function WizardPayload(inSession, inInstallerPayload, inMode, inErrorContainer)*/
function WizardPayload(inWizardPayloadSelect, inInstallerPayload)
{
	this.wizardSelect = inWizardPayloadSelect;
	this.session = this.wizardSelect.session;
	this.payload = inInstallerPayload;

	// A mode for deciding what checked and unchecked means
	this.mode = this.wizardSelect.mode;

	// A place to put errors
	this.errorbox = this.wizardSelect.wizardError;

	// Get the scoop on the payload
	this.checkbox = null;

	// Size may change depending on selection.
	this.OperationSize = new AdobeProperty(this.payload.OperationSize(true).totalBytes);

	// Fabricate the UI
	this.DOM = this._CreateDOM();
	
	
	// Sync the UI install state with the payload install state
	//this.actionMap = this.payload.GetUISelectionAction(this.session, this.mode);
	//this.Refresh();
}


WizardPayload.prototype._CreateDOM = function()
{
	// Checkbox
	var inputElement = document.createElement("input");
	inputElement.setAttribute("type", "checkbox");
	var thisCB = this;
	inputElement.onclick = function() {	thisCB.SetCheckBox(); };
	this.checkbox = inputElement;

	// Name
	var nameText = this.payload.GetUIProductName(this.session);
	var nameTextNode = document.createTextNode(nameText);
	
	// Annotation
	this.payloadNote = document.createElement("span");
	this.payloadNote.className = "payloadNote";

	// Size
	var spanElement = document.createElement("span");
	spanElement.className = "componentSize";
	this.OperationSize.Bind(spanElement, bytesToText);

	// Final Container assembly
	var ddElement = document.createElement("dd");
	ddElement.appendChild(inputElement);
	ddElement.appendChild(nameTextNode);
	ddElement.appendChild(this.payloadNote);
	ddElement.appendChild(spanElement);

	return ddElement;
}


WizardPayload.prototype.SetCheckBox = function()
{
	this.actionMap = this.payload.GetUISelectionAction(this.session, this.mode, this.checkbox.checked);
	if (this.payload.policyNode && (this.actionMap.checkedState == this.checkbox.checked))
	{
		this.payload.policyNode.SetAffinity();
	}
	this.wizardSelect.Refresh();
}


/**
Make the UI view match the InstallerPayload model.
*/
WizardPayload.prototype.Refresh = function()
{
	this.actionMap = this.payload.GetUISelectionAction(this.session, this.mode);
	if (this.actionMap.visible)
	{
		if (this.actionMap.selectable)
		{
			this.checkbox.disabled = false;
			this.DOM.className = "";
		}
		else
		{
			this.checkbox.disabled = true;
			this.DOM.className = "disabled";
		}
	}
	else
	{
		this.checkbox.disabled = true;
		this.DOM.className = "hidden";
	}

	this.checkbox.checked = this.actionMap.checkedState;
	this.checkbox.defaultChecked = this.checkbox.checked;

	if (this.errorbox)
	{
		if (this.checkbox.checked && !this.checkbox.disabled)
		{
			this.errorbox.ClearError("atleastone");
		}
	}

	// Set the payload annotation
	if (this.payloadNote)
	{
		RemoveAllChildren(this.payloadNote);
		if (this.actionMap.payloadNote)
		{
			this.payloadNote.appendChild(document.createTextNode("(" + this.actionMap.payloadNote.Translate(this.session.localization) + ")"));
		}
	}
	
	// Register any errors/warnings from the InstallerPayload
	if (this.actionMap.visible && this.errorbox && this.actionMap.payloadError)
	{
		var errors = null;
		if (this.actionMap.payloadError.id && this.actionMap.payloadError.text)
		{
			errors = new Object();
			errors[this.actionMap.payloadError.id] = this.actionMap.payloadError;
		}
		else
		{
			errors = this.actionMap.payloadError;
		}
		for (var errorId in errors)
		{
			var errorObj = errors[errorId];
			this.errorbox.AddError(errorId, errorObj.className,  errorObj.text);
		}
	}

	return this.actionMap.selectable ? 1 : 0;
}



/**
Return the DOM for the user interface to show/select this payload.
*/
WizardPayload.prototype.GetUIDOM = function()
{
	return this.DOM;
}



function WizardPayloadSelect(inSession, inMode, inListElement, inWizardError, inOptContainer)
{
	// Stash our input.
	this.session = inSession;
	this.mode = inMode;
	this.listElement = inListElement;
	this.wizardError = inWizardError;
	this.container = inOptContainer;

	// Get the payload list.
	this.payloads = PayloadUISort(inSession.sessionPayloads, inSession);
	
	// Keep track of how much space we need.
	this.totalSize = new AdobeProperty();
	
	// Keep track of whether or not all selectable options are selected.
	this.allSelected = new AdobeProperty(false);
	
	// Assemble the WizardPayload objects.
	this.uipayloads = new Array();
	for (var p in this.payloads)
	{
		var wp = new WizardPayload(this, this.payloads[p]);
		if (wp)
		{
			this.uipayloads.push(wp);
		}
	}
	
	// Update visibility and selectability.
	var count = this.Refresh();

	// We may be passed a function so the client can redirect
	// where a WizardPayload appears in the DOM on a payload
	// by payload basis.
	var GetListElement = function(inPayload)
	{
		if ("function" == typeof inListElement)
		{
			return inListElement(inPayload);
		}
		return inListElement;
	}

	// Assemble the UI.
	if (count.uiVisible > 0 && this.listElement)
	{
		RemoveAllChildren(GetListElement(null));
		for (var pIndex = 0; pIndex < this.uipayloads.length; pIndex++)
		{
			var dom = this.uipayloads[pIndex].GetUIDOM();
			if (dom)
			{
				GetListElement(this.uipayloads[pIndex]).appendChild(dom);
			}
		}
	}

	// Hide the container if it exists and there isn't anything to select.
	if (this.container)
	{
		this.container.style.visibility = count.uiVisible > 0 ? "visible" : "hidden";
	}

	// Make sure everything is in order.
	//this.ValidateSelections();
}


WizardPayloadSelect.prototype.ValidateSelections = function()
{
	var sessionIsValid = true;
	
	// Clear any errors this would generate
	var errorprefix = "WPS.";
	this.wizardError.ClearErrorsMatching("^WPS\..*");

	// Simulate installation and return any conflicts that would occur during that process
	try
	{
		_simulatePayloadOperations(this.session);
		
		// Report the results
		for (var anAdobeCode in this.session.sessionPayloads)
		{
			var aPayload = this.session.sessionPayloads[anAdobeCode];
			this.session.LogDebug("WizardPayloadSelect.ValidateSelections: checking operaiton result for " + aPayload.LogID());
			if (aPayload.GetOperationResult()
				&& aPayload.GetOperationResult().message
				&& aPayload.GetOperationResult().message.simulationResults)
			{
				var simulationResults = aPayload.GetOperationResult().message.simulationResults;
				for (var conflictIndex = 0; conflictIndex < simulationResults.conflicting.length; ++conflictIndex)
				{
					sessionIsValid = false;
					var conflictingAdobeCode = simulationResults.conflicting[conflictIndex];
					var conflictingPayload = this.session.allPayloads[conflictingAdobeCode];
					this.wizardError.AddError(errorprefix + "conflict" + anAdobeCode + conflictingAdobeCode, "critical",
						aPayload.GetUIProductName(this.session)
						+ " cannot be installed alongside "
						+ conflictingPayload.GetUIProductName(this.session));
				}
			}
			else
			{
				this.session.LogDebug("WizardPayloadSelect.ValidateSelections: no operation result message for " + aPayload.LogID());
				this.session.LogDebug(aPayload.GetOperationResult());
			}
		}
	}
	catch (ex)
	{
		this.session.LogError("Simulation exception, skipping additional conflict reporting.");
	}
	
	// Load the template string so we can substitute the values for the entries
	
	
	// Report any payload requirements that would not be met if the installation were to proceed
	var unsatisfiedRequirementsArray = this.session.AccumulateUnmetRequirements();
	for (var index = 0; index < unsatisfiedRequirementsArray.length; ++index)
	{
		sessionIsValid = false;
		var curRequirement = unsatisfiedRequirementsArray[index];
		
		var substParams = new Object();
		substParams["payload1"] = curRequirement.owningPayload.GetUIProductName(this.session);
		substParams["payload2"] = curRequirement.productName;
		
		var dependencyErrorText = this.session.localization.GetString('locRequirePayloadInstalled', curRequirement.owningPayload.GetUIProductName(this.session) + " requires " + curRequirement.productName + " to be installed.", substParams);
		this.wizardError.AddError(errorprefix + "dependency" + curRequirement.owningPayload.GetAdobeCode + curRequirement.productName, 
									"critical",
									dependencyErrorText);
	}
	
	// Update the total size
	this.totalSize.Set(this.session.OperationSize().totalBytes);

	return sessionIsValid;
}


WizardPayloadSelect.prototype.SelectAll = function()
{
	// Get our session payloads and order them.
	var payloads = PayloadDependencySort(this.payloads, this.mode == kInstallerModeRemove || this.allSelected.Get());

	// Select/Deselect appropriately
	for (var p in payloads)
	{
		var actionMap = payloads[p].GetUISelectionAction(this.session, this.mode);
		if (actionMap.selectable)
		{
			payloads[p].GetUISelectionAction(this.session, this.mode, !this.allSelected.Get());
		}
	}

	this.Refresh();
}


WizardPayloadSelect.prototype.Refresh = function()
{
	var retVal = {
		uiVisible: 0,
		uiSelectable: 0,
		uiSelected: 0
	};
	
	// Clear some errors.
	if (this.wizardError)
	{
		this.wizardError.ClearErrorsMatching("^InstallerPayload\..*");
		this.wizardError.ClearError("WizardPayload.AtLeastOne");
	}

	// Refresh each payload
	for (var pIndex = 0; pIndex < this.uipayloads.length; pIndex++)
	{
		this.uipayloads[pIndex].Refresh();
	}

	// Figure out totals for selectable and selected
	for ( pIndex = 0; pIndex < this.uipayloads.length; pIndex++)
	{
		if (this.uipayloads[pIndex].actionMap.visible)
		{
			retVal.uiVisible++;
		}
		if (this.uipayloads[pIndex].actionMap.selectable)
		{
			retVal.uiSelectable++;
			if (this.uipayloads[pIndex].actionMap.checkedState)
			{
				retVal.uiSelected++;
			}
		}
	}

	// Throw up an error if we don't meet the minimim selected threshold.
	var selectionMinimum = this.mode == kInstallerModeRemove ? 1 : 0;
	if (this.wizardError && retVal.uiVisible > 0 && retVal.uiSelected < selectionMinimum)
	{
		this.wizardError.AddError("WizardPayload.AtLeastOne", "critical", this.session.localization.GetString("locErrorNoSelections", "At least one component must be selected."));
	}

	// Set the property indicating whether or not everything is selected.  Useful for,
	// say, a Select/Deselect All button whose behavior changes depending on whether or
	// not everything is selected.
	this.allSelected.Set(retVal.uiSelectable == retVal.uiSelected);

	// Update the total size
	this.totalSize.Set(this.session.OperationSize().totalBytes);

	return retVal;
}


/*
LEGACY: Return the number of payloads selected by the user.
*/
WizardPayloadSelect.prototype.SelectCount = function()
{
	return this.Refresh();
}
