//File:		CTSUEng.js
//Author:	Guo Tao
//Dept. :	Convergence SW R&D
//CopyRight:	Creative Technology Ltd., 2001-2002 All rights reserved
//Created on:	02/08/2002
//Modified on:	01/11/2003	Support Multi-product update in 1.50.xx

/****************************************************************************************************************
 *														*
 *				Object CTSUEng()								*
 *				Wrapper class of ActiveX object CTSUEng.ocx					*
 *														*
 ****************************************************************************************************************/

//Message Handler: int CTSUProc(nMsg, varParam1, varParam2, varParam3, varParam4, varParam5)
//Messages are defined in Message.js

//Define constances
var PRODUCT_TYPE_APPLICATION=1;
var PRODUCT_TYPE_HARDWARE=2;

var COMPONENT_STATUS_HIDDEN=0;
var COMPONENT_STATUS_DESELECTED=1;
var COMPONENT_STATUS_SELECTED=2;

var COMPONENT_CATEGORY_RECOMMENDED=0;
var COMPONENT_CATEGORY_CRITICAL=1;
var COMPONENT_CATEGORY_COMPULSORY=2;

var COMPONENT_LIST_LISTBYCOMPONENT=0;
var COMPONENT_LIST_LISTBYPRODUCT=1;

var COMPANY_ID_CREATIVE=65536;
var COMPANY_ID_SIBOC=65537;
var COMPANY_ID_DELL=65538;
var COMPANY_ID_CREATIVEGENERIC=65545;
var COMPANY_ALL=268435455;

//Define error codes returned
var RETURN_ERROR_SUCCESS=0;
var RETURN_ERROR_USERCANCEL=1;
var RETURN_ERROR_NOMEMORY=2;

//Error Codes for Downloading files
var RETURN_ERROR_NOSPACE=23;
var RETURN_ERROR_NEEDPOSTCHECK=36;
var RETURN_ERROR_EXCLUSIVEPACK=37;
var RETURN_ERROR_MUSTREBOOT=38;

function CTSUEng(id)
{
	this.obj = 'CTSUEng'
	eval(this.obj+'=this')

	//Global variables and methods
	this.CTSU=id;	//CTSU Object; should not be null
	this.bGoToNext=false;	//GO_TO_NEXT flag
	this.bnCancel=null;	//Object pointing to the button which can cancel the thread
	this.bLastPause=false;	//TRUE if hold the last status for a second; else FALSE.
	this.bCTSUInit=false;
	this.bUserCancalled=false; //TRUE if user cancels any threads.

	this.CancelThread=fCancelThread; //Stop the thread
	this.OnBeforeUnload=fOnBeforeUnload; //called before unload the page
	this.Release=fRelease; //Delete all the instances from the memory. Called when the page is unloaded.
	this.CTSUProc=null;	//Message handler

	//Properties and methods for Product Pages
	this.winObject=null;
	this.nProductNum=0;	//Total NO. of products
	this.fmProduct=null;	//Object pointing to Product FORM
	this.bnChkUpdate=null;	//Object pointing to the button which launches the contact thread

	this.InitProductPage=fInitProductPage; //Initial function of product page; called when product page is loaded
	this.IgnorePID=fIgnorePID; //Filter out the hardware which has not been enabled for software-update;
	this.AddCompanyID=fAddCompanyID; //Add hardware company ID; -1 to clear the list;
	this.GetProduct=fGetProduct; // Get SU-enabled products
	this.CheckGetProductThreadStatus=fCheckGetProductThreadStatus; //Function to monitor GetProduct Thread
	this.SetProductCheckStatus=fSetProductCheckStatus; //Set the product check status; called once a product is selected/deselected
	this.CheckUpdates=fCheckUpdates; //Function to launch contact thread
	this.CheckContactThreadStatus=fCheckContactThreadStatus; //Function to monitor the contact thread
	this.ConfirmContactThreadSuccess=fConfirmContactThreadSuccess; //Function to confirm the thread is successful.
	this.CancelContactThread=fCancelContactThread; //Function to cancel the contact thread

	//Properties and methods for Component page
	this.nListType=COMPONENT_LIST_LISTBYCOMPONENT; //List the components by products
	this.bUserCancelled=false; //Flag to indicate the thread is cancelled by user
	this.fmComponent=null;	//Object pointing to component form
	this.bnDownload=null;	//Object pointing to the button which launches the download thread
	this.nComponentNum=0;	//Total NO. of components
	this.nComponentShowNum=0; //Total NO. of components shown
	this.nTotalPageNum=0;	//Total NO of pages=ceil(nComponentShowNum/nComponentListLen)
	this.Pages=null;	//Array to record the start component of each page
	this.nComponentListLen=0; //No of component in the list. Default is LIST_ALL
	this.nTotalSelComponentNum=0; //Total number of selected components
	this.nTotalDLSize=0; //Total download size of the selected components
	this.nTotalDLCompSize=0; //Total size of downloaded components
	this.bDownloadComplete=false; //Flag to indicate whether the download is complete
	this.bDownloaded=false;	//Flag to indicate any component is downloaded
	this.bInstalled=false; //Flag to indicate any component is installed
	this.bExclusiveLaunched=false; //Flag to indicate the exclusive pack is launched
	this.bLocal=false; //Flag to indicate whether it is local client.

	this.aryMap=new Array(); //store Component Index and product/component index; For multi-product mode only

	this.InitComponentPage=fInitComponentPage; //Initial function of component page; called when component page is loaded
	this.IsExclusive=fIsExclusive; //Check whether it is exclusive package.
	this.SetComponentListLen=fSetComponentListLen; //Set the numbr of components in the component list
	this.ShowValidComponent=fShowValidComponent; //Get the list of valid component
	this.HasRecommendComponent=fHasRecommendComponent; //Flag to indicate whether there are recommended components available.
	this.ShowAllComponent=fShowAllComponent; //Show all the components
	this.SetComponentCheck=fSetComponentCheck; //Set the check status of the component
	this.GetComponentDesc=fGetComponentDesc; //Get the full description of the component
	this.SelectAllComponents=fSelectAllComponents; //Select all the components from the list
	this.StartDownloadInstallProcess=fStartDownloadInstallProcess; //Start download and install process
	this.DownloadComponent=fDownloadComponent; //Download thread
	this.CheckDownloadThreadStatus=fCheckDownloadThreadStatus; //Check the status of download thread
	this.InstallComponent=fInstallComponent;  //Install thread
	this.CheckInstallThreadStatus=fCheckInstallThreadStatus; //Check the status of install thread
	this.CancelDownloadInstallThread=fCancelDownloadInstallThread;
	this.GetTotalSelData=fGetTotalSelData; //Private function to calculate the total data of selected components;
	this.IsDownloadInstalling=fIsDownloadInstalling; //Check download/install is processing or not
	this.GetAllSelCompName=fGetAllSelCompName; //Get name list of all selected components
	this.CheckExclusivePack=fCheckExclusivePack; //Is there any exclusive package selected
	this.IsProductChecked=fIsProductChecked; //Check whether targeted products of a component are checked or not
	this.EnableAllComponents=fEnableAllComponents; //Enable all components
}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fCancelThread()									|
|	Description	Try to cancel the current thread; The thread could be anyone of the followings:	|
|				Contact Thread								|
|				Download Thread								|
|				Install Thread								|
|				Refresh Thread								|
|	Parameters 	szMsg - String prompted out to the user to confirm the cancel action.		|
|				If it is null, then just stop the thread without warning message	|
|	return		True if thread is stopped; False if user cancels the stop action		|
---------------------------------------------------------------------------------------------------------
*/
function fCancelThread(szMsg)
{
	if(szMsg==null)
	{
		this.CTSU.StopCurrentThread()
	}else
	{
		this.CTSU.PauseCurrentThread(true) //Set the flag to pause download process
		if(confirm(szMsg))
		{	//Stop the tread
			this.CTSU.StopCurrentThread()
		}else
		{	//continue the thread
			this.CTSU.PauseCurrentThread(false)
			return false
		}
	}
	return true
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fOnBeforeUnload()							|
|	Description	Called before the page is unloaded.					|
|			If user tries to exit the wizard, the warning message is prompted out.	|
|	Parameters	szMsg - warning message
-------------------------------------------------------------------------------------------------
*/
function fOnBeforeUnload(szMsg)
{
	if(!this.bGoToNext) event.returnValue=szMsg
}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fRelease()									|
|	Description	save the current SU data and delete all instances from memory			|
|	Parameters	bDelArchive - TRUE if the local archive file should be removed			|
|			bReboot - TRUE if user wants the machine to be rebooted.			|
|				Rebooting is also controlled by the internal flag.			|
|				Only when user requires the reboot and the internal flag is set by OCX,	|
|				then the machine will be rebooted.					|
---------------------------------------------------------------------------------------------------------
*/
function fRelease(bDelArchive, bReboot)
{
	if(!bDelArchive) this.CTSU.SaveSUData();
	this.CTSU.OnFinish(bDelArchive, bReboot);
}
/*
-------------------------------------------------------------------------------------------------------------------------
|	Function	fInitProductPage()										|
|	Description	Initial function of product page. Called when the product page is loaded.			|
|	Parameters	fmProduct - Object point to product form.							|
|			bnChkUpdate - Object point to the button which launch contact thread. Ignored if null.		|
|			bnCancel - Object point to the button which cancel the contact thread. Ignored if null.		|
|			szSUPriServer - software update primary contact server						|
|			szSUSecServer - Software update backup contact server						|
|			nCompanyID - Company ID; by default, it is Creative						|
|			nDspLangID - Display language ID. 								|
|	Return		0 - successfully initialized									|
|			1 - Other client running									|
|			2 - Low memory											|
|			3 - Fail to load components									|
|			9 - Unable to detect any products on the user's system						|
-------------------------------------------------------------------------------------------------------------------------
*/
function fInitProductPage(fmProduct, bnChkUpdate, bnCancel, szSUPriServer, szSUSecServer, nCompanyID, nDspLangID)
{
	this.fmProduct=fmProduct;
	this.bnChkUpdate=bnChkUpdate;
	this.bnCancel=bnCancel;

	this.bCTSUInit=false;

	if(this.CTSUProc(MSG_CTSU_INITFAILED, this.CTSU.OnInit())!=MSG_RETURN_OKYES)
	{
		return -1;
	}else
	{
		this.bCTSUInit=true;
	}

	this.CTSU.SetSUContactServer(szSUPriServer, szSUSecServer) //Set su primary/backup contact servers

//	if(nCompanyID) this.CTSU.SetCompanyID(nCompanyID);

	this.CTSU.SetDspLang(nDspLangID);

	//Connected Devices only; started from RC 1.21.16
	this.CTSU.ConnectedDeviceOnly=true;
	//preset the removeafterinstall setting to fix the bug
//	var bAutoRemove=CTSU.RemoveAfterInstall;
//	CTSU.RemoveAfterInstall=bAutoRemove;
	return 0;
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fIgnorePID()								|
|	Description	Filter out the hardware which is not enabled for software-update	|
|	Parameters	szPIDName - a string containing list of PID names separated by $	|
|			szPID - a string containing list of PIDs separated by $			|
-------------------------------------------------------------------------------------------------
*/
function fIgnorePID(szPIDName, szPID)
{
	this.CTSU.FilterOutPID(szPIDName, szPID);
}
/*
-----------------------------------------------------------------------------------------
|	Function	fAddCompanyID()							|
|	Description	Add hardware company ID into list				|
|	Parameters	nCompanyID - Valid Company ID or -1 to clear the list		|
-----------------------------------------------------------------------------------------
*/
function fAddCompanyID(nCompanyID)
{
	this.CTSU.SetCompanyID(nCompanyID);
}
/*
-------------------------------------------------------------------------------------------------------------------------
|	Function	fGetProduct()											|
|	Description	Get the list of products including SU-enabled applications/hardware				|
|	Parameters	szAppName - application subpath. NULL for check for all products				|
|			nAppLangID - application language ID. It may be different from display ID			|
|			szProductID - ID of products required to check for updates					|
|			szProductName - Name of products required to check for updates					|
|	Return		-1 - Fail to create thread to get products; 0 - success						|
-------------------------------------------------------------------------------------------------------------------------
*/
function fGetProduct(szAppName, nAppLangID, szProductID, szProductName)
{
	if(szAppName!=null)
	{	//Check for single application
		if(!this.CTSU.CTCheckUpdateForSingleApp(szAppName, nAppLangID))
			return -1;
	}
	else if(szProductID!=null)
	{	//Check for single product
		if(!this.CTSU.CTCheckUpdateForSingleProduct(szProductID)) return -1;
	}
	else if(szProductName!=null)
	{	//Check for product name
		if(!this.CTSU.CTCheckUpdateForProductName(szProductName)) return -1;
	}
	else
	{	//Check for all the creative products
		if(!this.CTSU.CTCheckUpdateForAll(true, true, true)) return -1;
	}

	this.bLastPause=true; //Enable last pause flag

	this.CheckGetProductThreadStatus()
	return 0;
}
/*
-------------------------------------------------------------------------------------------------------------------------
|	Function	fCheckGetProductThreadStatus()									|
|	Description	Monitor function to check the status of GetProduct thread					|
-------------------------------------------------------------------------------------------------------------------------
*/
function fCheckGetProductThreadStatus()
{
	var nCode=CTSU.GetLastThreadExitCode();
	if(nCode==-1)
	{
		this.CTSUProc(MSG_CTSU_GETPRODUCTPROGRESS, nCode, this.CTSU.ThreadParam2);
		setTimeout(this.obj+'.CheckGetProductThreadStatus()', 1000);
	}
	else if(nCode==0)
	{
		this.nProductNum=this.CTSU.GetTotalAvailableProduct(); //Get total number of products
		if(this.bLastPause)
		{	//Hold last status for a second
			this.bLastPause=false;
			this.CTSUProc(MSG_CTSU_GETPRODUCTPROGRESS, -1, this.nProductNum);
			setTimeout(this.obj+'.CheckGetProductThreadStatus()', 1000);
			return;
		}
		var bDisableChkUpdate=true;
		var szProdDesc
		for(var i=0;i<this.nProductNum;i++)
		{
			if(this.CTSU.ProductType(i)==PRODUCT_TYPE_APPLICATION)
				szProdDesc=this.CTSUProc(MSG_CTSU_FORMPRODUCTDESC, PRODUCT_TYPE_APPLICATION, this.CTSU.GetProductDesc(i), this.CTSU.AppVerString(i), '');
			else
				szProdDesc=this.CTSUProc(MSG_CTSU_FORMPRODUCTDESC, PRODUCT_TYPE_HARDWARE, this.CTSU.GetProductDesc(i), this.CTSU.FWVerString(i), this.CTSU.DRVerString(i));

			this.CTSUProc(MSG_CTSU_ENUMPRODUCT, i, szProdDesc, this.CTSU.ProductCheckStatus(i));
			if(this.CTSU.ProductCheckStatus(i)) bDisableChkUpdate=false;
		}

		if(this.bnChkUpdate) this.bnChkUpdate.disabled=bDisableChkUpdate;

		this.CTSUProc(MSG_CTSU_GETPRODUCTPROGRESS, nCode, this.nProductNum);

		if(this.bnCancel) this.bnCancel.disabled=true;
	}
	else
	{
		this.CTSUProc(MSG_CTSU_GETPRODUCTPROGRESS, nCode, -1);
	}

}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fSetProductCheckStatus()							|
|	Description	Set the product check status; called when the product is selected/deselected	|
|	Parameters	nIndex - product index number							|
|			bChecked - product check status							|
---------------------------------------------------------------------------------------------------------
*/
function fSetProductCheckStatus(nIndex, bChecked)
{
	this.CTSU.ProductCheckStatus(nIndex)=bChecked
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fCheckUpdates()										|
|	Description	Launch the contact thread								|
|	Return		TRUE if contact thread starts; FALSE if fail to launch the contact thread		|
-----------------------------------------------------------------------------------------------------------------
*/
function fCheckUpdates()
{
	if(!this.CTSU.CheckUpdates()) return false;

	if(this.bnChkUpdate!=null) this.bnChkUpdate.disabled=true;
	if(this.bnCancel!=null) this.bnCancel.disabled=false;

	this.bLastPause=true;
	this.bGoToNext=false;
	this.CheckContactThreadStatus();
	return true;
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fCheckContactThreadStatus()								|
|	Description	Monitor Function to check for contact thread every second.				|
|	Return		TRUE if continue to monitor; FALSE if stop monitoring or start go to the next step	|
-----------------------------------------------------------------------------------------------------------------
*/
function fCheckContactThreadStatus()
{	//Make sure the buttons
	if(this.bnCancel) this.bnCancel.disabled=false;
	if(this.bnChkUpdate) this.bnChkUpdate.disabled=true;

	//Check thread status
	var nCode=this.CTSU.GetLastThreadExitCode();
	this.CTSUProc(MSG_CTSU_CHECKUPDATEPROGRESS, nCode, this.CTSU.ThreadParam2)
	if(nCode==-1) //Still active
	{
		setTimeout(this.obj+'.CheckContactThreadStatus()', 1000)
	}
	else if(nCode==0) //Succeed
	{
		if(this.bLastPause)
		{	//Hold last status for a second
			this.bLastPause=false;
			this.CTSUProc(MSG_CTSU_CHECKUPDATEPROGRESS, -1, 100);
			setTimeout(this.obj+'.CheckContactThreadStatus()', 1000);
			return;
		}
		//Direct to the component page
		this.bGoToNext=true;
		if(this.fmProduct) this.fmProduct.submit();
		return false;
	}else
	{	//Failed; Change the buttons
		if(this.bnCancel) this.bnCancel.disabled=true;
		if(this.bnChkUpdate) this.bnChkUpdate.disabled=false;
		return false;
	}
	return true;
}
/*
----------------------------------------------------------------------------------------------------------
|	Function	fConfirmContactThreadSuccess()
|	Description
|
|
|--------------------------------------------------------------------------------------------------------
*/
function fConfirmContactThreadSuccess()
{
	if(this.bUserCancelled)
	{
		if(this.bnCancel) this.bnCancel.disabled=true;
		if(this.bnChkUpdate) this.bnChkUpdate.disabled=false;
	}
}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fCancelContactThread()								|
|	Description	Cancel the contact thread							|
|	Parameters 	szMsg - String prompted out to the user to confirm the cancel action.		|
|				If it is null, then just stop the thread without warning message	|
|	Return		TRUE if thread is stopped; FALSE if user cancel the stop action.		|
---------------------------------------------------------------------------------------------------------
*/
function fCancelContactThread(szMsg)
{
	if(!this.CancelThread(szMsg)) return false;
	return true;
}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fInitComponentPage()								|
|	Description	Initial function of component page						|
|	Parameters	fmComponent - Object point to component form.					|
|			bnDownload - Object point to the button which launch download thread.		|
|			bnCancel - Object point to the button which cancel the download thread.		|
|			szFTPServer - FTP download server. Set if integrated with FTP queuing system.	|
|			nCompListLen - Max. Number of components in one page. Default is all (0)	|
|	Return		1 if succeeds; -1 if init failed; 0 if all the components are hidden		|
---------------------------------------------------------------------------------------------------------
*/
function fInitComponentPage(fmComponent, bnDownload, bnCancel, szFTPServer, nCompListLen)
{
	this.fmComponent=fmComponent;
	this.bnDownload=bnDownload;
	this.bnCancel=bnCancel;

	this.bCTSUInit=false;
	if(this.CTSUProc(MSG_CTSU_INITFAILED, this.CTSU.OnInit())!=MSG_RETURN_OKYES)
		return -1;

	this.bCTSUInit=true;

	this.CTSU.LoadSUData(); //Load archive data

	if(szFTPServer) this.CTSU.SetFTPQueuingServer(szFTPServer)

	this.nComponentNum=this.CTSU.GetTotalAvailableComponent(-1)
	if(this.nComponentNum<=0) return -1;

	this.nComponentShowNum=0;

	for(var i=0;i<this.nComponentNum;i++)
	{	//Get the total number of component shown
		if(this.CTSU.ComponentCheckStatus(i)>COMPONENT_STATUS_HIDDEN)
		{
			this.nComponentShowNum++;
		}
	}
	if(this.nComponentShowNum<=0) return 0;

	this.SetComponentListLen(nCompListLen);

	return 1;
}
/*
---------------------------------------------------------------------------------
|	Function	fSetComponentListLen()					|
|	Description	Set the number of components in the list to show	|
|	Parameters	nCompNOInList - Valid components in the list.		|
---------------------------------------------------------------------------------
*/
function fSetComponentListLen(nCompNOInList)
{
	if(this.Pages) this.Pages.length=0;
	if(nCompNOInList<=0)
	{ //List all
		this.Pages=new Array(1)
		this.Pages[0]=0;
		this.nTotalPageNum=1;
		this.nComponentListLen=this.nComponentShowNum; //Show all
	}else
	{ //Set the total number of pages
		this.nComponentListLen=nCompNOInList;
		this.nTotalPageNum=Math.ceil(this.nComponentShowNum/this.nComponentListLen);
		this.Pages=new Array(this.nTotalPageNum)
		var nPage=0, nComp=-1;
		for(var i=0;i<this.nComponentNum;i++)
		{
			if(this.CTSU.ComponentCheckStatus(i)>COMPONENT_STATUS_HIDDEN)
			{
				nComp++;
				if(nComp>=nPage*this.nComponentListLen)
				{
					this.Pages[nPage]=i;
					nPage++;
				}
				if(nPage==this.nTotalPageNum) break;
			}
		}
	}
}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fShowValidComponent()								|
|	Description	Show the list of valid components						|
|	Parameters	nPageNO - page number of component list. 					|
---------------------------------------------------------------------------------------------------------
*/
function fShowValidComponent(nPageNO)
{
	if(nPageNO<0 || nPageNO>this.nTotalPageNum) return;

	if(this.nListType==COMPONENT_LIST_LISTBYCOMPONENT)
	{
		var nItem=0;
		for(var i=this.Pages[nPageNO];nItem<this.nComponentListLen && i<this.nComponentShowNum;i++)
		{
			if(this.CTSU.ComponentCheckStatus(i)>COMPONENT_STATUS_HIDDEN)
			{
				nItem++;
				this.CTSUProc(MSG_CTSU_ENUMCOMPONENT, i, (this.CTSU.ComponentCheckStatus(i)==COMPONENT_STATUS_SELECTED)?true:false, this.CTSU.GetComponentName(i), this.CTSU.GetComponentCategory(i), this.CTSU.GetComponentSize(i));
			}
		}
	}
	else if(this.nListType==COMPONENT_LIST_LISTBYPRODUCT)
	{
		var nNumValidComp=0, nMasterFile=0, i, nCount;

		nCount=0;

		while((nNumValidComp=this.CTSU.GetTotalAvailableComponent(nMasterFile))>=0)
		{
			if(nNumValidComp>0)
			{
				//Have valid components
				if(this.CTSU.ProductType(nMasterFile)==PRODUCT_TYPE_APPLICATION)
					szProdDesc=this.CTSUProc(MSG_CTSU_FORMPRODUCTDESC, PRODUCT_TYPE_APPLICATION, this.CTSU.GetProductDesc(nMasterFile), this.CTSU.AppVerString(nMasterFile), '');
				else
					szProdDesc=this.CTSUProc(MSG_CTSU_FORMPRODUCTDESC, PRODUCT_TYPE_HARDWARE, this.CTSU.GetProductDesc(nMasterFile), this.CTSU.FWVerString(nMasterFile), this.CTSU.DRVerString(nMasterFile));
				this.CTSUProc(MSG_CTSU_ENUMPRODUCT, nMasterFile, szProdDesc, 0);
			}

			for(i=0;i<nNumValidComp;i++)
			{
				var nCompIndex=this.CTSU.GetValidCompIndex(nMasterFile, i);
				if(nCompIndex>=0)
				{
					if(this.CTSU.ComponentCheckStatus(nCompIndex)>COMPONENT_STATUS_HIDDEN)
					{
						this.CTSUProc(MSG_CTSU_ENUMCOMPONENT, nCompIndex, (this.CTSU.ComponentCheckStatus(nCompIndex)==COMPONENT_STATUS_SELECTED)?true:false, this.CTSU.GetComponentName(nCompIndex), this.CTSU.GetComponentCategory(nCompIndex), this.CTSU.GetComponentSize(nCompIndex));
						this.aryMap[nCount]=new Array();
						this.aryMap[nCount][0]=nMasterFile; //Store product index
						this.aryMap[nCount][1]=nCompIndex; //Store component index
						this.aryMap[nCount][2]=(this.CTSU.ComponentCheckStatus(nCompIndex)==COMPONENT_STATUS_SELECTED)?true:false; //Store component check status
						nCount++;
					}
				}
			}
			nMasterFile++;
		}	
	}
	this.GetTotalSelData();
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fHasRecommendComponent							|
|	Description	Check whether there are any recommended components			|
|	Return		true: there are some recommended components; false: do not have any	|
-------------------------------------------------------------------------------------------------
*/
function fHasRecommendComponent()
{
	for(var i=0;i<this.nComponentNum;i++)
	{
		if(this.CTSU.GetComponentCategory(i)==COMPONENT_CATEGORY_RECOMMENDED) return true;
	}
	return false;
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fIsExclusive								|
|	Description	Check whether the package is exclusive					|
|	return		true/false								|
-------------------------------------------------------------------------------------------------
*/
function fIsExclusive(nIndex)
{
	return this.CTSU.IsCompExclusive(nIndex);
}
/*
-----------------------------------------------------------------------------------------------
|	Function	fCheckExclusivePack()
|	Description	Check whether any exclusive package select
|	return		-1 - no exclusive package selected; >=0 index of exclusive package
----------------------------------------------------------------------------------------------
*/
function fCheckExclusivePack()
{
	for(var i=0;i<this.nComponentNum;i++)
	{
		if(this.IsExclusive(i))
		{
			if(this.CTSU.ComponentCheckStatus(i)==COMPONENT_STATUS_SELECTED)
			{
				if(this.IsProductChecked(i)) return i;
			}
		}
	}
	return -1;
}
/*
-----------------------------------------------------------------------------------------
|	Function	fShowAllComponent						|
|	Description	Set the status of all components to 'SHOW'			|
|----------------------------------------------------------------------------------------
*/
function fShowAllComponent()
{
	for(var i=0;i<this.nComponentNum;i++)
	{
		if(this.CTSU.ComponentCheckStatus(i)==COMPONENT_STATUS_HIDDEN) this.CTSU.ComponentCheckStatus(i)=COMPONENT_STATUS_DESELECTED;
	}
	this.nComponentShowNum=this.nComponentNum;
	this.SetComponentListLen(this.nComponentListLen);
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fGetTotalSelData							|
|	Description	Private function to calculate the total data of selected components;	|
|			It updates two properties: nTotalSelComponentNum, nTotalDLSize,		|
-------------------------------------------------------------------------------------------------
*/
function fGetTotalSelData()
{
	this.nTotalSelComponentNum=0;
	this.nTotalDLSize=0;
	for(var i=0;i<this.nComponentNum;i++)
	{
		if((this.IsProductChecked(i)==true) && (this.CTSU.ComponentCheckStatus(i)==COMPONENT_STATUS_SELECTED))
		{
			this.nTotalSelComponentNum++;
			this.nTotalDLSize+=this.CTSU.GetComponentSize(i);
		}
	}

	this.CTSUProc(MSG_CTSU_TOTALSELECTCHANGED, this.nTotalSelComponentNum, this.nTotalDLSize);
	if(!CTSU.IsDownloadInstalling())
	{
		if(this.bnDownload) this.bnDownload.disabled=(this.nTotalSelComponentNum==0);
	}
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fSetComponentCheck									|
|	Description	Set component check status								|
|	Parameters	nProdIndex - Product Index; -1 for all products
|			nIndex - index number of the component							|
|			nCompStatus - 2 if component is selected, 1 if it is deselected or 0 if it is hidden	|
|	Return		integer passed from CTSUProc; By default, it is MSG_RETURN_OKYES: Status is set.	|
-----------------------------------------------------------------------------------------------------------------
*/
function fSetComponentCheck(nProdIndex, nIndex, nCompStatus)
{
	var nReturn=MSG_RETURN_OKYES;

	if(this.CTSU.GetComponentCategory(nIndex)==COMPONENT_CATEGORY_COMPULSORY)
	{
		if(!this.IsDownloadInstalling())
		{
			this.CTSUProc(MSG_CTSU_COMPULSORYCOMPONENTCHANGING);
			this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, nIndex, COMPONENT_STATUS_SELECTED);
		}
		return MSG_RETURN_CANCEL;
	}

	var nNode=this.CTSU.CheckDpdComponent(nIndex, nCompStatus);
	var bIsExclusive=this.IsExclusive(nIndex);
	var nExcIndex=this.CheckExclusivePack();

	if(nNode>0 || bIsExclusive || nExcIndex>=0) //There are some dpd components
	{
		nReturn=this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGING, nCompStatus, this.CTSU.GetComponentName(nIndex), bIsExclusive, nExcIndex);

		if(nReturn==MSG_RETURN_OKYES)
		{
			if(bIsExclusive && nCompStatus==COMPONENT_STATUS_SELECTED && this.nTotalSelComponentNum>0)
			{
				this.CTSU.ComponentCheckStatus(nIndex)=COMPONENT_STATUS_SELECTED;
				//Deselect all other non essentail components
				for(var i=0;i<this.nComponentNum;i++)
				{
					if(i!=nIndex && this.CTSU.ComponentCheckStatus(i)==COMPONENT_STATUS_SELECTED && this.CTSU.GetComponentCategory(i)!=COMPONENT_CATEGORY_COMPULSORY)
					{
						this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, i, COMPONENT_STATUS_DESELECTED)
						this.CTSU.ComponentCheckStatus(i)=COMPONENT_STATUS_DESELECTED;
					}
				}

			}
			else
			{
				for(var i=0;i<nNode;i++)
				{
					var nDpdIndex=this.CTSU.GetDpdComponentIndex(i);
					var nDpdCompStatus=this.CTSU.GetDpdComponentStatus(i);
					this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, nDpdIndex, nDpdCompStatus)
					this.CTSU.ComponentCheckStatus(nDpdIndex)=nDpdCompStatus
				}
				this.CTSU.ComponentCheckStatus(nIndex)=nCompStatus
				this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, nIndex, nCompStatus); //Confirm the changes
			}
		}else
		{	//Only reset the check/uncheck status
			if(nCompStatus==COMPONENT_STATUS_DESELECTED) this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, nIndex, COMPONENT_STATUS_SELECTED);
			else if(nCompStatus==COMPONENT_STATUS_SELECTED) this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, nIndex, COMPONENT_STATUS_DESELECTED);
			return nReturn;
		}
	}else
	{
		this.CTSU.ComponentCheckStatus(nIndex)=nCompStatus
		this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, nIndex, nCompStatus); //Confirm the changes
	}

	if(nCompStatus==COMPONENT_STATUS_HIDDEN)
	{ //Components are hidden
		this.nComponentShowNum-=(nNode+1);
	}
	this.GetTotalSelData();

	return nReturn;
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fGetComponentDesc()									|
|	Description	Get the full description of the component; OCX will not try to separate the short/long	|
|			description; All them should be controlled by web page					|
|	Parameter	nIndex - Index of the component								|
|	Return		String of the full description of the component						|
-----------------------------------------------------------------------------------------------------------------
*/
function fGetComponentDesc(nIndex)
{
	return this.CTSU.GetComponentDesc(nIndex);
}
/*
---------------------------------------------------------------------------------------------------------
|	Function	fSelectAllComponents								|
|	Description	Set component check status							|
|	Parameters	bSelected - true/false to select/deselect all components			|
---------------------------------------------------------------------------------------------------------
*/

function fSelectAllComponents(bSelected)
{
	var nStart=0, nEnd=this.nComponentNum-1, nStep=1, nCompStatus=COMPONENT_STATUS_SELECTED;
	
	if(!bSelected)
	{
		nStart=this.nComponentNum-1;
		nEnd=0;
		nStep=-1;
		nCompStatus=COMPONENT_STATUS_DESELECTED;
	}
	
	for(var i=nStart;(nStep*i)<=(nStep*nEnd);i=i+nStep)
	{
		if(this.CTSU.GetComponentCategory(i)!=COMPONENT_CATEGORY_COMPULSORY && this.CTSU.ComponentCheckStatus(i)>COMPONENT_STATUS_HIDDEN)
		{ //Non-comulsory and non-hidden comp 
			this.CTSUProc(MSG_CTSU_COMPONENTSTATUSCHANGED, i, nCompStatus);
			this.CTSU.ComponentCheckStatus(i)=(bSelected)?COMPONENT_STATUS_SELECTED:COMPONENT_STATUS_DESELECTED;
		}
	}
	this.GetTotalSelData();
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fStartDownloadInstallProcess()						|
|	Parameters	winObj - window object							|
|			bDownloaded - flag whether the files are downloaded; used for resume	|
|	Return		0 if succeeds or nonzero if fail to init				|
|------------------------------------------------------------------------------------------------
*/
function fStartDownloadInstallProcess(winObj, bDownloaded)
{
	var nRet=this.CTSU.InitDownload(bDownloaded);
	if(nRet>0) return nRet;

	this.winObject=winObj;
	this.bUserCancelled=false;
	this.bDownloaded=bDownloaded;
	this.bInstalled=false;
	this.nTotalDLCompSize=0;

	if(this.bnDownload)this.bnDownload.disabled=true;
	if(this.bnCancel)this.bnCancel.disabled=false;
	return 0;
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fIsProductChecked							|
|	Parameters	nCompIndex - component index						|
|	return		TRUE-at least one product is selected; FALSE-no product is selected	|
-------------------------------------------------------------------------------------------------
*/
function fIsProductChecked(nCompIndex)
{
	if(this.nListType!=COMPONENT_LIST_LISTBYPRODUCT) return true; 

	var nCount;
	var bReturn=false;
	for(nCount=0; nCount<this.aryMap.length; nCount++)
	{
		if(this.aryMap[nCount][1]==nCompIndex)
		{
			if(this.CTSUProc(MSG_CTSU_ISPRODUCTCHECKED, this.aryMap[nCount][0])==MSG_RETURN_OKYES)
				bReturn=true;
		}
	}
	return bReturn;
}
/*
-------------------------------------------------------------------------------------------------
|	Function	fEnableAllComponents							|
|	Parameters	bEnabled - Enable flag							|
|	return		None									|
-------------------------------------------------------------------------------------------------
*/
function fEnableAllComponents(bEnabled)
{
	var nCount;
	for(nCount=0; nCount<this.aryMap.length; nCount++)
	{
		if(this.CTSUProc(MSG_CTSU_ISPRODUCTCHECKED, this.aryMap[nCount][0])==MSG_RETURN_OKYES)
		{
			this.CTSUProc(MSG_CTSU_ENABLECOMPONENT, this.aryMap[nCount][0], this.aryMap[nCount][1], bEnabled);
		}
	}
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fDownloadComponent()									|
|	Description	Launch thread to download the component							|
|	Parameter	nIndex - Index number of the component							|
-----------------------------------------------------------------------------------------------------------------
*/
function fDownloadComponent(nIndex)
{
	if(nIndex>=0)
	{
		for(var i=nIndex;i<this.nComponentShowNum;i++)
		{
			if(this.bUserCancelled) break;
			if(this.IsProductChecked(i))
			{
				if(this.CTSU.DownloadComponent(i))
				{
					this.CheckDownloadThreadStatus(i);
					return;
				}
			}
		}
	}
	
	//Start to install if any component is downloaded
	if(this.bDownloaded && this.bUserCancelled==false)
	{
		if(this.CTSUProc(MSG_CTSU_DLCOMPLETE, true, this.CTSU.AskMeB4Install)==MSG_RETURN_OKYES)
		{
			//Start install thread
			this.InstallComponent(0);
			return;
		}
	}else
	{
		this.CTSUProc(MSG_CTSU_DLCOMPLETE, false);
	}


	//Stop installation
	this.CTSU.ShutdownInstall()
	if(this.bnCancel) this.bnCancel.disabled=true
	if(this.bnDownload) this.bnDownload.disabled=false
	this.CTSUProc(MSG_CTSU_INSCOMPLETE, false);
}

function fGetAllSelCompName(aryCompName)
{
	for(var i=0;i<this.nComponentNum;i++)
	{
		if(this.IsProductChecked(i))
		{
			if(this.CTSU.ComponentCheckStatus(i)==COMPONENT_STATUS_SELECTED)
			{
				aryCompName[aryCompName.length]=this.CTSU.GetComponentName(i);
			}
		}
	}
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fCheckDownloadThreadStatus								|
|	Description	Monitor function to Check the status of download thread					|
|	Parameters	nIndex - index number of the component							|
-----------------------------------------------------------------------------------------------------------------
*/
function fCheckDownloadThreadStatus(nIndex)
{
	var nCode=this.CTSU.GetLastThreadExitCode()
	var nCompSize=this.CTSU.GetComponentSize(nIndex)
	var szCompName=this.CTSU.GetComponentName(nIndex);

	if(nCode==-1) //Still active
	{	//ThreadParam1 - status of download;
		//ThreadParam2 - nQueueNo if status=2 or speed if status=3|4
		//ThreadParam3 - component downloaded size
		var nStatus=this.CTSU.ThreadParam1
		var nQueueNo=null, nDLSpeed=null, nDLSize=null, nCompSize=null

		if(nStatus==0) //Idle or init
		{
			this.CTSUProc(MSG_CTSU_DLINIT, nIndex, szCompName);
		}
		else if(nStatus==1) //Contact server
		{
			this.CTSUProc(MSG_CTSU_DLCONTACTSERVER, nIndex, szCompName);
		}
		else if(nStatus==2) //In queue
		{
			this.CTSUProc(MSG_CTSU_DLWAITINQUEUE, nIndex, szCompName, this.CTSU.ThreadParam2);
		}
		else if(nStatus==3 || nStatus==4) //Ready for download or downloading
		{
			this.CTSUProc(MSG_CTSU_DLPROGRESS, nIndex, szCompName, this.nTotalDLCompSize+this.CTSU.ThreadParam3, this.nTotalDLSize, this.CTSU.ThreadParam2);
		}

		setTimeout(this.obj+'.CheckDownloadThreadStatus('+nIndex+')', 1000)
	}
	else
	{
		if(nCode==0)
		{
			this.nTotalDLCompSize+=nCompSize;
			this.bDownloaded=true;
			this.CTSUProc(MSG_CTSU_DLCOMPONENTDOWNLOADED, nIndex, szCompName, this.nTotalDLCompSize, this.nTotalDLSize);
			this.DownloadComponent(nIndex+1); 
		}else
		{

			var nRet=this.CTSUProc(MSG_CTSU_DLCOMPONENTFAILED, nIndex, szCompName, nCode);
			if(nRet==MSG_RETURN_CANCEL)
			{	//User cancel
				this.CTSU.ShutdownInstall()
				if(this.bnCancel) this.bnCancel.disabled=true
				if(this.bnDownload) this.bnDownload.disabled=false
				this.CTSUProc(MSG_CTSU_INSCOMPLETE, false);
			}
			else if(nRet==MSG_RETURN_NO)
			{	//Redownload the component
				this.DownloadComponent(nIndex); //redownload the component
			}else
			{	//Skip the component
//				if(nCode!=0) this.nTotalDLSize-=nCompSize;
				this.DownloadComponent(nIndex+1) //Download the next component
			}
		}
	}
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fInstallComponent()									|
|	Description	Launch thread to install the component							|
|	Parameter	nIndex - Index number of the component							|
-----------------------------------------------------------------------------------------------------------------
*/
function fInstallComponent(nIndex)
{
	if(this.bnCancel) this.bnCancel.disabled=true
	if(this.bnDownload) this.bnDownload.disabled=true

	if(nIndex>=0)
	{
		for(var i=nIndex;i<this.nComponentShowNum;i++)
		{
			if(this.bUserCancelled) break;
			if(this.IsProductChecked(i))
			{
				if(this.CTSU.InstallComponent(i))
				{
					this.CheckInstallThreadStatus(i)
					return
				}
			}
		}
	}

	this.CTSU.ShutdownInstall()

	if(this.bExclusiveLaunched)
	{
		this.CTSUProc(MSG_CTSU_EXCLUSIVEPACKLAUNCHED);
		this.bGoToNext=true; //Disable warning message
		if(this.fmComponent)
		{
			this.fmComponent.submit()
		}
		return;
	}

	if(this.bnCancel) this.bnCancel.disabled=true;
	if(this.bnDownload) this.bnDownload.disabled=false

	if(this.bLocal)
	{
		this.CTSUProc(MSG_CTSU_INSCOMPLETE, true, this.CTSU.GetRebootFlag());
		document.location.href="Finish.htm"
	}
	else
	{
		if(this.bInstalled)
		{
			this.CTSUProc(MSG_CTSU_INSCOMPLETE, true, this.CTSU.GetRebootFlag());
			this.bGoToNext=true; //Disable warning message
			if(this.fmComponent)
			{
				this.fmComponent.submit()
				return;
			}
		}else
		{
			this.CTSUProc(MSG_CTSU_INSCOMPLETE, false);
		}
	}
}
/*
-----------------------------------------------------------------------------------------------------------------
|	Function	fCheckInstallThreadStatus()								|
|	Description	Monitor function to check the status of the install thread				|
|	Parameters	nIndex - index number of the component							|
-----------------------------------------------------------------------------------------------------------------
*/
function fCheckInstallThreadStatus(nIndex)
{
	var nCode=this.CTSU.GetLastThreadExitCode();
	var szCompName=this.CTSU.GetComponentName(nIndex);

	if(nCode==-1) //Still active
	{
		this.CTSUProc(MSG_CTSU_INSPROGRESS, nIndex,  szCompName, 0);
		setTimeout(this.obj+'.CheckInstallThreadStatus('+nIndex+')', 1000)
	}
	else
	{
		if(nCode==RETURN_ERROR_NEEDPOSTCHECK)
		{	//Start to post check installation
			this.CTSU.PostCheckInstall(nIndex);
			setTimeout(this.obj+'.CheckInstallThreadStatus('+nIndex+')', 1000)
		}
		else if(nCode==0)
		{
			this.bInstalled=true;
			this.CTSUProc(MSG_CTSU_INSCOMPONENTINSTALLED, nIndex, szCompName);
			this.InstallComponent(nIndex+1);
		}
		else if(nCode==RETURN_ERROR_EXCLUSIVEPACK)
		{	//Exclusive package
			this.bExclusiveLaunched=true;
			this.InstallComponent(-1);
		}
		else if(nCode==RETURN_ERROR_MUSTREBOOT)
		{	//Must reboot
			var nRet=this.CTSUProc(MSG_CTSU_INSMUSTREBOOT, szCompName);
			if(nRet==MSG_RETURN_OKYES) //Reboot
			{
				this.CTSU.ShutdownInstall();
				if(!this.CTSU.ForceReboot(nIndex, this.bLocal))
				{
					if(this.bLocal)
					{
						document.location.href="Finish.htm"
					}else
					{
						if(this.fmComponent) this.fmComponent.submit();
					}
				}
			}else
			{
				this.InstallComponent(-1);
			}
		}
		else
		{
			var nRet=this.CTSUProc(MSG_CTSU_INSCOMPONENTFAILED, nIndex, szCompName, nCode);
			if(nRet==MSG_RETURN_OKYES)
				this.InstallComponent(nIndex+1) //Install the next component
			else if(nRet==MSG_RETURN_NO)
				this.InstallComponent(nIndex); //reinstall the component
			else if(nRet==MSG_RETURN_CANCEL) //abort or user cancelled
			{
				this.InstallComponent(-1); //Abort the install process
			}
		}
	}
}
/*
---------------------------------------------------------------------------------
|	Function	fCancelDownloadInstallThread()				|
|	Description	Cancel the download and install thread			|
|	Parameters	szMsg - message prompted to the user			|
|	Return		TRUE if thread is cancelled; otherwise, FALSE		|
---------------------------------------------------------------------------------
*/
function fCancelDownloadInstallThread(szMsg)
{
	if(this.CancelThread(szMsg))
	{	//The thread is cancelled by user
		this.CTSU.ShutdownInstall() //Close download&install process
		if(this.bnCancel) this.bnCancel.disabled=true
		if(this.bnDownload) this.bnDownload.disabled=false
		return true;
	}else
	{	//The thread is continued
		return false;
	}
}
/*
---------------------------------------------------------------------------------
|	Function	fIsDownloadInstalling()					|
|	Description	Check whether the download/install is processing	|
|	Return		TRUe if processing. FALSE if not.			|
---------------------------------------------------------------------------------
*/
function fIsDownloadInstalling()
{
	return this.CTSU.IsDownloadInstalling();
}
