/**
 * Copyright (c) 2008, AimToG. All rights reserved.
 * Code licensed under the AimToG License
 * Version 1.0
 *
 * @author jacojang<jacojang@aimtog.co.kr>
 */

//-----------------------------------------------------------------------------
// Edit Here
//-----------------------------------------------------------------------------
var TS_SERVER_HOST		= "ts.netfunnel.com";	// Default TS host
var TS_SERVER_PORT		= 8000;					// Default TS port
var TS_QUERY_STR		= "ts.wseq";			// Default request query
var TS_MAX_TTL			= 30;					// Default max ttl (second) 5~30
var TS_CONN_TIMEOUT		= 3;					// Default connect timeout (second)
var TS_CONN_RETRY		= 1;					// Default connect retry count
var TS_INIT_LIMIT		= 20;					// Default init retry
var TS_NO_ACTION		= 600;					// Default noAction Timeout (second) 
var TS_COOKIE_ID		= "NetFunnel_ID";		// Default Cookie ID
var TS_COOKIE_TIME		= 0;					// Default Cookie Time (minute) 
var TS_COOKIE_DOMAIN	= "";					// Default Cookie Domain
var TS_BYPASS			= false;				// NetFunnel Routine Bypass [true|false]//NetFunnel 사용하지 않을시 true로 변경
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Global Define
//-----------------------------------------------------------------------------

/*
 * Request Type.
 */
var RTYPE_NONE				= 0000;		/**< 0000:Type 없음				*/
var RTYPE_GET_TID			= 5001;		/**< 5001:티켓ID 요청			*/
var RTYPE_CHK_ENTER			= 5002;		/**< 5002:진입요청				*/
var RTYPE_ALIVE_NOTICE		= 5003;		/**< 5003:Alive Notice 			*/
var RTYPE_SET_COMPLETE		= 5004;		/**< 5004:완료 요청				*/
var RTYPE_GET_TID_CHK_ENTER	= 5101;		/**< 5101:ID요청 + 진입요청		*/
var RTYPE_INIT				= 5105;		/**< 5106:초기화 요청 			*/
var RTYPE_STOP				= 5106;		/**< 5107:정지 요청				*/

/**
 * Return Codes constants
 */
var RET_NORMAL				= 200;		/**< 200:정상					*/
var RET_CONTINUE			= 201;		/**< 201:계속 진행				*/
var RET_E_SYSTEM			= 500;		/**< 500:시스템 에러 			*/
var RET_E_SECURITY			= 501;		/**< 501:보안 에러				*/
var RET_E_IO				= 502;		/**< 502:I/O 에러				*/
var RET_E_CONN_TIMEOUT		= 503;		/**< 503:접속 시간 초과 		*/
var RET_E_ARUNNING			= 504;		/**< 504:이미 실행중			*/
var RET_E_NOINIT			= 505;		/**< 505:초기화 되지 않음		*/ 
var RET_E_INSERT			= 506;		/**< 506:입력 실패				*/
var RET_E_NOPERM			= 507;		/**< 507:권한이 없음.			*/
var RET_E_KEY_EXPIRE		= 508;		/**< 508:Key 유효시간 초과		*/
var RET_E_PARAM				= 509;		/**< 505:올바르지 않은 파라메터	*/ 
var RET_E_NOT_STARTED		= 510;		/**< 507:서비스가 아직 시작전임	*/ 
var RET_E_NO_ACTION			= 511;		/**< 508:사용자의 Action이 없음 */ 

/**
 * Process Status Constants
 */
var PS_N_RUNNING			= 0;		/**< 0:실행중이지 않은 상태		*/
var PS_RUNNING				= 1;		/**< 1:실행중 상태				*/
var PS_CONTINUE				= 2;		/**< 2:계속 실행중 상태			*/
var PS_TIMEOUT				= 3;		/**< 3:접속 제한시간 초과 		*/
var PS_ERROR				= 99;		/**< 99:에러 상태				*/

/**
 * Busy Box Display Type
 */
var BUSY_BOX_TYPE			= 0;		/**< 0:Round Bar 1:ProgressBar	*/

/**
 * NetFunnel Name Space 지정
 */
var NetFunnel 		= new Object();

/**
 * Easy interface를 위한 Global 객체
 */
NetFunnel.gControl 	= null;


/**
 * Busy Alert Box 
 */
NetFunnel.BusyBoxObj = new Object();
NetFunnel.BusyBoxCnt = 0;
NetFunnel.BusyBox = function(oID,oConfig){
    this._cells = new Object();
    this._config = new Object();
    // target Object
    if(typeof oID == "string"){
        this._obj = document.getElementById(oID);
    }else{
        this._obj = oID;
    }

    this._id = NetFunnel.BusyBoxCnt;
    NetFunnel.BusyBoxObj[this._id] = this;
    NetFunnel.BusyBoxCnt++;

    // Config 
    this._config["width"]       = 300;
    this._config["height"]      = 5;
    this._config["count"]       = 20;
    this._config["interval"]    = 50;
    this._config["colors"]		= this._colors;
    this._config["bgcolor"]		= "#FFFFFF";
    if(typeof oConfig == "object"){
        for(var i in oConfig){
            this._config[i] = oConfig[i];
        }
    }
    if(this._config["count"] <= 0){
        this._config["count"]   = 20;
    }

    // Make Display
    this._oTable    = document.createElement("table");
    this._oTable.style.width = this._config["width"]+"px";
    this._oTable.cellPadding = 0;
    this._oTable.cellSpacing = 0;
    //this._oTable.style.border = "1px solid #CDCDCD";

    tTbody  = document.createElement("tbody");
    tRow    = document.createElement("tr");

    for(var i = 0 ; i < this._config["count"] ; i++){
        tCell = document.createElement("td");
        tCell.style.height  = this._config["height"]+"px";
        tCell.style.backgroundColor  = this._config["bgcolor"];
        tCell.id = this._id;
        this._cells[i] = tCell;
        tRow.appendChild(tCell);
    }
    tTbody.appendChild(tRow);
    this._oTable.appendChild(tTbody);
    this._obj.appendChild(this._oTable);

    this.show = function(){
        this._obj.style.visibility = "visible";
        this._timer = setInterval("NetFunnel.BusyBox._action("+this._id+")",this._config["interval"]);
        return;
    };

    this.hide = function(){
        this._obj.style.visibility = "hidden";
        if(this._timer){
            clearInterval(this._timer);
            this._timer = null;
        }
        return;
    };


    this._action = function(id){
        if(this != NetFunnel.BusyBoxObj[id]){
            return this._action.apply(NetFunnel.BusyBoxObj[id],arguments);
        }

		colors_len = this._config["colors"].length;
        if(this._direct == 0){
			j=0
			for(i=(colors_len-1) ; i >= 0 ; i--){
            	tVal = Math.abs(this._curr - i);
            	this._cells[tVal].style.backgroundColor = this._config["colors"][j++];
			}
            this._curr++;
            if(this._curr == this._config["count"]){
                this._direct = 1;
                this._curr = this._config["count"] - 1;
            }
        }else{
			j=0
			for(i=(colors_len-1) ; i >= 0 ; i--){
				if(i>0){
					tVal = ((this._curr+i)>=this._config["count"])?this._config["count"]*2 -1 - (this._curr + i):(this._curr + i);
					if(tVal > 0) this._cells[tVal].style.backgroundColor = this._config["colors"][j++];
				}else{
					this._cells[this._curr].style.backgroundColor = this._config["colors"][j++];
				}
			}
            this._curr--;
            if(this._curr < 0 ){
                this._direct = 0;
                this._curr = 1;
            }
        }
        return true;
    }
}

NetFunnel.ProgressBar = function(oID,oConfig){
    this._cells = new Object();
    this._config = new Object();
    // target Object
    if(typeof oID == "string"){
        this._obj = document.getElementById(oID);
    }else{
        this._obj = oID;
    }

    this._id = NetFunnel.BusyBoxCnt;
    NetFunnel.BusyBoxObj[this._id] = this;
    NetFunnel.BusyBoxCnt++;

    // Config 
    this._config["width"]       = 300;
    this._config["height"]      = 5;
    this._config["count"]       = 20;
    this._config["interval"]    = 50;
    this._config["colors"]		= this._colors;
    this._config["bgcolor"]		= "#FFFFFF";
    if(typeof oConfig == "object"){
        for(var i in oConfig){
            this._config[i] = oConfig[i];
        }
    }
    if(this._config["count"] <= 0){
        this._config["count"]   = 20;
    }

    // Make Display
    this._oTable    = document.createElement("table");
    this._oTable.style.width = this._config["width"]+"px";
    this._oTable.cellPadding = 0;
    this._oTable.cellSpacing = 0;

    tTbody  = document.createElement("tbody");
    tRow    = document.createElement("tr");

    for(var i = 0 ; i < this._config["count"] ; i++){
        tCell = document.createElement("td");
        tCell.style.height  = this._config["height"]+"px";
        tCell.style.backgroundColor  = this._config["bgcolor"];
        tCell.id = this._id;
        this._cells[i] = tCell;
        tRow.appendChild(tCell);
    }
    tTbody.appendChild(tRow);
    this._oTable.appendChild(tTbody);
    this._obj.appendChild(this._oTable);

    this.show = function(){
        this._obj.style.visibility = "visible";
        this._timer = setInterval("NetFunnel.ProgressBar._action("+this._id+")",this._config["interval"]);
        return;
    };

    this.hide = function(){
        this._obj.style.visibility = "hidden";
        if(this._timer){
            clearInterval(this._timer);
            this._timer = null;
        }
        return;
    };

	// 최초 생성시 대기자 수
	var gWaitingCount = 0;
	// 초기 생성 구분 플래그
	var wFlag = 0;

    this._action = function(id){
		// 대기자 수를 구한다.
		var waitingCount = NetFunnel.gLastData.nwait;

		if( wFlag == 0 ){
			// 초기 POPUP생성시 대기자수를 글로벌 변수에 저장
			gWaitingCount = waitingCount;
			// 초기 POPUP 생성 여부를 판단하는 플래그
			wFlag = 1;
		}

		if(this != NetFunnel.BusyBoxObj[id]){
			return this._action.apply(NetFunnel.BusyBoxObj[id],arguments);
		}

		colors_len = this._config["colors"].length;

		// 진행 상태바를 표현하기 위한 데이터 변환( 대기자 수 백분율 환산 )
		currWaiting = 100 - Math.round((NetFunnel.gLastData.nwait / gWaitingCount)*100);

		// 잔상 제거 
		for( i = 0; i <= 99; i ++ )	{
			this._cells[i].style.backgroundColor = "#57A9E1";
		}

		// 현재 대기자 만큼 진행 상태바의 색을 채움
		for( i = 0; i <= currWaiting; i ++ ){
			this._cells[i].style.backgroundColor = this._config["colors"][0];
		}

		this._curr++;

		if(this._curr >= this._config["count"]) {
			this._direct = 100;
		}
		return true;
    }
}

NetFunnel.BusyBox.prototype._mmm    = 0;
NetFunnel.BusyBox.prototype._id     = 0;
NetFunnel.BusyBox.prototype._curr   = 0;
NetFunnel.BusyBox.prototype._direct = 0;
NetFunnel.BusyBox.prototype._obj    = null;
NetFunnel.BusyBox.prototype._cells  = null;
NetFunnel.BusyBox.prototype._timer  = null;
NetFunnel.BusyBox.prototype._oTable = null;
NetFunnel.BusyBox.prototype._config = null;
NetFunnel.BusyBox.prototype._colors = ['',"#FFFFFF","#DDDDDD","#BBBBBB","#999999","#777777","#444444"];


NetFunnel.BusyBox._action = function(id){
    NetFunnel.BusyBoxObj[id]._action(id);
}

NetFunnel.ProgressBar._action = function(id){
    NetFunnel.BusyBoxObj[id]._action(id);
}

/**
 * Cookie 관리
 */
NetFunnel.Cookie = {
	set: function(key,value,minutes,domain) {
		var tStr=key+ "=" +escape(value);

		if(typeof minutes != "undefined"  && (minutes.constructor == Number) && minutes > 0 ) {
			var expire=new Date();
			expire.setMinutes(expire.getMinutes() + minutes);	
			tStr += ";expires="+expire.toGMTString();
		}
		if(typeof domain != "undefined"  && domain.constructor == String && domain != "" ) {
			tStr += ";domain="+domain;
		}else if(TS_COOKIE_DOMAIN != ""){
			tStr += ";domain="+TS_COOKIE_DOMAIN;
		}
		tStr +=";path=/;";
		document.cookie=tStr;
	},

	del: function(key) {
		NetFunnel.Cookie.set(key,"",-1);
	},

	get: function(key){
		if (document.cookie.length>0) {
			c_start=document.cookie.indexOf(key + "=");
			if (c_start!=-1)
			{ 
				c_start=c_start + key.length+1; 
				c_end=document.cookie.indexOf(";",c_start);
				if (c_end==-1) c_end=document.cookie.length;
				return unescape(document.cookie.substring(c_start,c_end));
			} 
		}
		return "";
	}
};

/**
 * Detect Browser
 */
NetFunnel.BrowserDetect = {
	init: function () {
		this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
		this.version = this.searchVersion(navigator.userAgent)
			|| this.searchVersion(navigator.appVersion)
			|| "an unknown version";
		this.OS = this.searchString(this.dataOS) || "an unknown OS";
	},
	searchString: function (data) {
		for (var i=0;i<data.length;i++)	{
			var dataString = data[i].string;
			var dataProp = data[i].prop;
			this.versionSearchString = data[i].versionSearch || data[i].identity;
			if (dataString) {
				if (dataString.indexOf(data[i].subString) != -1)
					return data[i].identity;
			}
			else if (dataProp)
				return data[i].identity;
		}
	},
	searchVersion: function (dataString) {
		var index = dataString.indexOf(this.versionSearchString);
		if (index == -1) return;
		return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
	},
	dataBrowser: [
		{ string: navigator.userAgent, subString: "Chrome", identity: "Chrome" },
		{ string: navigator.userAgent, subString: "OmniWeb", versionSearch: "OmniWeb/", identity: "OmniWeb" },
		{ string: navigator.vendor, subString: "Apple", identity: "Safari" },
		{ prop: window.opera, identity: "Opera" },
		{ string: navigator.vendor, subString: "iCab", identity: "iCab" },
		{ string: navigator.vendor, subString: "KDE", identity: "Konqueror" },
		{ string: navigator.userAgent, subString: "Firefox", identity: "Firefox" },
		{ string: navigator.vendor, subString: "Camino", identity: "Camino" },
		// for newer Netscapes (6+)
		{ string: navigator.userAgent, subString: "Netscape", identity: "Netscape" },
		{ string: navigator.userAgent, subString: "MSIE", identity: "Explorer", versionSearch: "MSIE" },
		{ string: navigator.userAgent, subString: "Gecko", identity: "Mozilla", versionSearch: "rv" },
		// for older Netscapes (4-)
		{ string: navigator.userAgent, subString: "Mozilla", identity: "Netscape", versionSearch: "Mozilla" }
	],
	dataOS : [
		{ string: navigator.platform, subString: "Win", identity: "Windows" },
		{ string: navigator.platform, subString: "Mac", identity: "Mac" },
		{ string: navigator.platform, subString: "Linux", identity: "Linux" }
	]
};
NetFunnel.BrowserDetect.init();

/**
 * 현재의 Mouse의 위치를 받아와서 저장 한다.
 *
 * @memberOf NetFunnel
 * @param {Object} e Event Object
 * @return {Boolean} 실행 성공 여부
 */
NetFunnel.getMouseXY = function(e) {
//  if ( NetFunnel.BrowserDetect.browser == "Explorer") {
//             tempX = event.clientX + document.body.scrollLeft
//             tempY = event.clientY + document.body.scrollTop
//  }else{
//             tempX = e.pageX
//             tempY = e.pageY
//  }
     // catch possible negative values in NS4
//  if (tempX < 0){tempX = 0}
//  if (tempY < 0){tempY = 0}  
     // show the position values in the form named Show
     // in the text fields named MouseX and MouseY
//  NetFunnel.MouseX = tempX
//  NetFunnel.MouseY = tempY
     return true
}

/*
	if ( NetFunnel.BrowserDetect.browser == "Explorer") {
		tempX = event.clientX + document.body.scrollLeft
		tempY = event.clientY + document.body.scrollTop
	}else{
		tempX = e.pageX
		tempY = e.pageY
	}

	// catch possible negative values in NS4
	if (tempX < 0){tempX = 0}
	if (tempY < 0){tempY = 0}  

	// show the position values in the form named Show
	// in the text fields named MouseX and MouseY
	NetFunnel.MouseX = tempX
	NetFunnel.MouseY = tempY

	return true
*/

if ( NetFunnel.BrowserDetect.browser != "Explorer") document.captureEvents(Event.MOUSEMOVE);
document.onmousemove = NetFunnel.getMouseXY;


/**
 * Default Callback Function
 */
NetFunnel.gPop = null;
NetFunnel.gTimer = null;
NetFunnel.gLastData = null;
NetFunnel.countdown_stop = function()
{
	NetFunnel_sendStop();
	if(NetFunnel.gPop) { 
		NetFunnel.gPop.hide();
		NetFunnel.gPop.destroy();
		delete NetFunnel.gPop;
		NetFunnel.gPop = null;
	}
}

NetFunnel.countdown = function()
{
    if(NetFunnel.gLastData && NetFunnel.gLastData.time_left >= 0){
        // 대기 정보를 출력한다.
		var tTime = document.getElementById("NetFunnel_Loading_Popup_TimeLeft");
        var tCount = document.getElementById("NetFunnel_Loading_Popup_Count");

		tCount.innerHTML=NetFunnel.gLastData.nwait;
		tTime.innerHTML=NetFunnel.gLastData.real_time_left;
    }

	if(NetFunnel.gLastData.time_left <=0 && NetFunnel.gTimer){
		clearInterval(NetFunnel.gTimer)
		if(NetFunnel.gPop) { 
			//NetFunnel.gPop.hide();
		}
		return;
	}
	NetFunnel.gLastData.time_left--;
	NetFunnel.gLastData.real_time_left--;
}

NetFunnel.DefaultCallback = {
	"onSuccess": function(ev,ret){
		if(NetFunnel.gTimer){
			clearInterval(NetFunnel.gTimer);
		}
		if(NetFunnel.gPop){
			NetFunnel.gPop.hide();
			NetFunnel.gPop.destroy();
			delete NetFunnel.gPop;
			NetFunnel.gPop = null;
		}
		if(typeof ret.next == "string"){
			document.location.href=ret.next;
		}else if(typeof ret.next == "function"){
			ret.next(ev,ret);
		}
	},
	"onContinued": function(ev,ret) {

		if(typeof ret.next == "string"){
			document.location.href=ret.next;
			return;
		}else if(typeof ret.next == "function"){
			ret.next(ev,ret);
			return;
		}

		if(ret.rtype == RTYPE_CHK_ENTER || ret.rtype == RTYPE_GET_TID_CHK_ENTER){
			if(NetFunnel.gTimer){
				clearInterval(NetFunnel.gTimer);
			}

			if(NetFunnel.gPop){
				NetFunnel.gPop.destroy();
				delete NetFunnel.gPop;
				NetFunnel.gPop = null;
			}

			height=181;
			top_height=85;
			width=400;

			var lp = document.getElementById("NetFunnel_Loading_Popup");
			if(!lp){
				lp = document.createElement('div');
				lp.id = "NetFunnel_Loading_Popup";
				lp.style.border="3px solid #185887";
				lp.style.backgroundColor="#EDEDEE";
				lp.style.textAlign="center";

				lp_top = document.createElement('div');
				lp_top.id = "NetFunnel_Loading_Popup_Top";
				lp_top.style.backgroundColor="white";
				lp_top.style.height=top_height;
				lp_top.align="center";
				lp_top.style.paddingTop="3px";
				lp_top.style.paddingLeft="5px";
				lp_top.style.paddingRight="5px";
				lp.appendChild(lp_top);

				lp_bottom = document.createElement('div');
				lp_bottom.id = "NetFunnel_Loading_Popup_Bottom";
				lp_bottom.style.height=(height-top_height)
				lp_bottom.align="center";
				lp_bottom.style.paddingBottom="3px";
				lp_bottom.style.paddingLeft="5px";
				lp_bottom.style.paddingRight="5px";
				lp.appendChild(lp_bottom);

				lp_ct_top = document.createElement('div');
				lp_ct_top.id = "NetFunnel_Loading_Popup_CT_Top";
				lp_ct_top.style.textAlign="right";
				lp_ct_top.style.font="bold 8px Trebuchet MS,굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_top.innerHTML="<a href='http://www.aimtog.co.kr/net/net_01.asp' target=_blank style='text-decoration:none'><span style='color:#52cb4b'>NET</span><span style='color:337a99'>FUNNEL</span></a>";
				lp_top.appendChild(lp_ct_top);

				lp_ct_wait = document.createElement('div');
				lp_ct_wait.id = "NetFunnel_Loading_Popup_CT_Wait";
				lp_ct_wait.style.textAlign="center";
				lp_ct_wait.style.font="bold 14px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_wait.style.paddingTop="3px";
				lp_ct_wait.style.color="#185887";
				lp_ct_wait.innerHTML="PLEASE WAIT...";
				lp_top.appendChild(lp_ct_wait);

				lp_ct_sec = document.createElement('div');
				lp_ct_sec.id = "NetFunnel_Loading_Popup_CT_Sec";
				lp_ct_sec.style.textAlign="right";
				lp_ct_sec.style.font="bold 12px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_sec.style.color="#676767";
				lp_ct_sec.innerHTML="<span id='NetFunnel_Loading_Popup_TimeLeft'></span> Sec";
				lp_ct_sec.style.width=width*9/10;
				lp_ct_sec.style.paddingBottom="2px";
				lp_top.appendChild(lp_ct_sec);

				lp_ct_busy_top = document.createElement('div');
				lp_ct_busy_top.id = "NetFunnel_Loading_Popup_CT_Busy";
				lp_ct_busy_top.style.textAlign="center";
				lp_ct_busy_top.style.font="bold 12px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_busy_top.style.width=width*9/10;
				lp_ct_busy_top.style.padding="2px";
				lp_ct_busy_top.style.backgroundColor="#57A9E1";
				lp_top.appendChild(lp_ct_busy_top);

				lp_ct_busy = document.createElement('div');
				lp_ct_busy.id = "NetFunnel_Loading_Popup_CT_Busy";
				lp_ct_busy.style.textAlign="center";
				lp_ct_busy.style.width=width*9/10;
				lp_ct_busy_top.appendChild(lp_ct_busy);

				switch (BUSY_BOX_TYPE)
				{
				case 1:
					busybox = new NetFunnel.ProgressBar(lp_ct_busy,{ width:(width*9/10), count:100, bgcolor:"", colors:[ "#FFFF99", ], interval:50 });
					break;
				default :
					busybox = new NetFunnel.BusyBox(lp_ct_busy,{ width:(width*9/10), count:30, bgcolor:"", colors:[ "", "#57A9E1", "#73bbed", "#8dc9f3", "#a7d5f6", "#c3e2f8", "#dceefb", "#f2f7fb", "#FFFFFF", ], interval:50 });
					break;
				}
				busybox.show();

				lp_ct_msg1 = document.createElement('div');
				lp_ct_msg1.id = "NetFunnel_Loading_Popup_CT_Msg1";
				lp_ct_msg1.style.textAlign="center";
				lp_ct_msg1.style.font="normal 12px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_msg1.style.color="#676767";
				lp_ct_msg1.style.paddingTop="7px";
				lp_ct_msg1.style.width=width*9/10;
				lp_ct_msg1.innerHTML="고객님 앞에 <b><span id='NetFunnel_Loading_Popup_Count'></span></b>명의 대기자가 있습니다.";
				lp_top.appendChild(lp_ct_msg1);

				lp_ct_bar = document.createElement('div');
				lp_ct_bar.id = "NetFunnel_Loading_Popup_CT_Bar";
				lp_ct_bar.style.backgroundColor="#2B70A2";
				lp_ct_bar.style.height="1px";
				lp_ct_bar.innerHTML="&nbsp;";
				lp_ct_bar.style.fontSize=0;
				lp_ct_bar.style.lineHeight=0;
				lp_ct_bar.style.overflow="hidden";
				lp_bottom.appendChild(lp_ct_bar);

				lp_ct_msg2 = document.createElement('div');
				lp_ct_msg2.id = "NetFunnel_Loading_Popup_CT_Msg2";
				lp_ct_msg2.style.textAlign="center";
				lp_ct_msg2.style.font="normal 12px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_msg2.style.color="#5378A2";
				lp_ct_msg2.innerHTML="현재 접속량이 많아 대기 중이며, 잠시만 기다리시면";
				lp_ct_msg2.style.paddingTop="11px";
				lp_ct_msg2.style.width=width*9/10;
				lp_bottom.appendChild(lp_ct_msg2);

				lp_ct_msg3 = document.createElement('div');
				lp_ct_msg3.id = "NetFunnel_Loading_Popup_CT_Msg3";
				lp_ct_msg3.style.textAlign="center";
				lp_ct_msg3.style.font="normal 12px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_msg3.style.color="#5378A2";
				lp_ct_msg3.innerHTML="자동으로 해당페이지로 이동합니다.";
				lp_ct_msg3.style.paddingTop="7px";
				lp_ct_msg3.style.paddingBottom="13px";
				lp_ct_msg3.style.width=width*9/10;
				lp_bottom.appendChild(lp_ct_msg3);

				lp_ct_msg4 = document.createElement('div');
				lp_ct_msg4.id = "NetFunnel_Loading_Popup_CT_Msg4";
				lp_ct_msg4.style.padding="5px";
				lp_ct_msg4.style.backgroundColor="#185887";
				lp_ct_msg4.style.textAlign="center";
				lp_ct_msg4.style.color="white";
				lp_ct_msg4.style.width=width*9/10;
				lp_ct_msg4.style.font="normal 12px 굴림,Gulim,AppleGothic,sans-serif";
				lp_ct_msg4.innerHTML="※ Reload 하시면 대기시간이 더 길어집니다. <span onclick='NetFunnel.countdown_stop()' style='cursor:pointer'>[중지]</span>";
				lp_ct_msg4.style.paddingTop="4px";
				lp_bottom.appendChild(lp_ct_msg4);

				var theBody = document.getElementsByTagName('BODY')[0];
				theBody.appendChild(lp);
			}

			NetFunnel.gPop = new NetFunnel.Popup("NetFunnel_Loading_Popup",width,height);	

			delete NetFunnel.gLastData;
			NetFunnel.gLastData = ret.data;
			NetFunnel.gLastData.time_left     = parseInt(ret.data.ttl);
			NetFunnel.gLastData.tps = parseInt(ret.data.tps);
			if(NetFunnel.gLastData.tps == 0) NetFunnel.gLastData.tps = 1;
			NetFunnel.gLastData.real_time_left     = Math.round(parseInt(ret.data.nwait)/NetFunnel.gLastData.tps);
			if(NetFunnel.gLastData.real_time_left < 3){
				NetFunnel.gLastData.real_time_left = 3;
			}

			var tTime = document.getElementById("NetFunnel_Loading_Popup_TimeLeft");
			var tCount = document.getElementById("NetFunnel_Loading_Popup_Count");

			tCount.innerHTML=NetFunnel.gLastData.nwait;
			tTime.innerHTML=NetFunnel.gLastData.real_time_left;

			NetFunnel.gTimer = setInterval("NetFunnel.countdown()",1000);
			NetFunnel.gPop.show();

		}
	},
	"onError":function(ev,ret) {
		if(typeof ret.next == "string"){
			document.location.href=ret.next;
			return;
		}else if(typeof ret.next == "function"){
			ret.next(ev,ret);
			return;
		}
	}
};

/**
 * Event Class 의 생성자
 *
 * @classDescription	새로운 Event클래스를 생성한다.
 * @return {Object}	새로생성된 Event객체 
 * @constructor
 */
NetFunnel.Event = function()
{
	this.events = [];
	this.builtinEvts = [];
}

/**
 * 해당 Element에 대한 주어진 Action의 번호를 얻어온다.
 *
 * @memberOf NetFunnel.Event
 * @param {Object} obj action 이 연결된 element
 * @param {String} evt 이벤트 이름 
 * @param {Function} action 이벤트가 발생했을때 실행된 action
 * @param {Object} binding The object to scope the action to.
 * @return {Number} 정수값
 */
NetFunnel.Event.prototype.getActionIdx = function(obj,evt,action,binding)
{
	if(obj && evt)
	{

		var curel = this.events[obj][evt];
		if(curel)
		{
			var len = curel.length;
			for(var i = len-1;i >= 0;i--)
			{
				if(curel[i].action == action && curel[i].binding == binding)
				{
					return i;
				}
			}
		}
		else
		{
			return -1;
		}
	}
	return -1;
};

/**
 * Listener 추가
 *
 * @memberOf NetFunnel.Event
 * @param {Object} obj action 이 연결된 element
 * @param {String} evt 이벤트 이름 
 * @param {Function} action 이벤트가 발생했을때 실행된 action
 * @param {Object} binding The object to scope the action to.
 * @return {null} 없음.
 */
NetFunnel.Event.prototype.addListener = function(obj,evt,action,binding)
{
	if(this.events[obj])
	{
		if(this.events[obj][evt])
		{
			if(this.getActionIdx(obj,evt,action,binding) == -1)
			{
				var curevt = this.events[obj][evt];
				curevt[curevt.length] = {action:action,binding:binding};
			}
		}
		else
		{
			this.events[obj][evt] = [];
			this.events[obj][evt][0] = {action:action,binding:binding};
		}
	}
	else
	{
		this.events[obj] = [];
		this.events[obj][evt] = [];
		this.events[obj][evt][0] = {action:action,binding:binding};
	}
};

/**
 * Listener 제거
 *
 * @memberOf NetFunnel.Event
 * @param {Object} obj action 이 연결된 element
 * @param {String} evt 이벤트 이름 
 * @param {Function} action 이벤트가 발생했을때 실행된 action
 * @param {Object} binding The object to scope the action to.
 * @return {null} 없음
 */
NetFunnel.Event.prototype.removeListener = function(obj,evt,action,binding)
{
	if(this.events[obj])
	{
		if(this.events[obj][evt])
		{
			var idx = this.actionExists(obj,evt,action,binding);
			if(idx >= 0)
			{
				this.events[obj][evt].splice(idx,1);
			}
		}
	}
};

/**
 * 이벤트 발생
 *
 * @memberOf NetFunnel.Event
 * @param e [(event)] 내장 이벤트객체 전달
 * @param {Object} obj action 이 연결된 element
 * @param {String} evt 이벤트 이름 
 * @param {Object} args 이벤트에 전달된 인자
 * @return {null} 없음.
 */
NetFunnel.Event.prototype.fireEvent = function(e,obj,evt,args)
{
	if(!e){e = window.event;}

	if(obj && this.events)
	{
		var evtel = this.events[obj];
		if(evtel)
		{
			var curel = evtel[evt];
			if(curel)
			{
				for(var act = 0; curel.length > act; act ++)
				{
					var action = curel[act].action;
					if(curel[act].binding)
					{
						action = action.bind(curel[act].binding);
					}
					action(e,args);
				}
			}
		}
	}
};


NetFunnel.gPopup = new Array();
NetFunnel.PopupUtil = {
	getViewportHeight:function () {
		if (window.innerHeight!=window.undefined) return window.innerHeight;
		if (document.compatMode=='CSS1Compat') return document.documentElement.clientHeight;                        
		if (document.body) return document.body.clientHeight;                                                       
		return window.undefined;                                                                                    
	},
	 getViewportWidth:function() {                                                                                   
		var offset = 17;
		var width = null;
		if (window.innerWidth!=window.undefined) return window.innerWidth; 
		if (document.compatMode=='CSS1Compat') return document.documentElement.clientWidth;                         
		if (document.body) return document.body.clientWidth;                                                        
	},                                                                                                               
	getScrollTop:function() { 
		if (self.pageYOffset) {   
			return self.pageYOffset;                                                                                
		} else if (document.documentElement && document.documentElement.scrollTop){   
			return document.documentElement.scrollTop;                                                              
		} else if (document.body) {   
			return document.body.scrollTop;                                                                         
		}                                                                                                           
	},
	getScrollLeft:function() {
		if (self.pageXOffset) {   
			return self.pageXOffset;                                                                                
		} else if (document.documentElement && document.documentElement.scrollLeft){   
			return document.documentElement.scrollLeft;                                                             
		} else if (document.body) {   
			return document.body.scrollLeft;                                                                        
		}                                                                                                           
	},
	resizePopup:function(){
		for(var i = 0; NetFunnel.gPopup.length > i; i++){
			NetFunnel.gPopup[i]._centerPopWin();
		}
	}
}



/**
 * Modal Popup Window
 */
NetFunnel.Popup = function (id,width,height) {
	var theBody = document.getElementsByTagName('BODY')[0];
	var popmask = document.getElementById('mpopup_bg');
	var popiframe = document.getElementById('pop_iframe');
	
	if(!popmask){
		popmask = document.createElement('div');
		popmask.id = 'mpopup_bg';
		popmask.innerHTML="<table width='100%' height='100%'><tr><td>&nbsp;</td></tr></table>";

		popmask.style.position="absolute";
		popmask.style.zIndex="1200";
		popmask.style.top="0px";
		popmask.style.left="0px";
		popmask.style.width="100%";
		popmask.style.height="100%";

		theBody.appendChild(popmask);
	}
	
	if(!popiframe){
		//IE6.0 select처리
		popiframe = document.createElement('iframe');
		popiframe.id = 'pop_iframe';
		popiframe.scrolling = "no";
		popiframe.frameborder="0";
		popiframe.border="0";
		popiframe.framespacing="0";
		popiframe.marginheight="0";
		popiframe.marginwidth="0";
		
		popiframe.style.filter="alpha(opacity=1)";
		popiframe.style.zIndex="1199";
		popiframe.style.top="0px";
		popiframe.style.left="0px";
		popiframe.style.width="100%";
		popiframe.style.height="100%";
		popiframe.style.position="absolute";
		
		theBody.appendChild(popiframe);
	}
	
	var tObj = document.getElementById(id);
	tObj.style.position 	= "absolute";
	tObj.style.visibility 	= "hidden";
	tObj.style.display 		= "none";
	tObj.style.width 		= width;
	tObj.style.height 		= height;

	this._mCount++;	
	this._mMask = popmask;
	this._mPopIFrame = popiframe;
	this._mObj 	= tObj;

	this._mWidth 	= width;
	this._mHeight 	= height;

	this.mid		= "mpopup_"+this._mCount;

	//addEvent(window, "resize", NetFunnel.PopupUtil.resizePopup);
    this.addListener(window,"resize",NetFunnel.PopupUtil.resizePopup); 
	NetFunnel.gPopup.push(this);
}

NetFunnel.Popup.prototype           = new NetFunnel.Event(); 
NetFunnel.Popup.prototype._mCount 	= 0;
NetFunnel.Popup.prototype._mid 		= "";
NetFunnel.Popup.prototype._mObj		= null;
NetFunnel.Popup.prototype._mMask	= null;
NetFunnel.Popup.prototype._mPopIFrame    = null;
NetFunnel.Popup.prototype._mWidth	= 0;
NetFunnel.Popup.prototype._mHeight	= 0;
NetFunnel.Popup.prototype._mIsShown	= false;

NetFunnel.Popup.prototype._setMaskSize = function() {
    var theBody = document.getElementsByTagName("BODY")[0];                                     
            
    var fullHeight = NetFunnel.PopupUtil.getViewportHeight();                                                       
    var fullWidth = NetFunnel.PopupUtil.getViewportWidth();                                                         
    
    // Determine what's bigger, scrollHeight or fullHeight / width                              
    if (fullHeight > theBody.scrollHeight) {                                                    
        popHeight = fullHeight;                                                                 
    } else {
        popHeight = theBody.scrollHeight;                                                       
    }                                                                                           
    
    if (fullWidth > theBody.scrollWidth) {                                                      
        popWidth = fullWidth;                                                                   
    } else {
        popWidth = theBody.scrollWidth;                                                         
    }                                                                                           
    
    this._mMask.style.height 	= popHeight + "px";                                                 
    this._mMask.style.width 	= popWidth + "px";                                                   
}  

NetFunnel.Popup.prototype._centerPopWin = function () {
	if (this._mIsShown){
        var theBody = document.getElementsByTagName("BODY")[0];

        //theBody.style.overflow = "hidden";
        var scTop = parseInt(NetFunnel.PopupUtil.getScrollTop(),10);
        var scLeft = parseInt(theBody.scrollLeft,10);

		this._setMaskSize();

        var fullHeight = NetFunnel.PopupUtil.getViewportHeight();
        var fullWidth = NetFunnel.PopupUtil.getViewportWidth();

        this._mObj.style.top = (scTop + ((fullHeight - this._mHeight) / 2)) + "px";
        this._mObj.style.left =  (scLeft + ((fullWidth - this._mWidth) / 2)) + "px";
    }
}


NetFunnel.Popup.prototype.show = function(){
	var theBody = document.getElementsByTagName("BODY")[0];
	theBody.style.overflow = "hidden";
	this._mObj.style.zIndex 	= "1202";	
	this._mObj.style.visibility = "visible";
	this._mObj.style.display 	= "block";
	this._mMask.style.visiblity	= "visible";
	this._mMask.style.display	= "block";
	this._mPopIFrame.style.visiblity = "visible";
	this._mPopIFrame.style.display   = "block";
	this._mIsShown = true;
	this._centerPopWin();
}

NetFunnel.Popup.prototype.hide = function(){
	var theBody = document.getElementsByTagName("BODY")[0];
	theBody.style.overflow = "auto";
	this._mObj.style.visibility	= "hidden";
	this._mObj.style.display	= "none";
	this._mMask.style.visiblity	= "hidden";
	this._mMask.style.display	= "none";
	this._mPopIFrame.style.visiblity = "hidden";
	this._mPopIFrame.style.display   = "none";
	this._mIsShown = false;
}

NetFunnel.Popup.prototype.destroy = function(){
	// remove event handler;
	//removeEvent(window,"resize",NetFunnel.PopupUtil.resizePopup);
    //this.removeListener(window,"resize",NetFunnel.PopupUtil.resizePopup); 
	//removeEvent(window,"scroll",NetFunnel.PopupUtil.resizePopup);

	// global list 에서 삭제
	var tsize = NetFunnel.gPopup.length;
	for(var i = 0 ; i < tsize ; i++){
		var tObj = NetFunnel.gPopup.pop();
		if(tObj.mid == this.mid){
			delete tObj;
			continue;
		}
		NetFunnel.gPopup.push(tObj);	
	}
}

/**
 * RetVal Class 의 생성자.
 *
 * @classDescription NetFunnel에서 받아온 결과값을 Parsing해 준다.
 * @param {String} 결과 문자열
 */
NetFunnel.RetVal = function(str)
{
	this._mParam	= new Object();
	this._mRtype 	= parseInt(str.substr(0,4));
	this._mCode 	= parseInt(str.substr(5,3));
	this._mRetStr	= str.substr(9,str.length - 9);

	this._parse();
}

//-----------------------------------------------------------------------------
// NetFunnel.RetVal private variable 
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// NetFunnel.RetVal public variable 
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// NetFunnel.RetVal private member function
//-----------------------------------------------------------------------------
/**
 * left trim
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} str Input String
 * @return {String} processed String
 */
NetFunnel.RetVal.prototype._ltrim = function(str) { 
	for(var k = 0; k < str.length && this._isWhitespace(str.charAt(k)); k++);
	return str.substring(k, str.length);
}
/**
 * right trim
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} str Input String
 * @return {String} processed String
 */
NetFunnel.RetVal.prototype._rtrim = function(str) {
	for(var j=str.length-1; j>=0 && this._isWhitespace(str.charAt(j)) ; j--) ;
	return str.substring(0,j+1);
}

/**
 * String trim
 *   - 문자열 앞뒤의 공백 제거
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} str Input String
 * @return {String} processed String
 */
NetFunnel.RetVal.prototype._trim = function(str) {
	return this._ltrim(this._rtrim(str));
}

/**
 * 공백문자 여부 판다.
 *    - 공백문자 = " \t\n\r\f"
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} charToCheck 테스트 char
 * @return {Boolean} 공백여부
 */
NetFunnel.RetVal.prototype._isWhitespace = function(charToCheck) {
	var whitespaceChars = " \t\n\r\f";
	return (whitespaceChars.indexOf(charToCheck) != -1);
}

/**
 * 입력된 결과값을 파싱해서 사용하기 편리한 형태로 저장 한다.
 *
 * @memberOf NetFunnel.RetVal
 * @return {null} 없음
 */
NetFunnel.RetVal.prototype._parse = function()
{
	var titem = this._mRetStr.split('&');
	for(var i = 0; titem.length > i; i++){
		temp=titem[i].split('=');

		if(temp.length > 1){
			key=this._trim(temp[0]);
			value=this._trim(temp[1]);

			this._mParam[key] = value;
		}
	}
}

//-----------------------------------------------------------------------------
// NetFunnel.RetVal public member function
//-----------------------------------------------------------------------------
/**
 * Return Code 전달
 *
 * @memberOf NetFunnel.RetVal
 * @return {Number} Return Code 값
 */
NetFunnel.RetVal.prototype.getRetCode = function(){
	return this._mCode;
}
NetFunnel.RetVal.prototype.setRetCode = function(inCode){
	return (this._mCode = inCode);
}
/**
 * 요청 타입 (Request Type) 전달
 *
 * @memberOf NetFunnel.RetVal
 * @return {Number} Request Type 값
 */
NetFunnel.RetVal.prototype.getReqType = function(){
	return this._mRtype;
}
NetFunnel.RetVal.prototype.setReqType = function(inType){
	return (this._mRtype = inType);
}
/**
 * 결과 문자열 전달
 *
 * @memberOf NetFunnel.RetVal
 * @return {String} 생성시 입력되었던 결과 문자열
 */
NetFunnel.RetVal.prototype.getRetStr = function(){
	return this._mRetStr;
}

/**
 * 결과값 요청
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} key 찾으려는 값의 key 문자열
 * @return {String} key에 해당하는 value 문자열
 */
NetFunnel.RetVal.prototype.getValue = function(key){
	try{
		return this._mParam[key];
	}catch(e){
		return null;
	}
}

/**
 * 결과값 설정
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} key 설정하려는 값의 key 문자열
 * @param {String} value 설정하려는 값의 value 문자열
 * @return {String} 이전 Value 값
 */
NetFunnel.RetVal.prototype.setValue = function(key,value){
	oldValue = null
	try{
		
		if ( this.isKeyExist(key) ){
			oldValue = this.getValue(key);
		}

		this._mParam[key] = value;
		return oldValue;
	}catch(e){
		return null;
	}
}


/**
 * 숫자형 결과값 요청
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} key 찾으려는 값의 key 문자열
 * @return {Number} key에 해당하는 value 숫자
 */
NetFunnel.RetVal.prototype.getNumber = function(key){
	try{
		return parseInt(this._mParam[key]);
	}catch(e){
		return 0;
	}
}

/**
 * key 존재 여부 확인
 *
 * @memberOf NetFunnel.RetVal
 * @param {String} key 찾으려는 값의 key 문자열
 * @return {Boolean} key의 존재여부
 */
NetFunnel.RetVal.prototype.isKeyExist = function(key){
	try{
		if(this._mParam[key] != null){
			return true;
		}
	}catch(e){
	}
	return false;
}

/**
 * 전체 Parameter Object 요청
 *
 * @memberOf NetFunnel.RetVal
 * @return {Object} parameter들의 저장된 Object
 */
NetFunnel.RetVal.prototype.getParam = function(){
	return this._mParam;
}



/**
 * TsClient Contructor
 *
 */
NetFunnel.TsClient = function(oConfigs,oCallbacks)
{
	this.mConfig 					= new Object();
	this.mConfig["host"] 			= TS_SERVER_HOST;
	this.mConfig["port"]			= TS_SERVER_PORT;
	this.mConfig["query"]			= TS_QUERY_STR;
	this.mConfig["max_ttl"]			= TS_MAX_TTL;
	this.mConfig["conn_timeout"]	= TS_CONN_TIMEOUT;
	this.mConfig["conn_retry"]		= TS_CONN_RETRY;
	this.mConfig["no_action"]		= TS_NO_ACTION;
	this.mConfig["cookie_id"]		= TS_COOKIE_ID;
	this.mConfig["cookie_time"]		= TS_COOKIE_TIME;
	this.mConfig["cookie_domain"]	= TS_COOKIE_DOMAIN;

    // Validate configs
    if(oConfigs && (oConfigs.constructor == Object)) {
        for(var sConfig in oConfigs) {
            this.mConfig[sConfig] = oConfigs[sConfig];
        }
    }
	this.id			= NetFunnel.TsClient._Count;
	//this.id			= "netfunnel_obj_"+NetFunnel.TsClient._Count;
	NetFunnel.TsClient._Objects[this.id] = this;
	NetFunnel.TsClient._Count = NetFunnel.TsClient._Count + 1;

	// Add Event Listener
	if(oCallbacks["onSuccess"])		{ this.addListener(this,"onSuccess",oCallbacks["onSuccess"]); }
	if(oCallbacks["onContinued"])	{ this.addListener(this,"onContinued",oCallbacks["onContinued"]); }
	if(oCallbacks["onError"])		{ this.addListener(this,"onError",oCallbacks["onError"]); }


	this.counter[RTYPE_NONE]			= 0;
	this.counter[RTYPE_GET_TID]			= 0;
	this.counter[RTYPE_CHK_ENTER]		= 0;
	this.counter[RTYPE_ALIVE_NOTICE]	= 0;
	this.counter[RTYPE_SET_COMPLETE]	= 0;
	this.counter[RTYPE_INIT]			= 0;
	this.counter[RTYPE_STOP]			= 0;


	this.connTimeout = function connTimeout(id)
	{
		if(this != NetFunnel.TsClient._Objects[id]){
			return connTimeout.apply(NetFunnel.TsClient._Objects[id],arguments);
		}
		this._resetScript();

		if(this.counter[this._mReqType] < this.mConfig["conn_retry"]){
			this._mStatus = PS_TIMEOUT;
			this.counter[this._mReqType] += 1;
			switch(this._mReqType){
				case RTYPE_GET_TID: 
					this.getTicketID(this.user_id,this.user_tid,false);
					return;
					break;
				case RTYPE_CHK_ENTER: 
					this.chkEnter(this.key,false);
					return;
					break;
				case RTYPE_GET_TID_CHK_ENTER: 
					this.getTidChkEnter(this.user_id,this.user_tid,false);
					return;
					break;
				case RTYPE_ALIVE_NOTICE: 
					this.aliveNotice(this.key,"","",false);
					return;
					break;
				case RTYPE_SET_COMPLETE: 
					this.setComplete(this.key,"","",false);
					return;
					break;
				default:
			}
		}
		if(this._mReqType == RTYPE_CHK_ENTER || this._mReqType == RTYPE_GET_TID_CHK_ENTER ){
			NetFunnel.Cookie.set(this.mConfig["cookie_id"],"5002:200:key=connection_timeout",1,this.mConfig["cookie_domain"]);
		}
		this.fireEvent(null,this,'onError',{rtype:this._mReqType,code:RET_E_CONN_TIMEOUT,data:{msg:"Connection Timeout"},next:this.next.success});
		this._mStatus = PS_ERROR;

	};
}

NetFunnel.connTimeout = function(id)
{
	try{
		setTimeout("NetFunnel.connTimeoutProc("+id+")",5000);
	}catch(e){
	}
};

NetFunnel.connTimeoutProc = function(id)
{
	try{
		NetFunnel.TsClient._Objects[id].connTimeout(id);
	}catch(e){
	}
};


NetFunnel.chkEnter = function(id)
{
	try{
		tRetVal = null;
		tKey 	= NetFunnel.TsClient._Objects[id].key;

		if( typeof NetFunnel.TsClient._Objects[id].retval == "object" ){
			tRetVal = NetFunnel.TsClient._Objects[id].retval;
		}

		if(tRetVal != null && tRetVal.isKeyExist("key")){
			tKey = tRetVal.getValue("key");
		}
		
		NetFunnel.TsClient._Objects[id].chkEnter(tKey);
	}catch(e){
	}
};


NetFunnel.chkEnterCont = function(id)
{
	try{
		tRetVal = null;
		tKey 	= NetFunnel.TsClient._Objects[id].key;

		if( typeof NetFunnel.TsClient._Objects[id].retval == "object" ){
			tRetVal = NetFunnel.TsClient._Objects[id].retval;
		}

		if(tRetVal != null && tRetVal.isKeyExist("key")){
			tKey = tRetVal.getValue("key");
		}
		
		NetFunnel.TsClient._Objects[id].chkEnterCont(tKey);
	}catch(e){
	}
};

NetFunnel.aliveNotice = function(id)
{
	try{
		tRetVal = null;
		tKey 	= NetFunnel.TsClient._Objects[id].key;
		tIp 	= NetFunnel.TsClient._Objects[id].ip;
		tPort 	= NetFunnel.TsClient._Objects[id].port;


		if( typeof NetFunnel.TsClient._Objects[id].retval == "object" ){
			tRetVal = NetFunnel.TsClient._Objects[id].retval;
		}

		if(tRetVal && tRetVal.isKeyExist("key")){
			tKey = tRetVal.getValue("key");
		}
		if(tRetVal && tRetVal.isKeyExist("ip")){
			tIp = tRetVal.getValue("ip");
		}
		if(tRetVal && tRetVal.isKeyExist("port")){
			tPort = tRetVal.getValue("port");
		}

		NetFunnel.TsClient._Objects[id].aliveNotice(tKey,tIp,tPort,true);
	}catch(e){
	}
};


NetFunnel.aliveNoticeCont = function(id)
{
	try{
		tRetVal = null;
		tKey 	= NetFunnel.TsClient._Objects[id].key;
		tIp 	= NetFunnel.TsClient._Objects[id].ip;
		tPort 	= NetFunnel.TsClient._Objects[id].port;

		if( typeof NetFunnel.TsClient._Objects[id].retval == "object" ){
			tRetVal = NetFunnel.TsClient._Objects[id].retval;
		}

		if(tRetVal && tRetVal.isKeyExist("key")){
			tKey = tRetVal.getValue("key");
		}
		if(tRetVal && tRetVal.isKeyExist("ip")){
			tIp = tRetVal.getValue("ip");
		}
		if(tRetVal && tRetVal.isKeyExist("port")){
			tPort = tRetVal.getValue("port");
		}

		NetFunnel.TsClient._Objects[id].aliveNoticeCont(tKey,tIp,tPort,true);
	}catch(e){
	}
};

NetFunnel.setComplete = function(id)
{
	try{
		tRetVal = null;
		tKey 	= NetFunnel.TsClient._Objects[id].key;
		tIp 	= NetFunnel.TsClient._Objects[id].ip;
		tPort 	= NetFunnel.TsClient._Objects[id].port;

		if( typeof NetFunnel.TsClient._Objects[id].retval == "object" ){
			tRetVal = NetFunnel.TsClient._Objects[id].retval;
		}

		if(tRetVal && tRetVal.isKeyExist("key")){
			tKey = tRetVal.getValue("key");
		}
		if(tRetVal && tRetVal.isKeyExist("ip")){
			tIp = tRetVal.getValue("ip");
		}
		if(tRetVal && tRetVal.isKeyExist("port")){
			tPort = tRetVal.getValue("port");
		}

		NetFunnel.TsClient._Objects[id].setComplete(tKey,tIp,tPort,true);
	}catch(e){
	}
};




//-----------------------------------------------------------------------------
// NetFunnelTsClient private variable 
//-----------------------------------------------------------------------------
NetFunnel.TsClient._Count 				= 0;
NetFunnel.TsClient._Objects 			= new Object();

/**
 * NetFunnel.Event Class 상속
 */
NetFunnel.TsClient.prototype			= new NetFunnel.Event();

/**
 * Init Done flag
 */
NetFunnel.TsClient.prototype._initDone 	= false;



//-----------------------------------------------------------------------------
// NetFunnelTsClient public variable 
//-----------------------------------------------------------------------------
/**
 * Object ID
 */
NetFunnel.TsClient.prototype.id 		= null;

/**
 * 설정정보 
 */
NetFunnel.TsClient.prototype.mConfig	= null;

/**
 * TS 서버 접속을 위한 key
 */
NetFunnel.TsClient.prototype.key		= null;

/**
 * Script Object
 */
NetFunnel.TsClient.prototype.script		= null;

/**
 * Alarm Object
 */
NetFunnel.TsClient.prototype.alarm		= null;

/**
 * Alarm Object
 */
NetFunnel.TsClient.prototype._mReqType	= RTYPE_NONE;

/**
 * Previous Mouse Position
 */
NetFunnel.TsClient.prototype._mMousePos	= 0;

/**
 * Action 이 없었던 누적 시간
 */
NetFunnel.TsClient.prototype._mNoActTime= 0;

/**
 * Process Status
 */
NetFunnel.TsClient.prototype._mStatus	= PS_N_RUNNING;


NetFunnel.TsClient.prototype.counter	= new Object();

/**
 * 성공및 실패시 이동할 경로
 */
NetFunnel.TsClient.prototype.next		= {success:"",error:""};

//-----------------------------------------------------------------------------
// NetFunnel.TsClient Private member function
//-----------------------------------------------------------------------------
/**
 * 초기화
 *   - 객체를 생성한 후에 최초 1번 꼭 실행시켜 주어야 한다.
 *   - 초기화 성공여부는 isInitDone() 함수를 통해서 확인 활 수 있다.
 *
 * @memberOf NetFunnel.TsClient
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.init = function(){
	this._nCount++;
	this._initDone = true;

};

/**
 * 사용자의 Action 이 있는지 여부 확인
 *   - 마우스의 움직으로 확인한다.
 *
 * @memberOf NetFunnel.TsClient
 * @return {Boolean} Action여부.
 */
NetFunnel.TsClient.prototype._isNoAction = function(){
	if(this._mMousePos == NetFunnel.MouseX){
		return true;
	}
	this._mMousePos = NetFunnel.MouseX;
	return false;
};

/**
 * Connection Timeout 을 체크하기 위한 타이머를 Reset
 *
 * @memberOf NetFunnel.TsClient
 * @return {Null} 없음
 */
NetFunnel.TsClient.prototype._resetAlarm = function(){
	if(this.alarm != null){
		clearTimeout(this.alarm);
	}
	this.alarm = null;
};

/**
 * Continued 이벤트에 의한 재시도를 위한 타이머를 Reset
 *
 * @memberOf NetFunnel.TsClient
 * @return {Null} 없음
 */
NetFunnel.TsClient.prototype._resetRetryTimer = function(){
	if(this.retryTimer != null){
		clearTimeout(this.retryTimer);
	}
	this.retryTimer = null;
};

/**
 * Script Object를 초기화 한다.
 *
 * @memberOf NetFunnel.TsClient
 * @return {Null} 없음
 */
NetFunnel.TsClient.prototype._resetScript = function(){
	if(this.script){
		var head = document.getElementsByTagName("head").item(0);
		head.removeChild(this.script);
	}
	this.script = null;
};

/**
 * 사용자의 요청에 의한 결과 값을 Parsing 하고 알맞는 이벤트를 사용자에게 
 * 돌려준다.
 *
 * @memberOf NetFunnel.TsClient
 * @return {Null} 없음
 */
NetFunnel.TsClient.prototype._showResult = function(){
	this._resetAlarm();
	this.retval = new NetFunnel.RetVal(this.result);
	
	// 받아온 값을 쿠키에 저장
	if(this.retval.getReqType() == RTYPE_GET_TID_CHK_ENTER){
		this.retval.setReqType(RTYPE_CHK_ENTER);	
	}

	NetFunnel.ttl = 0;
	this.counter[this._mReqType] = 0;
	switch(this.retval.getReqType()){
		case RTYPE_GET_TID: 
			this._showResultGetTicketID(this.retval);
			break;
		case RTYPE_CHK_ENTER: 
			this._showResultChkEnter(this.retval);
			break;
		case RTYPE_ALIVE_NOTICE: 
			this._showResultAliveNotice(this.retval);
			break;
		case RTYPE_SET_COMPLETE: 
			this._showResultSetComplete(this.retval);
			break;
		default:
			NetFunnel.Cookie.del(this.mConfig["cookie_id"]);
			this.fireEvent(null,this,'onError',
					{rtype:RTYPE_NONE,code:this.retval.getRetCode(),data:this.retval.getParam(),next:this.next.error});
			this._mStatus = PS_ERROR;
	}
};

NetFunnel.TsClient.prototype._showResultGetTicketID = function(retval){
	switch(retval.getRetCode()){
		case RET_NORMAL:
			// Success Event 
			NetFunnel.Cookie.set(this.mConfig["cookie_id"],this.result,this.mConfig["cookie_time"],this.mConfig["cookie_domain"]);
			this._mStatus = PS_N_RUNNING;
			this.fireEvent(null,this,'onSuccess',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.success});
			break;
		default:
			// Fail Event
			NetFunnel.Cookie.del(this.mConfig["cookie_id"]);
			this._mStatus = PS_ERROR;
			this.fireEvent(null,this,'onError',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.error});
			
	}
	return;
};

NetFunnel.TsClient.prototype._showResultChkEnter = function(retval){
	switch(retval.getRetCode()){
		case RET_NORMAL:
			// Success Event 
			NetFunnel.Cookie.set(this.mConfig["cookie_id"],this.result,this.mConfig["cookie_time"],this.mConfig["cookie_domain"]);
			this._mStatus = PS_N_RUNNING;
			this.fireEvent(null,this,'onSuccess',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.success});
			break;
		case RET_CONTINUE:
			// Continued Event 
			this._mStatus = PS_CONTINUE;

			// ReTry
			ttl = retval.getNumber('ttl');
			if(ttl > this.mConfig["max_ttl"]){
				ttl = this.mConfig["max_ttl"];
				retval.setValue('ttl',ttl);
			}

			this.fireEvent(null,this,'onContinued',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.continued});

			if(ttl > 0){
				if(this.retryTimer){
					clearTimeout(this.retryTimer);
				}
				NetFunnel.ttl = ttl;
				this.retryTimer = setTimeout("NetFunnel.chkEnterCont("+this.id+")",ttl*1000);	
			}

			break;
		default:
			// Fail Event
			NetFunnel.Cookie.del(this.mConfig["cookie_id"]);
			this._mStatus = PS_ERROR;
			this.fireEvent(null,this,'onError',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.error});
			
	}
	return;
};

NetFunnel.TsClient.prototype._showResultAliveNotice = function(retval){
	switch(retval.getRetCode()){
		case RET_NORMAL:
			// Success Event 
			this._mStatus = PS_N_RUNNING;
			this.fireEvent(null,this,'onSuccess',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.success});
			break;
		case RET_CONTINUE:
			// Continued Event 
			this._mStatus = PS_CONTINUE;
			if( this._mNoActTime > this.mConfig["no_action"]){
				this.fireEvent(null,this,'onError',
						{rtype:retval.getReqType(),code:RET_E_NO_ACTION,data:retval.getParam(),next:this.next.error});
				this._mNoActTime = 0;
				this._mStatus = PS_ERROR;
				break;
			}

			ttl = retval.getNumber('ttl');
			if(ttl > this.mConfig["max_ttl"]){
				ttl = this.mConfig["max_ttl"];
				retval.setValue('ttl',ttl);
			}

			this.fireEvent(null,this,'onContinued',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.continued});

			if(ttl > 0){
				if(this.retryTimer){
					clearTimeout(this.retryTimer);
				}
				if(this._isNoAction()){
					this._mNoActTime += ttl;
				}else{
					this._mNoActTime = 0;
				}
				this.retryTimer = setTimeout("NetFunnel.aliveNoticeCont("+this.id+")",ttl*1000);	
			}

			break;
		default:
			// Fail Event
			if(retval.getRetCode() == RET_E_KEY_EXPIRE){
				NetFunnel.Cookie.del(this.mConfig["cookie_id"]);
			}
			this._mStatus = PS_ERROR;
			this.fireEvent(null,this,'onError',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.error});
			
	}
	return;
};

NetFunnel.TsClient.prototype._showResultSetComplete = function(retval){
	NetFunnel.Cookie.del(this.mConfig["cookie_id"]);
	switch(retval.getRetCode()){
		case RET_NORMAL:
			// Success Event 
			this._mStatus = PS_N_RUNNING;
			this.fireEvent(null,this,'onSuccess',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.success});
			break;
		default:
			// Fail Event
			this._mStatus = PS_ERROR;
			this.fireEvent(null,this,'onError',
					{rtype:retval.getReqType(),code:retval.getRetCode(),data:retval.getParam(),next:this.next.error});
			
	}
	return;
};




/**
 * 신규 접속을 위한 접속정보 초기화
 *
 * @memberOf NetFunnelTsClient
 * @param {Number} rtype 요청 타입
 * @return {Boolean} 초기화 성공여부
 */
NetFunnel.TsClient.prototype._connInit = function(rtype)
{
	this.result 		= null;
	this._mReqType		= rtype;
	this._resetAlarm();
	this._resetScript();
	this._resetRetryTimer();
	this.alarm = setTimeout("NetFunnel.connTimeout("+this.id+")",parseInt(this.mConfig["conn_timeout"])*1000);


	if(!this.mConfig["host"] || this.mConfig["host"] == ""){
		return false;
	}
	if(!this.mConfig["port"] || this.mConfig["port"] == ""){
		return false;
	}
	if(!this.mConfig["query"] || this.mConfig["query"] == ""){
		return false;
	}
	this._mStatus = PS_RUNNING;
	return true;
};

/**
 * TS 서버로 요청 전송
 *
 * @memberOf NetFunnelTsClient
 * @param {String} url 요청 URL
 * @return {Boolean} 요청 성공여부
 */
NetFunnel.TsClient.prototype._sendRequest = function(url){
	// 1. Script 객체 생성
	this.script = document.createElement ("script");

	// 2. Script 객체에 URL 등록, Head에 Script 등록
	this.script.src = url;
	var head = document.getElementsByTagName("head").item(0);
	head.appendChild(this.script);

	return true;
}

/**
 * 에러 전달 
 *
 * @memberOf NetFunnelTsClient
 * @param {Number} eRType 요청 타입
 * @param {Number} eCode 결과값 코드
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype._sendError = function(eRType,eCode)
{		
	var tMsg = "";
	switch(eCode){
		case RET_E_ARUNNING:
			tMsg = "Already running";
			break;
		case RET_E_NOINIT:
			tMsg = "Uninitialized object";
			break;
		case RET_E_SYSTEM:
		default:
			tMsg = "System error";
			
	}
	this.fireEvent(null,this,'onError',{rtype:eRType,code:eCode,data:{msg:tMsg},next:this.next.error});
}



//-----------------------------------------------------------------------------
// NetFunnel.TsClient public member function
//-----------------------------------------------------------------------------

/**
 * 명령 성공시 이동하게될 URL를 설정한다.
 *   - DefaultCallback 을 사용할때만 유효하며 Callback 함수를 지정했다면
 *     사용되지 않는다.
 *
 * @memberOf NetFunnelTsClient
 * @param {String} success 명령 성공시 이동할 URL
 * @param {String} error 명령 실패시 이동할 URL
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.setNext = function(next){
	if( typeof next == "object"){
		this.next 	= next;
	}else{
		this.next.success = undefined;
		this.next.continued = undefined;
		this.next.error = undefined;
	}
}

/**
 * 실행중인 명령 멈춤 전송
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @memberOf NetFunnelTsClient
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.sendStop = function(first){
	if(TS_BYPASS == true) { this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success}); return true; }

	if(first == 'undefined'){ first = true; }
	if(first){ this.counter[RTYPE_STOP]=0; }

	this._resetAlarm();
	this._resetRetryTimer();
	this._resetScript();
	this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success});

	this._mStatus = PS_N_RUNNING;
	return true;
}


/**
 * TicketID 요청 명령 전송
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @memberOf NetFunnelTsClient
 * @param {String} user_id 사용자ID
 * @param {String} user_tid 사용자TID (서비스에 사용되는 Ticket에 대한 식별자)
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.getTicketID = function(user_id,user_tid,first){
	if(TS_BYPASS == true) { this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success}); return true; }

	if(first == 'undefined'){ first = true; }
	if(first){ this.counter[RTYPE_GET_TID]=0; }

	// 0. 실행중인지 여부 확인
	if ( this._mStatus == PS_RUNNING ) {
		this._sendError(RTYPE_GET_TID,RET_E_ARUNNING);
		return false;
	}

	// 1. 초기화
	if(!this._connInit(RTYPE_GET_TID)){
		this._sendError(RTYPE_GET_TID,RET_E_NOINIT);
		return false;
	}

	this.user_id = user_id;
	this.user_tid = user_tid;

	// 2. URL 생성
	url = "http://"+this.mConfig["host"]+":"+this.mConfig["port"]+"/"+this.mConfig["query"]+"?opcode="+RTYPE_GET_TID+"&nfid="+this.id;
	url += "&js=yes";
	url += "&user_id="+user_id;
	url += "&user_tid="+user_tid;

	tdate = new Date();
	url += "&"+tdate.getTime();

	this._sendRequest(url);

	return true;
}


/**
 * 진입 요청 명령 전송
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onContinued(evt,oArg.rtype,oArg.code,oArg.data) : 대기
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @memberOf NetFunnelTsClient
 * @param {String} key getTicketID를 통해 전달받은 식별자
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.chkEnter = function(key,first){
	// 0. 실행중인지 여부 확인
	if(TS_BYPASS == true) { this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success}); return true; }

	if ( this._mStatus == PS_RUNNING || this._mStatus == PS_CONTINUE) {
		this._sendError(RTYPE_CHK_ENTER,RET_E_ARUNNING);
		return false;
	}
	return this.chkEnterProc(key,first);
}

NetFunnel.TsClient.prototype.chkEnterCont = function(key,first){
	// 0. 실행중인지 여부 확인
	if ( this._mStatus == PS_RUNNING ) {
		this._sendError(RTYPE_CHK_ENTER,RET_E_ARUNNING);
		return false;
	}
	return this.chkEnterProc(key,first);
}

NetFunnel.TsClient.prototype.chkEnterProc = function(key,first){
	if(first == 'undefined'){ first = true; }
	if(first){ this.counter[RTYPE_CHK_ENTER]=0; }

	// 1. 초기화
	if(!this._connInit(RTYPE_CHK_ENTER)){
		this._sendError(RTYPE_CHK_ENTER,RET_E_NOINIT);
		return false;
	}

	if(!key || key == ""){
		if(this.key){
			key = this.key;	
		}else{
			this._sendError(RTYPE_CHK_ENTER,RET_E_PARAM);
			return false;
		}
	}
	this.key = key;

	url = "http://"+this.mConfig["host"]+":"+this.mConfig["port"]+"/"+this.mConfig["query"]+"?opcode="+RTYPE_CHK_ENTER+"&key="+key+"&nfid="+this.id;
	if(NetFunnel.ttl > 0){
		url = url+"&ttl="+NetFunnel.ttl;
	}
	url += "&js=yes";
	tdate = new Date();
	url += "&"+tdate.getTime();

	this._sendRequest(url);

	return true;
}

/**
 * ID발급 + 진입 요청 명령 전송
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onContinued(evt,oArg.rtype,oArg.code,oArg.data) : 대기
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @memberOf NetFunnelTsClient
 * @param {String} user_id 사용자ID
 * @param {String} user_tid 사용자TID (서비스에 사용되는 Ticket에 대한 식별자)
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.getTidChkEnter = function(user_id,user_tid,first){
	// 0. 실행중인지 여부 확인
	if(TS_BYPASS == true) { this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success}); return true; }

	if ( this._mStatus == PS_RUNNING || this._mStatus == PS_CONTINUE) {
		this._sendError(RTYPE_CHK_ENTER,RET_E_ARUNNING);
		return false;
	}
	return this.getTidChkEnterProc(user_id,user_tid,first);
}

NetFunnel.TsClient.prototype.getTidChkEnterProc = function(user_id,user_tid,first){
	if(first == 'undefined'){ first = true; }
	if(first){ this.counter[RTYPE_GET_TID_CHK_ENTER]=0; }

	// 1. 초기화
	if(!this._connInit(RTYPE_GET_TID_CHK_ENTER)){
		this._sendError(RTYPE_GET_TID_CHK_ENTER,RET_E_NOINIT);
		return false;
	}

	this.user_id = user_id;
	this.user_tid = user_tid;

	url = "http://"+this.mConfig["host"]+":"+this.mConfig["port"]+"/"+this.mConfig["query"]+"?opcode="+RTYPE_GET_TID_CHK_ENTER+"&nfid="+this.id;
	if(NetFunnel.ttl > 0){
		url = url+"&ttl="+NetFunnel.ttl;
	}
	url += "&js=yes";
	tdate = new Date();
	url += "&"+tdate.getTime();
	url += "&user_id="+user_id;
	url += "&user_tid="+user_tid;

	this._sendRequest(url);

	return true;
}


/**
 * Alive Notice 요청 명령 전송
 *  - chkEnter 명령을 통해서 시스템에 진입 허가를 받은후에는 이 명령을 전송해 줘야만 현재의 
 *    client가 프로세스를 진행 하는지를 TS 서버에서 알 수 있게 된다. 반복 주기는 TS 서버에서 
 *    알려 주게 되며 flash client에서 자동으로 재전송하게 된다.
 *
 *   - Event
 *     - onContinued(evt,oArg.rtype,oArg.code,oArg.data) : 대기
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @memberOf NetFunnelTsClient
 * @param {String} key chkEnter를 통해 전달받은 식별자
 * @param {String} ip TS서버 IP 정보
 * @param {Number} port TS서버 Port 정보
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.aliveNoticeProc = function(key,ip,port,first){
	if(first == 'undefined'){ first = true; }
	if(first){ this.counter[RTYPE_ALIVE_NOTICE]=0; }

	// 1. 초기화
	if(!this._connInit(RTYPE_ALIVE_NOTICE)){
		this._sendError(RTYPE_ALIVE_NOTICE,RET_E_NOINIT);
		return false;
	}

	if(!key || key == ""){
		if(this.key){
			key = this.key;	
		}else{
			this._sendError(RTYPE_ALIVE_NOTICE,RET_E_PARAM);
			return false;
		}
	}
	this.key 	= key;
	this.ip 	= ip;
	this.port 	= port;

	if(ip && ip!="" && port && port != ""){
		url = "http://"+ip+":"+port+"/"
	}else{
		url = "http://"+this.mConfig["host"]+":"+this.mConfig["port"]+"/"
	}
	url = url+this.mConfig["query"]+"?opcode="+RTYPE_ALIVE_NOTICE+"&key="+key+"&nfid="+this.id;
	url += "&js=yes";
	tdate = new Date();
	url += "&"+tdate.getTime();

	this._sendRequest(url);
	return true;

}

NetFunnel.TsClient.prototype.aliveNotice = function(key,ip,port,first){
	// 0. 실행중인지 여부 확인
	if(TS_BYPASS == true) { this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success}); return true; }
	if ( this._mStatus == PS_RUNNING || this._mStatus == PS_CONTINUE ) {
		this._sendError(RTYPE_ALIVE_NOTICE,RET_E_ARUNNING);
		return false;
	}
	return this.aliveNoticeProc(key,ip.port,first);
}

NetFunnel.TsClient.prototype.aliveNoticeCont = function(key,ip,port,first){
	// 0. 실행중인지 여부 확인
	if ( this._mStatus == PS_RUNNING ) {
		this._sendError(RTYPE_ALIVE_NOTICE,RET_E_ARUNNING);
		return false;
	}
	return this.aliveNoticeProc(key,ip,port,first);
}

/**
 * 완료 요청 명령 전송
 *   - 모든 프로세스가 종료 되었을때 호출 한다.
 *   - 완료 후 이명령을 호출하지 않으면 시스템의 가용성이 저하되며, 정확한 통계정보를 얻을 수 없다.
 *
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @memberOf NetFunnelTsClient
 * @param {String} key chkEnter를 통해 전달받은 식별자
 * @param {String} ip TS서버 IP 정보
 * @param {Number} port TS서버 Port 정보
 * @return {null} 없음.
 */
NetFunnel.TsClient.prototype.setComplete = function(key,ip,port,first){
	if(TS_BYPASS == true) { this.fireEvent(null,this,'onSuccess',{rtype:this._mReqType,code:RET_NORMAL,data:{},next:this.next.success}); return true; }

	if(first == 'undefined'){ first = true; }
	if(first){ this.counter[RTYPE_SET_COMPLETE]=0; }

	// 0. 실행중인지 여부 확인
	if ( this._mStatus == PS_RUNNING ) {
		this._sendError(RTYPE_SET_COMPLETE,RET_E_ARUNNING);
		return false;
	}

	// 1. 초기화
	if(!this._connInit(RTYPE_SET_COMPLETE)){
		this._sendError(RTYPE_SET_COMPLETE,RET_E_NOINIT);
		return false;
	}

	if(!key || key == ""){
		if(this.key){
			key = this.key;	
		}else{
			this._sendError(RTYPE_SET_COMPLETE,RET_E_PARAM);
			return false;
		}
	}
	this.key 	= key;
	this.ip 	= ip;
	this.port 	= port;

	if(ip && ip!="" && port && port != ""){
		url = "http://"+ip+":"+port+"/"
	}else{
		url = "http://"+this.mConfig["host"]+":"+this.mConfig["port"]+"/"
	}
	url = url+this.mConfig["query"]+"?opcode="+RTYPE_SET_COMPLETE+"&key="+key+"&nfid="+this.id;
	url += "&js=yes";
	tdate = new Date();
	url += "&"+tdate.getTime();

	this._sendRequest(url);
	return true;
}

/**
 * NetFunnel 쿠키 존재 여부
 *
 * @memberOf NetFunnelTsClient
 * @return {boolean} 쿠키존재 여부
 */
NetFunnel.TsClient.prototype.cookieExist = function()
{
	result = NetFunnel.Cookie.get(this.mConfig["cookie_id"]);
	if(result == ""){
		return false;
	}

	var retval = new NetFunnel.RetVal(result);
	key = retval.getValue("key");
	if(!key){ 
		NetFunnel.Cookie.del(this.mConfig["cookie_id"]);
		return false; 
	}
	return true;
}

/**
 * NetFunnel 구동중 여부
 *
 * @memberOf NetFunnelTsClient
 * @return {boolean} 구동중 여부
 */
NetFunnel.TsClient.prototype.isRunning = function()
{
	if ( this._mStatus == PS_RUNNING || this._mStatus == PS_CONTINUE ) {
		return true;
	}
	return false;
}



/**
 * NetFunnel Ts Utilities 
 * 	Static functions
 */
var NetFunnelTsUtil = {
	/**
	 * Event 에 의해 전달된 Data를 Debug 메세지 형태의 문자열로 만들어준다.
	 *
	 * @memberOf NetFunnelTsUtil
	 * @param {String} callback Callback Event 이름
	 * @param {Number} rtype Request Type
	 * @param {Number} code Return Code
	 * @param {Object} data Return Data
	 * @param {Boolean} is_html HTML 형태 여부
	 * @return {String} 입력값에 의해 작성된 문자열
	 */
	makeDebugMsg:function(callback,rtype,code,data,is_html)
	{
		var nl="\n";
		var space="       ";
		if(is_html == true){
			nl="<br>";
			space="&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
		}

		switch(rtype){
			case RTYPE_GET_TID: rtype_s 			= "getTicketID"; 		break;
			case RTYPE_CHK_ENTER: rtype_s 			= "chkEnter"; 			break;
			case RTYPE_ALIVE_NOTICE: rtype_s 		= "aliveNotice"; 		break;
			case RTYPE_SET_COMPLETE: rtype_s 		= "setComplete"; 		break;
			case RTYPE_GET_TID_CHK_ENTER: rtype_s 	= "getTID+ChkEnter";	break;
			case RTYPE_INIT: rtype_s 				= "Init"; 				break;
			case RTYPE_STOP: rtype_s 				= "stop"; 				break;
			default: rtype_s 						= "Unknown"; 			break;
		}

		switch(code){
			case RET_NORMAL: code_s 			= "Normal"; 			break;
			case RET_CONTINUE: code_s 			= "Continue"; 			break;
			case RET_E_SYSTEM: code_s 			= "System Error"; 		break;
			case RET_E_SECURITY: code_s 		= "Security Error"; 	break;
			case RET_E_IO: code_s 				= "I/O Error"; 			break;
			case RET_E_CONN_TIMEOUT: code_s 	= "Connection Timeout"; break;
			case RET_E_ARUNNING: code_s 		= "Already Running"; 	break;
			case RET_E_NOINIT: code_s 			= "Init Error"; 		break;
			case RET_E_INSERT: code_s 			= "Insert Error"; 		break;
			case RET_E_NOPERM: code_s 			= "No Permission"; 		break;
			case RET_E_KEY_EXPIRE: code_s 		= "Key Expire"; 		break;
			case RET_E_PARAM: code_s 			= "Parameter Error"; 	break;
			case RET_E_NOT_STARTED: code_s 		= "No service time"; 	break;
			case RET_E_NO_ACTION: code_s 		= "No action Error"; 	break;
			default: code_s 					= "Unknown Error"; 		break;
		}

		var tStr = callback+" "+nl+nl+"  - type : "+rtype_s+" ("+rtype+")"+nl+" - Code : "+code_s+" ("+code+")"+nl+" - Params"+nl;
		for (var i in data)
		{
			tStr += space+i+" ---> "+data[i]+nl;
		}
		return tStr;
	},

	/**
	 * Event 에 의해 전달된 Data를 다음 url 로 전달
	 * 
	 * @memberOf NetFunnelTsUtil
	 * @param {String} url 이동할 URL
	 * @param {Object} data Return Data
	 * @return {null}
	 */
	goNextPage:function(url,data){
		var tUrl = url;
		for(var i in data){
			tUrl += "&"+i+"="+data[i];
		}
		document.location.href = tUrl;
	},

	/**
	 * 디버그 메세지를 출력한다. ( flash 에 의해 호출 된다. )
	 *
	 * @memberOf NetFunnelTsUtil
	 * @param {String} msg 출력될 문자열
	 */
	alertDebugMsg:function(msg){
		alert(msg);
	}
}

var gtext="";
/**
 * 초기화 요청 
 *
 *  - CallBack
 *		* onSuccess   : 성공시 호출되는 함수 
 *		* onContinued : ttl 이 전달된 경우 호출되는 함수 ( 호출후에 ttl 만큼 sleep 한다. )
 *		* onError     : 에러 발생시 호출되는 함수
 *
 *
 * @param {Object|String} oFlash Flash Object에 대한 이름이나 Object 객체
 * @param {Object} oConfigs 설정정보
 * @param {Object} oCallbacks 이벤트에 대한 Callback 함수 정의
 * @return {Boolean} 객체생성 성공 여부
 */
function NetFunnel_init(oFlash,oConfigs,oCallbacks){
	try{
		if(NetFunnel.gControl){
			NetFunnel.gControl = null;
		}

		if(typeof oCallbacks == "undefined"){
			oCallbacks = NetFunnel.DefaultCallback;
		}else{
			if(!oCallbacks["onSuccess"]) { oCallbacks["onSuccess"] = NetFunnel.DefaultCallback["onSuccess"]; }
			if(!oCallbacks["onContinued"]) { oCallbacks["onContinued"] = NetFunnel.DefaultCallback["onContinued"]; }
			if(!oCallbacks["onError"]) { oCallbacks["onError"] = NetFunnel.DefaultCallback["onError"]; }
		}

		NetFunnel.gControl = new NetFunnel.TsClient(oConfigs,oCallbacks);
		return true;
	}catch(err){
		NetFunnel.gControl = null;
		gtext = err;
		return false;
	}
}

/**
 * 실행중인 명령 멈춤 전송
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @param {String|Function} next 명령 성공시 이동할 URL or 실행할 Function (Optional)
 * @return {boolean} 성공여부
 */
function NetFunnel_sendStop(next){
	try{
		if(!NetFunnel.gControl){ NetFunnel_init();  }
		NetFunnel.gControl.setNext(next);
		NetFunnel.gControl.sendStop();
		return true;
	}catch(err){
		return false;
	}
}

/**
 * TicketID 요청 명령 전송
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @param {String|Function} next 명령 성공시 이동할 URL or 실행할 Function (Optional)
 * @param {String} user_id 사용자 아이디 
 * @param {String} user_tid 사용자 ticket 아이디 
 * @return {boolean} 성공여부
 */
function NetFunnel_getTicketID(next,user_id,user_tid){
	try{
		if(!NetFunnel.gControl){ NetFunnel_init();  }

		NetFunnel.gControl.setNext(next);
		NetFunnel.gControl.getTicketID(user_id,user_tid);
		return true;
	}catch(err){
		return false;
	}
}

/**
 * 진입 요청 명령 전송
 *   - chkEnter 명령을 통해서 시스템에 진입 허가를 받은후에는 이 명령을 전송해 줘야만 현재의 
 *     client가 프로세스를 진행 하는지를 TS 서버에서 알 수 있게 된다. 반복 주기는 TS 서버에서 
 *     알려 주게 되며 flash client에서 자동으로 재전송하게 된다.
 *
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onContinued(evt,oArg.rtype,oArg.code,oArg.data) : 대기
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @param {String|Function} next 명령 성공시 이동할 URL or 실행할 Function (Optional)
 * @param {Object} data 접속 Data (Optional) 
 * @return {boolean} 성공여부
 */
function NetFunnel_chkEnter(next){
	try{
		if(!NetFunnel.gControl){ NetFunnel_init();  }

		if(typeof data != "undefined" && data.constructor == Object){
			key = data["key"];
			if(!key){ return false; }
		}else{
			// Cookie 에서 값을 가져온다.
			result = NetFunnel.Cookie.get(NetFunnel.gControl.mConfig["cookie_id"]);
			if(result == ""){
				return false;
			}

			var retval = new NetFunnel.RetVal(result);
			var key = retval.getValue("key");
            if(!key){ 
                NetFunnel.Cookie.del(NetFunnel.gControl.mConfig["cookie_id"]);
                return false; 
            }
		}

		NetFunnel.gControl.setNext(next);
		NetFunnel.gControl.chkEnter(key);

		return true;
	}catch(err){
		return false;
	}
}

/**
 * 발급요청 + 진입 요청 명령 전송
 *   - Key 발급요청과 chkEnter 요청을 동시에 수행한다.
 *   - chkEnter 명령을 통해서 시스템에 진입 허가를 받은후에는 이 명령을 전송해 줘야만 현재의 
 *     client가 프로세스를 진행 하는지를 TS 서버에서 알 수 있게 된다. 반복 주기는 TS 서버에서 
 *     알려 주게 되며 client에서 자동으로 재전송하게 된다.
 *
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onContinued(evt,oArg.rtype,oArg.code,oArg.data) : 대기
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @param {String|Function} next 명령 성공시 이동할 URL or 실행할 Function (Optional)
 * @param {String} user_id 사용자 아이디 
 * @param {String} user_tid 사용자 ticket 아이디 
 * @return {boolean} 성공여부
 */
function NetFunnel_getTidChkEnter(next,user_id,user_tid){
	try{
		if(!NetFunnel.gControl){ NetFunnel_init();  }

		NetFunnel.gControl.setNext(next);
		NetFunnel.gControl.getTidChkEnter(user_id,user_tid);
		return true;
	}catch(err){
		return false;
	}
}


/**
 * Alive Notice 요청 명령 전송
 *   - Event
 *     - onContinued(evt,oArg.rtype,oArg.code,oArg.data) : 대기
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @param {String|Function} next 명령 성공시 이동할 URL or 실행할 Function (Optional)
 * @param {Object} data 접속 Data (Optional) 
 * @return {boolean} 성공여부
 */
function NetFunnel_aliveNotice(next,data){
	try{
		if(!NetFunnel.gControl){ NetFunnel_init();  }


		if(typeof data != "undefined" && data.constructor == Object){
			key = data["key"];
			if(!key){ return false; }
			ip = data["ip"];
			port = data["port"];
		}else{
			// Cookie 에서 값을 가져온다.
			result = NetFunnel.Cookie.get(NetFunnel.gControl.mConfig["cookie_id"]);
			if(result == ""){
				return false;
			}

			var retval = new NetFunnel.RetVal(result);
			key = retval.getValue("key");
            if(!key){ 
                NetFunnel.Cookie.del(NetFunnel.gControl.mConfig["cookie_id"]);
                return false; 
            }
			ip = retval.getValue("ip");
			port = retval.getValue("port");
		}

		NetFunnel.gControl.setNext(next);
		NetFunnel.gControl.aliveNotice(key,ip,port);
		return true;
	}catch(err){
		return false;
	}
}

/**
 * 완료 요청 명령 전송
 *   - 모든 프로세스가 종료 되었을때 호출 한다.
 *   - 완료 후 이명령을 호출하지 않으면 시스템의 가용성이 저하되며, 정확한 통계정보를 얻을 수 없다.
 *
 *   - Event
 *     - onSuccess(evt,oArg.rtype,oArg.code,oArg.data) : 성공시
 *     - onError(evt,oArg.rtype,oArg.code,oArg.data) : 실패시
 *
 * @param {String|Function} next 명령 성공시 이동할 URL or 실행할 Function (Optional)
 * @param {Object} data 접속 Data (Optional) 
 * @return {boolean} 성공여부
 */
function NetFunnel_setComplete(next,data){
	try{
		if(!NetFunnel.gControl){ NetFunnel_init();  }

		if(typeof data != "undefined" && data.constructor == Object){
			key = data["key"];
			if(!key){ return false; }
			ip = data["ip"];
			port = data["port"];
		}else{
			// Cookie 에서 값을 가져온다.
			result = NetFunnel.Cookie.get(NetFunnel.gControl.mConfig["cookie_id"]);
			if(result == ""){
				return false;
			}

			var retval = new NetFunnel.RetVal(result);
			key = retval.getValue("key");
			if(!key){ 
				NetFunnel.Cookie.del(NetFunnel.gControl.mConfig["cookie_id"]);
				return false; 
			}
			ip = retval.getValue("ip");
			port = retval.getValue("port");
		}

		NetFunnel.gControl.setNext(next);
		NetFunnel.gControl.setComplete(key,ip,port);
		return true;
	}catch(err){
		return false;
	}
}

/**
 * NetFunnel 쿠키 존재 여부
 *
 * @return {boolean} 쿠키존재 여부
 */
function NetFunnel_cookieExist(){
	if(!NetFunnel.gControl){ return false }
	return NetFunnel.gControl.cookieExist();
}

/**
 * NetFunnel 구동중 여부
 *
 * @return {boolean} 구동중 여부
 */
function NetFunnel_isRunning(){
	if(!NetFunnel.gControl){ return false; }
	return NetFunnel.gControl.isRunning();
}
