// EVM
// ÀÌº¥Æ® Ã³¸®¸¦ ´ã´çÇÑ´Ù.

function EVMDelegator( /*function*/ _fn )
{
	try
	{
		this.fn = _fn;
	}
	catch( e ) 
	{
		Debug.print ( " EVMDelegator " );
	}
}


function __EVM()
{
// public:

	// ÀÌº¥Æ®Å¸ÀÔ »ó¼ö Á¤ÀÇ
	this.k_nEventType_immediately = 0;		// ÆûÀÓ. »ç¿ëÇÒ ÀÏÀº ¾øÀ½. ( µð¹ö±ë¿ë, Å×½ºÆÃ¿ë Á¦¿Ü )
	this.k_nEventType_onPageStart = 1;
	this.k_nEventType_onPageEnd = 2;
	this.k_nEventType_onLoad = 3;
	this.k_nEventType_onUnload = 4;
	this.k_nEventType_onSubmit = 5;


	this.k_nEventType_onNXPMInitialized = 6;

	this.k_nEventType_onLoginReply = 9;
	this.k_nEventType_onLoginReplyOK = 10;
	this.k_nEventType_onConnectionClosed = 11;
	this.k_nEventType_onInitialized = 12;
	this.k_nEventType_onFriendListChanged = 13;
	this.k_nEventType_onFriendInfoChanged = 14;
	this.k_nEventType_onUserInfoChanged = 15;
	this.k_nEventType_onServerMessage = 16;
	this.k_nEventType_onCustomNotifyAll_Reload = 17;
	this.k_nEventType_onRefresh_Avatar = 18;
	this.k_nEventType_onRefresh_Nickname = 19;
	this.k_nEventType_onNoteReceived = 20;
	this.k_nEventType_onChatStarted = 21;
	this.k_nEventType_onChatReceived = 22;
	this.k_nEventType_onRefreshNoteBox = 23;
	this.k_nEventType_onFindFriend = 24;
	this.k_nEventType_onAddFriendConfirm = 25;
	this.k_nEventType_onChatMemberChanged = 26;
	this.k_nEventType_onFileUploadSession = 27;
	this.k_nEventType_onFileDownloadSession = 28;
	this.k_nEventType_onFileEvent = 29;

	this.k_nEventType_onChatRoomStarted = 30;
	this.k_nEventType_onChatRoomInfoChanged = 31;
	this.k_nEventType_onChatRoomMemberChanged = 32;
	this.k_nEventType_onChatRoomMessageReceived	= 33;
	this.k_nEventType_onChatRoomCreateFailed = 34;
	this.k_nEventType_onChatRoomClosed = 35;
	this.k_nEventType_onChatRoomRegistered = 36;

	this.k_nEventType_onRefresh_Config = 37;

	this.k_nEventType_onFirstLoad	= 38;

	this.k_nEventType_onMsg_Init = 39;
	this.k_nEventType_onMsg_Connected = 40;
	this.k_nEventType_onMsg_Disconnnected = 41;
	this.k_nEventType_onMsg_Message = 42;
	this.k_nEventType_onMsg_Error = 43;
	this.k_nEventType_NotifyLogoutVirtual = 44;
	
	this.k_nEventType_GuildOnlineInfoChanged = 45;
	this.k_nEventType_GuildChatMessage = 46;
	
	this.k_nEventType_NotifyDetach = 47;
	this.k_nEventType_onDefaultChatRoomStarted = 48;


	// Priority »ó¼ö Á¤ÀÇ
	this.k_nPriority_noUse = 0;
	this.k_nPriority_low = 1;
	this.k_nPriority_normal = 2;
	this.k_nPriority_high = 3;
	this.k_nPriority_critical = 4;

	// Interface
	this.addHandler = EVM_addHandler;		// ¸»±×´ë·Î ÀÌº¥Æ® ÇÚµé·¯. ÀÌº¥Æ®°¡ ¹ß»ýÇÒ¶§¸¶´Ù ½ÇÇàµÈ´Ù.
	this.addCommand = EVM_addCommand;		// ÇØ´ç ÀÌº¥Æ®°¡ ¹ß»ýÇßÀ»¶§ 1¹ø ½ÇÇàµÇ¸ç, ÀÌº¥Æ®°¡ ÀÌ¹Ì ¹ß»ýÇß´Ù¸é Áï½Ã ½ÇÇàµÈ´Ù.
	this.pauseEventHandling = EVM_pauseEventHandling;		// ÀÌº¥Æ® ÇÚµé¸µÀÌ Àá½Ã ÁßÁöµÈ´Ù. ( Command µµ ¸¶Âù°¡ÁöÀÌ´Ù. ) resume ½Ã ´Ù½Ã ¸ðµÎ Ã³¸®µÈ´Ù.
	this.resumeEventHandling = EVM_resumeEventHandling;		// pause µÈ ÀÌº¥Æ® ÇÚµé¸µÀ» Àç°³ÇÑ´Ù.
	this.cancelEventHandling = EVM_cancelEventHandling;		// ÀÌº¥Æ® ÇÚµé¸µÀ» Ãë¼ÒÇÑ´Ù. ( Command µµ ¸¶Âù°¡Áö ) Ãë¼ÒÈÄ¿¡´Â this.k_nEventState_raised »óÅÂ·Î ¼¼ÆÃµÈ´Ù.

// private:
	// »ó¼ö Á¤ÀÇ
	
	
	this.k_nCount_eventType = 49;

	// ÀÌº¥Æ® »óÅÂ
	this.k_nEventState_notRaised = 1;
	this.k_nEventState_raised = 2;
	this.k_nEventState_paused = 3;
	this.k_nEventState_canceled = 4;

	// ¸â¹ö º¯¼ö
	this.arrHandler = new Array( this.k_nCount_eventType );
	this.arrCommand = new Array( this.k_nCount_eventType );
	for ( var i = 0; i < this.k_nCount_eventType; i++ )
	{
		this.arrHandler[ i ] = new Array();
		this.arrCommand[ i ] = new Array();

		this.arrHandler[ i ][ 0 ] = this.k_nEventState_notRaised;
		this.arrCommand[ i ][ 0 ] = this.k_nEventState_notRaised;
	}

	// ¸Þ¼Òµå
	this.init = EVM_init;
	this.replaceEventHandlerHelper = EVM_replaceEventHandlerHelper;
	this.replaceEventHandler = EVM_replaceEventHandler;
	this.getEventTypeName = EVM_getEventTypeName;
	this.raiseEvent = EVM_raiseEvent;
}


// Implementaion
function EVM_addCommand( /*int*/ nEventType, /*int*/ nPriority, /*EVMDelegator*/ delegator /*, ¾Æ±Ô¸ÕÆ® ¸®½ºÆ®... */ )
{
	var nNewCommandIdx = this.arrCommand[ nEventType ].length;
	var nArgumentCount = arguments.length - 3;
	
	Debug.assert( nNewCommandIdx >= 1 && nArgumentCount >= 0 );

	if ( nEventType == this.k_nEventType_immediately || this.arrCommand[ nEventType ][ 0 ] == this.k_nEventState_raised )
	{
		try
		{
			delegator.fn( arguments[ 3 ], arguments[ 4 ], arguments[ 5 ], arguments[ 6 ], arguments[ 7 ] );
		}
		catch( e )
		{
			Debug.print( "Execution Error!!! : " + delegator.fn.toString() );
			Debug.assert( false );
		}
	}
	else
	{
		this.arrCommand[ nEventType ][ nNewCommandIdx ] = new Array( 1 + nArgumentCount );
		this.arrCommand[ nEventType ][ nNewCommandIdx ][ 0 ] = delegator;
		for ( var i = 0; i < nArgumentCount; i++ )
		{
			this.arrCommand[ nEventType ][ nNewCommandIdx ][ i + 1 ] = arguments[ i + 3 ];
		}
	}
}

function EVM_addHandler( /*int*/ nEventType, /*int*/ nPriority, /*EVMDelegator*/ delegator /*, ¾Æ±Ô¸ÕÆ® ¸®½ºÆ®... */ )
{
	var nNewHandlerIdx = this.arrHandler[ nEventType ].length;
	var nArgumentCount = arguments.length - 3;

	Debug.assert( nEventType != this.k_nEventType_immediately && nNewHandlerIdx >= 1 && nArgumentCount >= 0 );

	this.arrHandler[ nEventType ][ nNewHandlerIdx ] = new Array( 1 + nArgumentCount );
	this.arrHandler[ nEventType ][ nNewHandlerIdx ][ 0 ] = delegator;
	for ( var i = 0; i < nArgumentCount; i++ )
	{
		this.arrHandler[ nEventType ][ nNewHandlerIdx ][ i + 1 ] = arguments[ i + 3 ];
	}
}

function EVM_pauseEventHandling( /*int*/ nEventType )
{
	this.arrHandler[ nEventType ][ 0 ] = this.k_nEventState_paused;
	this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_paused;
}

// (!!!) ¾ÆÁ÷ FULL ±¸ÇöÀÌ µÇ¾î ÀÖÁö ¾Ê´Ù. ÇÊ¿äÇÒ¶§ FULL ±¸ÇöÇÑ´Ù.
function EVM_resumeEventHandling( /*int*/ nEventType )
{
	this.arrHandler[ nEventType ][ 0 ] = this.k_nEventState_raised;
	this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_raised;

	this.raiseEvent( nEventType );
}

function EVM_cancelEventHandling( /*int*/ nEventType )
{
	this.arrHandler[ nEventType ][ 0 ] = this.k_nEventState_canceled;

	this.arrCommand[ nEventType ] = new Array();
	this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_canceled;
}



function EVM_init()
{
}

function EVM_replaceEventHandlerHelper( /*function*/ fnEventHandler, /*string*/ strPreJavascriptCode, /*string*/ strPostJavascriptCode )
{
	var strEventHandlerJavascriptCode = "";
	if ( fnEventHandler )
	{
		strEventHandlerJavascriptCode = fnEventHandler.toString();
		strEventHandlerJavascriptCode = strEventHandlerJavascriptCode.slice( strEventHandlerJavascriptCode.indexOf( "{" ) + 1, -1 );
	}
	
	return new Function( strPreJavascriptCode + strEventHandlerJavascriptCode + strPostJavascriptCode );
}

function EVM_replaceEventHandler()
{
	// this.k_nEventType_immediately : addCommand() ¿¡¼­ Áï½Ã ÇØ´çÇÏ´Â raiseEvent() È£Ãâ
	// this.k_nEventType_onPageEnd : frk_body.js ¸¶Áö¸· ºÎºÐ¿¡¼­ ÇØ´çÇÏ´Â raiseEvent() È£Ãâ
	
	// this.k_nEventType_onLoad
	document.body.onload = this.replaceEventHandlerHelper( document.body.onload, "", "return EVM.raiseEvent( EVM.k_nEventType_onLoad, null );" );

	// this.k_nEventType_onUnload
	document.body.onunload = this.replaceEventHandlerHelper( document.body.onunload, "", "return EVM.raiseEvent( EVM.k_nEventType_onUnload, null );" );
	
	// this.k_nEventType_onSubmit
	// (!!!) NX Framework Only
	if ( document.NX != null )
		document.NX.onsubmit = this.replaceEventHandlerHelper( document.NX.onsubmit, "", "return EVM.raiseEvent( EVM.k_nEventType_onSubmit, null );" );
}

function EVM_getEventTypeName( nEventType )
{
	var strResult = "(undefined)";

	switch ( nEventType )
	{
	case this.k_nEventType_immediately: strResult = "k_nEventType_immediately"; break;
	case this.k_nEventType_onPageStart: strResult = "k_nEventType_onPageStart"; break;
	case this.k_nEventType_onPageEnd: strResult = "k_nEventType_onPageEnd"; break;
	case this.k_nEventType_onLoad: strResult = "k_nEventType_onLoad"; break;
	case this.k_nEventType_onUnload: strResult = "k_nEventType_onUnload"; break;
	case this.k_nEventType_onSubmit: strResult = "k_nEventType_onSubmit"; break;

	case this.k_nEventType_onNXPMInitialized: strResult = "k_nEventType_onNXPMInitialized"; break;

	case this.k_nEventType_onLoginReplyOK: strResult = "k_nEventType_onLoginReplyOK"; break;
	case this.k_nEventType_onLoginReply: strResult = "k_nEventType_onLoginReply"; break;
	case this.k_nEventType_onConnectionClosed: strResult = "k_nEventType_onConnectionClosed"; break;
	case this.k_nEventType_onInitialized: strResult = "k_nEventType_onInitialized"; break;
	case this.k_nEventType_onFriendListChanged: strResult = "k_nEventType_onFriendListChanged"; break;
	case this.k_nEventType_onFriendInfoChanged: strResult = "k_nEventType_onFriendInfoChanged"; break;
	case this.k_nEventType_onUserInfoChanged: strResult = "k_nEventType_onUserInfoChanged"; break;
	case this.k_nEventType_onServerMessage: strResult = "k_nEventType_onServerMessage"; break;
	case this.k_nEventType_onCustomNotifyAll_Reload: strResult = "k_nEventType_onCustomNotifyAll_Reload"; break;
	case this.k_nEventType_onRefresh_Avatar: strResult = "k_nEventType_onRefresh_Avatar"; break;
	case this.k_nEventType_onRefresh_Nickname: strResult = "k_nEventType_onRefresh_Nickname"; break;
	case this.k_nEventType_onRefresh_Config: strResult = "k_nEventType_onRefresh_Config"; break;
	case this.k_nEventType_onNoteReceived: strResult = "k_nEventType_onNoteReceived"; break;
	case this.k_nEventType_onChatStarted: strResult = "k_nEventType_onChatStarted"; break;
	case this.k_nEventType_onChatReceived: strResult = "k_nEventType_onChatReceived"; break;
	case this.k_nEventType_onRefreshNoteBox: strResult = "k_nEventType_onRefreshNoteBox"; break;
	case this.k_nEventType_onFindFriend: strResult = "k_nEventType_onFindFriend"; break;
	case this.k_nEventType_onAddFriendConfirm: strResult = "k_nEventType_onAddFriendConfirm"; break;
	case this.k_nEventType_onChatMemberChanged: strResult = "k_nEventType_onChatMemberChanged"; break;
	case this.k_nEventType_onFileUploadSession: strResult = "k_nEventType_onFileUploadSession"; break;
	case this.k_nEventType_onFileDownloadSession: strResult = "k_nEventType_onFileDownloadSession"; break;
	case this.k_nEventType_onFileEvent: strResult = "k_nEventType_onFileEvent"; break;
	
	case this.k_nEventType_onFirstLoad: strResult = "k_nEventType_onFirstLoad"; break;
	
	case this.k_nEventType_onChatRoomStarted: strResult = "k_nEventType_onChatRoomStarted"; break;
	case this.k_nEventType_onChatRoomInfoChanged: strResult = "k_nEventType_onChatRoomInfoChanged"; break;
	case this.k_nEventType_onChatRoomMemberChanged: strResult = "k_nEventType_onChatRoomMemberChanged"; break;
	case this.k_nEventType_onChatRoomMessageReceived: strResult = "k_nEventType_onChatRoomMessageReceived"; break;
	case this.k_nEventType_onChatRoomCreateFailed: strResult = "k_nEventType_onChatRoomCreateFailed"; break;
	case this.k_nEventType_onChatRoomClosed: strResult = "k_nEventType_onChatRoomClosed"; break;
	case this.k_nEventType_onChatRoomRegistered: strResult = "k_nEventType_onChatRoomRegistered"; break;

	case this.k_nEventType_onMsg_Init: strResult = "k_nEventType_onMsg_Init"; break;
	case this.k_nEventType_onMsg_Connected: strResult = "k_nEventType_onMsg_Connected"; break;
	case this.k_nEventType_onMsg_Disconnnected: strResult = "k_nEventType_onMsg_Disconnnected"; break;
	case this.k_nEventType_onMsg_Message: strResult = "k_nEventType_onMsg_Message"; break;
	case this.k_nEventType_onMsg_Error: strResult = "k_nEventType_onMsg_Error"; break;
	case this.k_nEventType_NotifyLogoutVirtual: strResult = "k_nEventType_NotifyLogoutVirtual"; break;
	case this.k_nEventType_GuildOnlineInfoChanged: strResult = "k_nEventType_GuildOnlineInfoChanged"; break;
	case this.k_nEventType_GuildChatMessage: strResult = "k_nEventType_GuildChatMessage"; break;
	case this.k_nEventType_NotifyDetach: strResult = "k_nEventType_NotifyDetach"; break;
	case this.k_nEventType_onDefaultChatRoomStarted: strResult = "k_nEventType_onDefaultChatRoomStarted"; break;

	}

	return strResult;
}


var g_lockEVM = false;
function EVM_raiseEvent( /*int*/ nEventType, /*object*/ eventArg )
{
	if ( g_lockEVM )
	{
		if( eventArg != null || isNaN( eventArg ) )
			setTimeout( "EVM.raiseEvent(" + nEventType + ", '" + eventArg + "')", 100 );
		else
			setTimeout( "EVM.raiseEvent(" + nEventType + ", " + eventArg + ")", 100 );
		return;
	}
	g_lockEVM = true;
//	Debug.print( EVM.getEventTypeName( nEventType ) );
	Debug.print( EVM.getEventTypeName( nEventType ) );

	
	// Handler ½ÇÇà : Command º¸´Ù ¸ÕÀú ½ÇÇàµÈ´Ù.
	for ( var i = 1; i < this.arrHandler[ nEventType ].length; i++ )
	{
		if ( this.arrHandler[ nEventType ][ 0 ] == this.k_nEventState_paused || this.arrHandler[ nEventType ][ 0 ] == this.k_nEventState_canceled )
			break;
		var itemHandler = this.arrHandler[ nEventType ][ i ];
		try
		{
			itemHandler[ 0 ].fn( eventArg, itemHandler[ 1 ], itemHandler[ 2 ], itemHandler[ 3 ], itemHandler[ 4 ], itemHandler[ 5 ] ) ;
		}
		catch( e )
		{
			Debug.print( "Execution Error!!!( Handler ) : " + itemHandler[ 0 ].fn.toString() );
			Debug.assert( false );
			result = false;
			break;
		}
	}

	var result = null;
	if ( this.arrHandler[ nEventType ][ 0 ] == this.k_nEventState_canceled )
	{
		result = false;
		this.arrHandler[ nEventType ][ 0 ] = this.k_nEventState_raised;
		this.arrCommand[ nEventType ] = new Array();
		this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_raised;
	}
	else if ( this.arrHandler[ nEventType ][ 0 ] == this.k_nEventState_paused )
	{
		result = false;
		this.arrHandler[ nEventType ][ 0 ] = this.k_nEventState_paused;
		this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_paused;
	}
	else
	{
		result = true;
		this.arrHandler[ nEventType ][ 0 ] = this.k_nEventState_raised;
		this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_raised;
	}

	// Command ½ÇÇà
	if ( result )
	{
		for ( var i = 1; i < this.arrCommand[ nEventType ].length; i++ )
		{
			var itemCommand = this.arrCommand[ nEventType ][ i ];
			try
			{
				itemCommand[ 0 ].fn( itemCommand[ 1 ], itemCommand[ 2 ], itemCommand[ 3 ], itemCommand[ 4 ], itemCommand[ 5 ] );
			}
			catch( e )
			{
				Debug.print( "Execution Error!!!( Command ) : " + itemCommand[ 0 ].fn.toString() );
				Debug.assert( false );
				result = false;
				break;
			}
		}

		this.arrCommand[ nEventType ] = new Array();
		this.arrCommand[ nEventType ][ 0 ] = this.k_nEventState_raised;
	}

	g_lockEVM = false;
	return result;
}


// Singleton object »ý¼º
var EVM = new __EVM();
EVM.init();
