/**
 *	Qihoo Ajax Class [3.0], Copyright (C) Qihoo 2007
 *
 *	Update History:
 *	Dec 18,2005	[V1.0] Create By LiuQixing(liuqixing@gmail.com)
 *	Dec 27,2006	[V2.0] By LiuQiXing
 *	Mar 22,2007	[V3.0] By LiuQiXing
 *
 *	回调函数写法
 *	HttpGetResponse / HttpSendPost:
 *	------------------------------------------------------------
 *		object =
 *		{
 *			advmode : false,			//	普通模式
 *			timeout : 3*60*1000,			//	超时，单位毫秒
 *			tmoproc : function( sText, vArglist ),	//	超时后的回调函数
 *			failure : function( sText, vArglist ),
 *			success : function( sText, vArglist )
 *		}
 *		OR
 *		{
 *			advmode : true,				//	高级模式，会直接返回 xml 对象给调用者
 *			timeout : 3*60*1000,			//	超时，单位毫秒
 *			tmoproc : function( oResponse ),	//	超时后的回调函数
 *			failure : function( oResponse ),
 *			success : function( oResponse )
 *		}
 *	HttpPostForm:						//	因为 PostForm 仅仅是将一个 Form Submit 所以没有成功失败和超时
 *	------------------------------------------------------------
 *		object =
 *		{
 *			advmode : false,			//	普通模式
 *			postfrm : function( sText, vArglist )
 *		}
 *		OR
 *		object =
 *		{
 *			advmode : true,				//	高级模式，会直接返回 xml 对象给调用者
 *			postfrm : function( oResponse )
 *		}
 */

function CQhAjax()
{
	//
	//	@ Private
	//	ActiveX pid
	//
	var m_ArrMsXmlProgid	= new Array( 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP' );

	//
	//	@ Private
	//	unique frame id
	//
	var m_sFrameId		= "id_frame_ajax_" + parseInt( Math.floor( ( Math.random() )*10000 ) );
	var m_oFrameAjax	= null;
	var m_oFormNode		= null;

	//
	//	@ Private
	//
	var m_nTimeOutId	= 0;		//	timer timeout id
	var m_nIntervalId	= 0;		//	timer interval id
	var m_nIntervalTime	= 50;		//	循环检查时间

	//
	//	HTTP 对象
	//
	var m_oHttp		= null;

	//
	//	回调对象
	//
	var m_fpCallbackFunc	= null;

	/**
	 *	用户数据
	 */
	var m_vArglist		= null;


	//
	//	@ Public
	//
	this.MyUrlEncode = function( Va )
	{
		return Va.replace(/:/g, '%3A').replace(/\//g, '%2F').replace(/\?/g, '%3F').replace(/&/g, '%26').replace(/=/g, '%3D');
	};


	//
	//	@ Public
	//	Url encode ( UTF-8 format )
	//
	this.UrlEncode = function( Va )
	{
		if ( encodeURIComponent )
			return encodeURIComponent( Va );
		if ( escape )
			return escape( Va );
	};

	//
	//	@ Public
	//
	this.HtmlEncode = function( Va )
	{
		return Va.replace(/&/g, '&amp').replace(/'/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
	};


	//
	//	@ Public
	//	GET 方式的请求
	//
	this.HttpGetResponse = function( strUrl, fpCallbackFunc, vArglist, sPostData )
	{
		//
		//	strUrl		- [in]
		//	fpCallbackFunc	- [in]     callback function list
		//	vArglist	- [in]
		//	sPostData	- [in/opt] POST DATA
		//

		var oHttp		= null;
		var bPost		= false;

		if ( strUrl.length > 0 )
		{
			strUrl += ( -1 != strUrl.indexOf("?") ? "&" : "?" ) + "rand=" + Math.floor((Math.random())*10000);

			if ( m_oHttp && m_oHttp && 0 != m_oHttp.readyState )
			{
				m_oHttp.abort();
			}

			//	..
			oHttp = GetHttpObject();
			if ( oHttp )
			{
				m_oHttp			= oHttp;
				m_fpCallbackFunc	= fpCallbackFunc;
				m_vArglist		= vArglist;
				bPost			= ( sPostData && sPostData.length );

				m_oHttp.open( bPost ? "POST" : "GET", strUrl, true );
				if ( bPost )
				{
					SetHeader( "Content-Type", "application/x-www-form-urlencoded" );
					SetHeader( "content-length", sPostData.length );
				}
				HandleReadyState();
				m_oHttp.send( bPost ? sPostData : null );
			}
		}
	};

	//
	//	@ Public
	//	POST 方式的请求
	//
	this.HttpSendPost = function( strUrl, fpCallbackFunc, vArglist, sPostData )
	{
		//
		//	strUrl		- [in]
		//	fpCallbackFunc	- [in]     callback function list
		//	vArglist	- [in]
		//	sPostData	- [in/opt] POST DATA
		//

		return this.HttpGetResponse( strUrl, fpCallbackFunc, vArglist, sPostData );
	};

	//
	//	POST 数据
	//	数据被 UTF8 编码
	//
	this.HttpPostForm = function( sFormId, strTagUrl, fpCallbackFunc, vArglist )
	{
		//
		//	sFormId		- [in] FORM ID
		//	strTagUrl	- [in] POST 目标地址
		//	fpCallbackFunc	- [in] address of callback function
		//	vArglist	- [in] param
		//

		var oForm		= GetFormObjectById( sFormId );
		if ( ! oForm )
			return false;

		m_oFormNode		= oForm;
		m_oFrameAjax		= CreateFrame( null );
		m_fpCallbackFunc	= fpCallbackFunc;
		m_vArglist		= vArglist;

		DoPostForm( m_oFormNode, m_oFrameAjax, strTagUrl );
		ReleaseObject();

		return true;
	};

	//
	//	@ Public
	//	This method assembles the form label and value pairs and constructs an encoded string.
	//	HTTP header Content-Type must be set application/x-www-form-urlencoded.
	//
	this.GetFormData = function( sFormId )
	{
		//
		//	sFormId		- [in] FORM ID
		//	RETURN		- FormData
		//

		var oForm		= GetFormObjectById( sFormId );

		if ( ! oForm )
		{
			return null;
		}

		var sFormData	= "";
		var oElement, sName, sValue, bEnable;
		var hasSubmit	= false;
		var i		= 0;

		//
		//	Iterate over the form elements collection to construct the label-value pairs.
		//
		for ( i = 0; i < oForm.elements.length; i ++ )
		{
			oElement	= oForm.elements[ i ];
			bEnable		= oForm.elements[ i ].disabled ? false : true;
			sName		= oForm.elements[ i ].name;
			sValue		= oForm.elements[ i ].value;

			//	Do not submit fields that are disabled or
			//	do not have a name attribute value.
			if ( ! bEnable || ! sName )
			{
				continue;
			}

			switch ( oElement.type )
			{
			case "select-one" :
			case "select-multiple" :
				{
					for ( var j = 0; j < oElement.options.length; j++ )
					{
						if ( oElement.options[j].selected )
						{
							if ( window.ActiveXObject )
							{
								sFormData += encodeURIComponent(sName) + '=' + encodeURIComponent(oElement.options[j].attributes['value'].specified?oElement.options[j].value:oElement.options[j].text) + '&';
							}
							else
							{
								sFormData += encodeURIComponent(sName) + '=' + encodeURIComponent(oElement.options[j].hasAttribute('value')?oElement.options[j].value:oElement.options[j].text) + '&';
							}
						}
					}
				}
				break;
			case "radio" :
			case "checkbox" :
				{
					if ( oElement.checked )
					{
						sFormData += encodeURIComponent(sName) + '=' + encodeURIComponent(sValue) + '&';
					}
				}
				break;
			case "file":		//	stub case as XMLHttpRequest will only send the file path as a string.
			case undefined:		//	stub case for fieldset element which returns undefined.
			case "undefined":
			case "reset":		//	stub case for input type reset button.
			case "button":		//	stub case for input type button elements.
				break;
			case "submit":
				{
					if ( hasSubmit == false )
					{
						sFormData += encodeURIComponent(sName) + '=' + encodeURIComponent(sValue) + '&';
						hasSubmit = true;
					}
				}
				break;
			default:
				{
					sFormData += encodeURIComponent(sName) + '=' + encodeURIComponent(sValue) + '&';
				}
				break;
			}
		}

		return sFormData.substr( 0, sFormData.length - 1 );
	};


	////////////////////////////////////////////////////////////
	//	@ Private
	////////////////////////////////////////////////////////////

	//
	//	创建 http 对象
	//
	function CreateHttpObject()
	{
		var obj		= null;

		try
		{
			//	非 IE 浏览器
			obj	= new XMLHttpRequest();
		}
		catch( e )
		{
			for( var i in m_ArrMsXmlProgid )
			{
				try
				{
					//	For IE
					obj = new ActiveXObject( m_ArrMsXmlProgid[ i ] );
					break;
				}
				catch(e)
				{}
			}
		}
		finally
		{
			return obj;
		}
	}

	//
	//	释放 Http 对象
	//
	function ReleaseObject()
	{
		if ( m_oHttp )
		{
			m_oHttp = null;
		}
	}

	//
	//	获取 HTTP 对象
	//
	function GetHttpObject()
	{
		return CreateHttpObject();
	}

	//
	//	get form Object by id
	//
	function GetFormObjectById( sFormId )
	{
		//
		//	sFormId		- [in] FORM ID
		//
		var oForm	= null;

		if ( typeof sFormId == 'string' )
		{
			oForm	= ( document.getElementById( sFormId ) || document.forms[ sFormId ] );
		}
		else if ( typeof sFormId == 'object' )
		{
			oForm	= sFormId;
		}

		return oForm;
	}

	//
	//	创建 frame
	//
	function CreateFrame( sSecureUri )
	{
		//
		//	sSecureUri	- [in] URI
		//	RETURN		- [in] frame object
		//

		var frameId	= m_sFrameId;
		var oframe	= null;

		if ( window.ActiveXObject )
		{
			//	for IE
			oframe = document.createElement( '<IFRAME id="' + frameId + '" name="' + frameId + '">' );

			//	IE will throw a security exception in an SSL environment if the
			//	iframe source isn't set.
			if ( typeof sSecureUri == 'boolean' )
			{
				oframe.src = "JavaScript:false";
			}
			else
			{
				oframe.src = sSecureUri;
			}
		}
		else
		{
			oframe		= document.createElement( 'IFRAME' );
			oframe.id	= frameId;
			oframe.name	= frameId;
		}

		oframe.style.position	= 'absolute';
		oframe.style.top	= '-1000px';
		oframe.style.left	= '-1000px';

		document.body.appendChild( oframe );

		return oframe;
	}

	//
	//	Accessor that sets the HTTP headers for each transaction.
	//
	function SetHeader( sLabel, sValue )
	{
		//
		//	sLabel	- [in] HTTP header label
		//	sValue	- [in] HTTP header value
		//

		if ( ! m_oHttp )
			return;

		if ( sLabel && sLabel.length && sValue )
		{
			m_oHttp.setRequestHeader( sLabel, sValue );
		}
	}

	//
	//	@ Private
	//	Uploads HTML form, including files/attachments,  targeting the iframe created in createFrame.
	//
	function DoPostForm( oForm, oFrameAjax, sUri )
	{
		if ( ! oForm )
			return false;
		if ( ! oFrameAjax )
			return false;

		//	Initialize the HTML form properties in case they are
		//	not defined in the HTML form.
		oForm.action	= sUri;
		oForm.enctype	= 'multipart/form-data';
		oForm.method	= 'POST';
		oForm.target	= oFrameAjax.id;
		oForm.submit();

		//	Create the upload callback handler that fires when the iframe
		//	receives the load event.  Subsequently, the event handler is detached
		//	and the iframe removed from the document.

		var CallbackDoPostForm = function()
		{
			var oResponse	= {};

			oResponse.responseText	= oFrameAjax.contentWindow.document.body ? oFrameAjax.contentWindow.document.body.innerHTML : null;
			oResponse.responseXML	= oFrameAjax.contentWindow.document.XMLDocument ? oFrameAjax.contentWindow.document.XMLDocument : oFrameAjax.contentWindow.document;
			oResponse.argument	= m_vArglist;

			if ( m_fpCallbackFunc.postfrm )
			{
				if ( m_fpCallbackFunc.advmode )
				{
					//	用户指定的高级模式
					m_fpCallbackFunc.postfrm( oResponse );
				}
				else
				{
					//	普通模式
					m_fpCallbackFunc.postfrm( oResponse.responseText, m_vArglist );
				}
			}

			//	Destory event
			if ( window.ActiveXObject )
			{
				oFrameAjax.detachEvent( "onload", CallbackDoPostForm );
			}
			else
			{
				oFrameAjax.removeEventListener( "load", CallbackDoPostForm, false );
			}

			window.setTimeout
			(
				function(){ document.body.removeChild( oFrameAjax ); },
				100
			);
		};


		//	Bind the onload handler to the iframe to detect the file upload response.
		if ( window.ActiveXObject )
		{
			oFrameAjax.attachEvent( 'onload', CallbackDoPostForm );
		}
		else
		{
			oFrameAjax.addEventListener( 'load', CallbackDoPostForm, false );
		}
	}

	//
	//	@ Private
	//
	function HandleReadyState()
	{
		//
		//	超时处理
		//
		if ( m_fpCallbackFunc && m_fpCallbackFunc.timeout )
		{
			m_nTimeOutId = window.setTimeout
			(
				function()
				{
					ProcessTimeout();
				},
				m_fpCallbackFunc.timeout
			);
		}

		//
		//	定时探测
		//
		m_nIntervalId = window.setInterval
		(
			function()
			{
				if ( m_oHttp && 4 == m_oHttp.readyState )
				{
					//	200 - 300，或者 404 都会到这里
					ClearAllTimer();
					HandleTransactionResponse();
				}
			},
			m_nIntervalTime
		);
	}

	//
	//	@ Private
	//
	function ProcessTimeout()
	{
		if ( IsCallInProgress() )
		{
			m_oHttp.abort();

			//	如果发现 timeout 定时器不为 0，则认为是超时了
			ClearAllTimer();
			HandleTransactionResponse( true );
			return true;
		}
		return false;
	}

	//
	//	@ Private
	//
	function ClearAllTimer()
	{
		if ( m_nIntervalId )
		{
			window.clearInterval( m_nIntervalId );
		}
		if ( m_nTimeOutId )
		{
			window.clearTimeout( m_nTimeOutId );
		}

		m_nIntervalId	= 0;
		m_nTimeOutId	= 0;
	}

	//
	//	@ Private
	//
	function IsCallInProgress()
	{
		if ( ! m_oHttp )
			return false;

		return ( 4 != m_oHttp.readyState && 0 != m_oHttp.readyState );
	}

	//
	//	@ Private
	//
	function HandleTransactionResponse( bIsTimeout )
	{
		if ( ! m_fpCallbackFunc )
		{
			ReleaseObject();
			return;
		}

		var nStatusCode		= 0;
		var oResponse		= null;
		var pfnProc		= null;

		try
		{
			if ( undefined !== m_oHttp.status && 0 != m_oHttp.status )
			{
				nStatusCode	= m_oHttp.status;
			}
			else
			{
				nStatusCode	= 13030;
			}
		}
		catch(err)
		{
			//	13030 is the custom code to indicate the condition -- in Mozilla/FF --
			//	when the o object's status and statusText properties are
			//	unavailable, and a query attempt throws an exception.
			nStatusCode = 13030;
		}

		if ( nStatusCode >= 200 && nStatusCode < 300 )
		{
			//	成功
			try
			{
				oResponse = CreateResponseObject();
				if ( m_fpCallbackFunc.success )
				{
					if ( m_fpCallbackFunc.advmode )
					{
						//	用户指定的高级模式
						m_fpCallbackFunc.success( oResponse );
					}
					else
					{
						//	普通模式
						m_fpCallbackFunc.success( oResponse.responseText, m_vArglist );
					}
				}
			}
			catch(err)
			{}
		}
		else
		{
			try
			{
				//
				//	The following case labels are wininet.dll error codes that may be encountered.
				//
				switch( nStatusCode )
				{
				case 12002:	//	Server timeout
				case 12029:	//	12029 to 12031 correspond to dropped connections.
				case 12030:
				case 12031:
				case 12152:	//	Connection closed by server.
				case 13030:	//	See above comments for variable status.
					{
						oResponse = CreateExceptionObject( bIsTimeout ? bIsTimeout : false );
						if ( bIsTimeout && m_fpCallbackFunc.tmoproc )
						{
							pfnProc = m_fpCallbackFunc.tmoproc;
						}
						else
						{
							pfnProc = m_fpCallbackFunc.failure;
						}
						if ( pfnProc )
						{
							if ( m_fpCallbackFunc.advmode )
							{
								//	用户指定的高级模式
								pfnProc( oResponse );
							}
							else
							{
								//	普通模式
								pfnProc( oResponse.responseText, m_vArglist );
							}
						}
					}
					break;
				default:
					{
						oResponse = CreateResponseObject();
						if ( m_fpCallbackFunc.failure )
						{
							if ( m_fpCallbackFunc.advmode )
							{
								//	用户指定的高级模式
								m_fpCallbackFunc.failure( oResponse );
							}
							else
							{
								//	普通模式
								m_fpCallbackFunc.failure( oResponse.responseText, m_vArglist );
							}
						}
					}
					break;
				}
			}
			catch(err)
			{}
		}

		ReleaseObject();
		oResponse = null;
	}

	//
	//	@ Private
	//
	function CreateResponseObject()
	{
		var obj		= {};
		var ArrHeader	= {};

		try
		{
			var headerStr	= m_oHttp.getAllResponseHeaders();
			var header	= headerStr.split('\n');
			var delimitPos	= 0;
			for ( var i = 0; i < header.length; i++ )
			{
				delimitPos = header[i].indexOf(':');
				if ( -1 != delimitPos )
				{
					ArrHeader[ header[i].substring(0,delimitPos) ] = header[i].substring( delimitPos + 2 );
				}
			}
		}
		catch(e)
		{}

		obj.fid				= m_oHttp.fid;
		obj.status			= m_oHttp.status;
		obj.statusText			= m_oHttp.statusText;
		obj.getResponseHeader		= ArrHeader;
		obj.getAllResponseHeaders	= headerStr;
		obj.responseText		= m_oHttp.responseText;
		obj.responseXML			= m_oHttp.responseXML;
		obj.argument			= m_vArglist;

		return obj;
	}

	//
	//	@ Private
	//
	function CreateExceptionObject( bIsAbort )
	{
		var COMM_CODE	= 0;
		var COMM_ERROR	= 'communication failure';
		var ABORT_CODE	= -1;
		var ABORT_ERROR	= 'transaction timeout or aborted';
		var obj		= {};

		try
		{
			obj.fid		= m_oHttp.fid;
			obj.argument	= m_vArglist;
			if ( bIsAbort )
			{
				obj.status		= ABORT_CODE;
				obj.statusText		= ABORT_ERROR;
				obj.responseText	= ABORT_ERROR;
			}
			else
			{
				obj.status		= COMM_CODE;
				obj.statusText		= COMM_ERROR;
				obj.responseText	= COMM_ERROR;
			}
		}
		catch(e)
		{}

		return obj;
	}
}



function getEvalValue( str )
{
	var vRet = null;
	try
	{
		eval( "vRet = " + str );
	}
	catch(err)
	{}
	return vRet;
}