﻿CONST_GET_TIMEOUT = 1000 * 25;
CONST_GET_RETRY = 3;
CONST_REPOST_TIMEOUT = 1000 * 120;

var browser = detectBrowser();  // 检测浏览器类型

/*pub function*/
/* 从XML文本中解析Response列表 */
function XMLParseRsp(dom)
{
	try
	{
		return dom.getElementsByTagName("Rsp");
	}
	catch(e)
	{
		return null;
	}
}

//获取tagName 的节点数目
function XMLGetNodesLength(xml)
{
  try
  {
		if(null != xml)
			return xml.length;
		else
			return 0;
	}
	catch(e)
	{
		return 0;
	}
}

//获取tagName 的指定节点
function XMLGetNode(xml,i)
{
	if(null != xml)
		return xml.item(i);
	else
		return null;
}

function XMLGetNamedAttr(node, attrName)
{
	try
	{
		if (null == node)
		{
			return "";
		}
		else
		{
			if(browser == "firefox")
			{
				return node.attributes.getNamedItem(attrName).textContent;
			}
			else
			{
				return node.attributes.getNamedItem(attrName).nodeValue;
			}
		}
	}
	catch(e)
	{
		return "";
	}
}

/* Ajax*/
function XMLHttp(client, tag)
{
	var owner = this;
	var mUrl = "";
	var mClient = client;
	var mTag = tag;
	var mPostData = "";
	var mRepostTime = 0;
	var mSubmit = false;
	var mAsyn = true;
	var mHttp;

	this.CreateAjax = function() 
	{
		if (window.ActiveXObject)
		{
			try
			{
				mHttp = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (e)
			{
				try
				{
					mHttp = new ActiveXObject("Microsoft.XMLHTTP");
				}
				catch (e)
				{
					alert("Create Ajax object defeat!");
				}
			}
		}
  	else if (window.XMLHttpRequest)
	  {
  		mHttp = new XMLHttpRequest();
	  	if (mHttp.overrideMimeType)
		  {
  			mHttp.overrideMimeType("text/xml");
	  	}
	  } 
		mHttp.onreadystatechange = this.XMLHandle;
	}
       
	this.SendReq = function()
	{
		if (!mSubmit)
		{
			mHttp.open("POST", mUrl, mAsyn);
			mHttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			mHttp.send(mPostData);
			mSubmit = true;
		}
	}
	this.SetURL = function(value)
	{
		if (mUrl == "")
		{
			mUrl = value;
		}
	}
	this.SetPostData = function(value)
	{
		mPostData = value;
	}
	this.AddPostData = function(name, value)
	{
		mPostData += name + "=" + escape(value) + "&";
	}
	this.GetPostData = function(value)
	{
		return mPostData;
	}
	this.SetRepostTime = function(value)
	{
		mRepostTime = value;
	}
	this.GetRepostTime = function()
	{
		return mRepostTime;
	}
	this.SetAsyn = function(value)
	{
		mAsyn = value;
	}	
	this.GetTag = function()
	{
		return mTag;
	}
	this.GetXmlHttp = function()
	{
		return mHttp;
	}
	this.XMLHandle = function()
	{
		if (mHttp.readyState == 4)
		{
			if (mHttp.status == 200)
			{
				mClient.ResponseHandle(owner);
				mHttp = null;
				owner = null;
				mClient.Repost();
			}
			else
			{
				var cmdArray = new Array('SAY');
				var cmd = getStringField(getStringField(mPostData, '&', 1), '=', 2);
				if (cmdArray.search(cmd) >= 0)
				{
					if (owner.GetRepostTime() == 0)
					{
						mClient.RepostQueueFoot(owner);
					}
					else
					{
						mClient.RepostQueueHead(owner);
					}
				}
				mHttp = null;
				owner = null;
			}
		}
	}
	this.CreateAjax();
}

function XMLChannel(srvAddr, params, debug)
{
	var owner = this;
	var mConnected = false;
	var mGetRetry = 0;
	var mSrvAddr = srvAddr;
	var mParams = params;
	var mDebug = debug;
	var mChannelTag = "";
	var mChannelId = 0;
	var mSiteTag = "";//sTag;
	var mSiteId = 0;
	var mVisiTag = "";
	var mVisiId = 0;
	var mVisiName = "";
	var mLastMsg = -1;

	var mShutdown = false;
	var mAddNo = 1;
	var mLastGetTime = 0;
	var mLastGetTag = 0;
	var mCounter = 0;
	var mRepostDataList = new Array();
	var mRepostTimeList = new Array();

	XMLChannel.prototype.lastInstance = this;
	XMLChannel.prototype.ClientTimeout = function()
	{
		XMLChannel.prototype.lastInstance.Timeout();
	}

/*public event*/
	this.OnOpenChannel = function(rCode,sTag,vTag,chTag,vName,sId,vId,chId,postChat,sendFile,postChatUrl,bVideo,voiceUrl,bAudio,bRobot,chatList,wid,v2cName,visibleUserInfo,visibleVisitorInfo,enabledMember,enabledWarnings,warningsMsg,mId,coId,dId,oId) {}//rCode:0--success, -1--site not found, -2--visitor chatting, -3--operator not found
	this.OnEndChannel = function() {}
	this.OnRecvMsg = function(name, msg, type) {}
	this.OnRecvTyping = function(name, typing) {}
	this.OnRecvFile = function(name, filename, filesize, url, type) {}
	this.OnRecvImageUrl = function(name, url) {}
	this.OnRecvWeb = function(name, url) {}
	this.OnRecvAudio = function(isOpen) {}
	this.OnRecvVideo = function(isOpen) {}
	this.OnChannelMsg = function(type, msg, pId) {}//type:1--join, 2--leave, 3--welcome
//	this.OnSystemMsg = function(id) {}
	this.OnSendMsg = function(rCode) {}
	this.OnSendTyping = function(rCode) {}
	this.OnSendPreview = function(rCode) {}
	this.OnSendAudio = function(rCode) {}
	this.OnSendVideo = function(rCode) {}
	this.OnSendFile = function(rCode) {}
	this.OnRedirect = function(url) {}
	this.OnPopupWindow = function() {}
	this.OnErr = function(errCode, message) {}
	this.OnDebug = function(message) {}

/*function*/
	this.Timeout = function()
	{
		if ((mConnected) && (mLastGetTime > 0))
		{
			var nowTime = new Date().getTime();

			if ((nowTime - mLastGetTime) > CONST_GET_TIMEOUT)
			{
				if (mGetRetry >= CONST_GET_RETRY)
				{
					if (mDebug)
					{
						this.OnDebug("CONST_GET_RETRY:" + mGetRetry);
					}
					mConnected = false;
					this.OnEndChannel();
					return;
				}					
				this.GetCmd(true);
			}
		}
	}

	this.RepostQueueHead = function(req)
	{
		var repostData = req.GetPostData();
		var repostTime = req.GetRepostTime();
		if (mRepostDataList.search(repostData) >= 0)
		{
			return;
		}
		mRepostDataList.unshift(repostData);
		mRepostTimeList.unshift(repostTime);
	}
	this.RepostQueueFoot = function(req)
	{
		var repostData = req.GetPostData();
		var repostTime = req.GetRepostTime();
		if (mRepostDataList.search(repostData) >= 0)
		{
			return;
		}
		mRepostDataList.push(repostData);
		mRepostTimeList.push(repostTime);
	}
	this.Repost = function()
	{
		if (mRepostDataList.length == 0)
		{
			return;
		}
		var repostData = mRepostDataList.shift();
		var repostTime = mRepostTimeList.shift();
		if (repostTime == 0)
		{
			repostTime = new Date().getTime();
		}
		else
		{
			if (new Date().getTime() - CONST_REPOST_TIMEOUT > repostTime)
			{
				this.Repost();
				return;
			}
		}

		var req = this.CreateRequest();

		if (req == null)
		{
			return;
		}

		req.SetURL(mSrvAddr);
		req.SetRepostTime(repostTime);
		req.SetPostData(repostData);
		req.SendReq();

		return req.GetTag();
	}
	
	this.CreateRequest = function() {
		if (mShutdown) {
			return null;
		} else {
			var req = new XMLHttp(owner, ++mCounter);
			return req;
		} 
	}
	this.ResponseHandle = function(request)
	{
		var ajax = request.GetXmlHttp();
		if (mDebug)
		{
//			this.OnDebug(ajax.responseText);
		}
		var rspList = XMLParseRsp(ajax.responseXML);
		var rspLength = XMLGetNodesLength(rspList);
		if (rspLength != 0)
		{
			for(var i=0; i<rspLength; i++)
			{
				var rsp = XMLGetNode(rspList,i);
				this.RspProc(request.GetTag(), rsp);
			}    
		}
		else
		{
			mAddNo++;
			this.OnErr(0, "Parse rsp error!");
		}
	}
	this.RspProc = function(tag, rsp)
	{
		var cmd;
		var errCode = 0;
		var node;
		var nodeList;
		var data;
		var msg;
        
		if (rsp == null)
		{
			return;
		}
        
		try
		{
			cmd = XMLGetNamedAttr(rsp, "cmd");
			switch (cmd)
			{
				case "GET":
					if ((mConnected) && (tag == mLastGetTag))
					{
						mGetRetry = 0;
//						this.OnDebug("GET " +tag + "/" + mLastGetTag + "-" + XMLGetNamedAttr(rsp, "tag"));
						this.GetCmd();
 					}
					break;
				case "LMI":
					mLastMsg = XMLGetNamedAttr(rsp, "lastMsgId");
					break;
				case "TYP":
					this.OnRecvTyping(unescape(XMLGetNamedAttr(rsp, "name")),XMLGetNamedAttr(rsp, "typing"));
					break;
				case "MSG":
					this.OnRecvMsg(unescape(XMLGetNamedAttr(rsp, "name")),XMLGetNamedAttr(rsp, "msg"),XMLGetNamedAttr(rsp, "type"));
					break;
				case "FIL":
					this.OnRecvFile(unescape(XMLGetNamedAttr(rsp, "name")),unescape(XMLGetNamedAttr(rsp, "filename")),XMLGetNamedAttr(rsp, "filesize"),unescape(XMLGetNamedAttr(rsp, "url")),XMLGetNamedAttr(rsp, "type"));
					break;
				case "IMG":
					this.OnRecvImageUrl(unescape(XMLGetNamedAttr(rsp, "name")),unescape(XMLGetNamedAttr(rsp, "url")));
					break;
				case "WEB":
					this.OnRecvWeb(unescape(XMLGetNamedAttr(rsp, "name")),unescape(XMLGetNamedAttr(rsp, "url")));
					break;
				case "VID": 
					if (XMLGetNamedAttr(rsp, "onlyAudio") == "1")  
					{
						this.OnRecvAudio(XMLGetNamedAttr(rsp, "isOpen") == "1" ? true : false);
					}
					else
					{
						this.OnRecvVideo(XMLGetNamedAttr(rsp, "isOpen") == "1" ? true : false);
					}
					break;
				case "CHM":
					this.OnChannelMsg(XMLGetNamedAttr(rsp, "type"),unescape(XMLGetNamedAttr(rsp, "msg")), XMLGetNamedAttr(rsp, "pId"));
					break;
				case "SSM":
					this.OnSystemMsg(XMLGetNamedAttr(rsp, "id"));
					break;
				case "SMG":
					this.OnSendMsg(XMLGetNamedAttr(rsp, "rCode"));
					break;
				case "STP":
					this.OnSendTyping(XMLGetNamedAttr(rsp, "rCode"));
					break;
				case "SPV":
					this.OnSendPreview(XMLGetNamedAttr(rsp, "rCode"));
					break;
				case "SAU":				
					this.OnSendAudio(XMLGetNamedAttr(rsp, "rCode"));
					break;
				case "SVI":
					this.OnSendAudio(XMLGetNamedAttr(rsp, "rCode"));
					break;
				case "SFI":
					this.OnSendFile(XMLGetNamedAttr(rsp, "rCode"));
					break;
				case "RDR":
					this.OnRedirect(XMLGetNamedAttr(rsp, "url"));
					break;
				case "OCH": 
					mConnected = true;
				  mSiteTag = XMLGetNamedAttr(rsp, "sTag");
				  mSiteId = XMLGetNamedAttr(rsp, "sId");
				  mChannelTag = XMLGetNamedAttr(rsp, "chTag");
				  mChannelId = XMLGetNamedAttr(rsp, "chId");
				  mVisiTag = XMLGetNamedAttr(rsp, "vTag");
				  mVisiId = XMLGetNamedAttr(rsp, "vId");
				  mVisiName = XMLGetNamedAttr(rsp, "vName");
					mLastMsg = -1;
					var rCode = XMLGetNamedAttr(rsp, "rCode");
					var postChat = XMLGetNamedAttr(rsp, "postChat") == "1" ? true : false;
				  var sendFile = XMLGetNamedAttr(rsp, "sendFile") == "1" ? true : false;
				  var postChatUrl = XMLGetNamedAttr(rsp, "postChatUrl");
				  var voiceUrl = XMLGetNamedAttr(rsp, "voiceUrl");
				  var bVideo = XMLGetNamedAttr(rsp, "bVideo") == "1" ? true : false;
				  var bAudio = XMLGetNamedAttr(rsp, "bAudio") == "1" ? true : false;
				  var bRobot = XMLGetNamedAttr(rsp, "bRobot") == "1" ? true : false;
				  var chatList = XMLGetNamedAttr(rsp, "chatList");
				  var wid = XMLGetNamedAttr(rsp, "wid");
//				  var ip = XMLGetNamedAttr(rsp, "IP");
				  var mId = XMLGetNamedAttr(rsp, "mId");
				  var v2cName = XMLGetNamedAttr(rsp, "v2cName");
					var visibleUserInfo = XMLGetNamedAttr(rsp, "visibleUserInfo") == "1" ? true : false;
					var visibleVisitorInfo = XMLGetNamedAttr(rsp, "visibleVisitorInfo") == "1" ? true : false;
					var enabledMember = XMLGetNamedAttr(rsp, "enabledMember") == "1" ? true : false;
					var enabledWarnings = XMLGetNamedAttr(rsp, "enabledWarnings") == "1" ? true : false;
					var warningsMsg = XMLGetNamedAttr(rsp, "warningsMsg");					
					var coId = XMLGetNamedAttr(rsp, "coId");
					var dId = XMLGetNamedAttr(rsp, "dId");
					var oId = XMLGetNamedAttr(rsp, "oId");
				  XMLChannel.prototype.timerID = setInterval("XMLChannel.prototype.ClientTimeout()",1000);
					this.OnOpenChannel(rCode,mSiteTag,mVisiTag,mChannelTag,mVisiName,mSiteId,mVisiId,mChannelId,postChat,sendFile,postChatUrl,bVideo,voiceUrl,bAudio,bRobot,chatList,wid,v2cName,visibleUserInfo,visibleVisitorInfo,enabledMember,enabledWarnings,warningsMsg,mId,coId,dId,oId);
					break;
				case "ECH":
					mConnected = false;
					this.OnEndChannel();
					break;
				case "CCH":
					break;
				case "OK":
					break;
				case "ERR":
					break;
				default:
					this.OnErr(0, "unknown rsp:" + cmd);
			}
		}
		catch(e)
		{
			this.OnErr(e.name,  'Cmd:' + cmd + '\n' +e.message);
			return;
		}
	}
/* GetCmd */
	this.GetCmd = function(reconnect)
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}

		mGetRetry++;
		req.SetURL(mSrvAddr);
		if (reconnect)
		{
			mAddNo++;
			req.AddPostData("reconn", "1");
			this.OnDebug("Reconnect:" + mGetRetry);
		}

		mLastGetTime = new Date().getTime();
		req.AddPostData("CMD", "GET");
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("lastMsg", mLastMsg);
		req.AddPostData("TIME", mLastGetTime);

		req.SendReq();
		mLastGetTag = req.GetTag();

		return req.GetTag();
	}
/* public function */
/* ShutDown */
	this.ShutDown = function(isDown)
	{
		mShutdown = isDown;
		if (mShutdown)
		{
			mLastGetTime = 0;
		}
		else
		{
			mLastGetTime = new Date().getTime();
		}
	}
/* SendMsg */
	this.SendMsg = function(msg)
	{
		var req = this.CreateRequest();

		if (req == null) {
			return;
		}

		req.SetURL(mSrvAddr);

		var wordCount = msg.length;
		var sMsg = escape(msg);
		var sMsg = sMsg.replace(/\+/gi, "%2B");
//alert(sMsg);
		req.AddPostData("CMD", "SMG");
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("Msg", sMsg);
		req.AddPostData("wordCount", wordCount);
		req.SendReq();
        
		return req.GetTag();
	}
/* SendTyping(1,0) */
	this.SendTyping = function(typing)
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr);

		req.AddPostData("CMD", "STP");
		req.AddPostData("TIME", new Date().getTime());
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("typing", typing);

		req.SendReq();

		return req.GetTag();
	}
/* SendPreview */
	this.SendPreview = function(msg)
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr);

		var sMsg = escape(msg);
		var sMsg = sMsg.replace(/\+/gi, "%2B");
		req.AddPostData("CMD", "SPV");
		req.AddPostData("TIME", new Date().getTime());
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("Msg", sMsg);

		req.SendReq();

		return req.GetTag();
	}
/* SendFile */
	this.SendFile = function(filename, filesize, url)
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr);

		req.AddPostData("CMD", "SFI");
		req.AddPostData("TIME", new Date().getTime());
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("filename", escape(filename));
		req.AddPostData("filesize", filesize);
		req.AddPostData("url", escape(url));

		req.SendReq();

		return req.GetTag();
	}
/* SendAudio(1,0) */
	this.SendAudio = function(open)
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr);

		req.AddPostData("CMD", "SAU");
		req.AddPostData("TIME", new Date().getTime());
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("open", open);

		req.SendReq();

		return req.GetTag();
	}
/* SendVideo(1,0) */
	this.SendVideo = function(open)
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr);

		req.AddPostData("CMD", "SVI");
		req.AddPostData("TIME", new Date().getTime());
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);
		req.AddPostData("open", open);

		req.SendReq();

		return req.GetTag();
	}
/* OpenChannel */
	this.OpenChannel = function()
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr + mParams);

		mLastGetTime = new Date().getTime();
		req.AddPostData("CMD", "OCH");
		req.AddPostData("TIME", new Date().getTime());

		req.SendReq();
		mLastGetTag = req.GetTag();

		return req.GetTag();
	}
/* CloseChannel */
	this.CloseChannel = function()
	{
		var req = this.CreateRequest();

		if (null == req)
		{
			return;
		}
        
		req.SetURL(mSrvAddr);
		req.SetAsyn(false);

		mLastGetTime = new Date().getTime();
		req.AddPostData("CMD", "CCH");
		req.AddPostData("TIME", mLastGetTime);
		req.AddPostData("sTag", mSiteTag);
		req.AddPostData("vTag", mVisiTag);
		req.AddPostData("chTag", mChannelTag);

		req.SendReq();
		mLastGetTag = req.GetTag();

		return req.GetTag();
	}
}
