#include "stdafx.h"
#include "PatcherDlg.h"

#include "Patcher.h"
#include "skin/SkinResource.h"


BEGIN_MESSAGE_MAP( cPatcherDlg, cSkinDialog )
	ON_WM_CREATE()
	ON_WM_DESTROY()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_CTLCOLOR()
	ON_BN_CLICKED( CID_OK, OnOkButton )
	ON_BN_CLICKED( CID_CLOSE, OnCloseButton )
	ON_BN_CLICKED( CID_HOME, OnHomeButton )
	ON_BN_CLICKED( CID_JOIN, OnJoinButton )
	ON_MESSAGE(WM_USER_MESSAGE, OnUserMessage)
END_MESSAGE_MAP()


cPatcher* cPatcherDlg::mPatcher = 0;

cPatcherDlg::cPatcherDlg( const cString& path, const cString& hostName, const cString& baseDir, const cString& cmdLine, CWnd* parent )
: cSkinDialog( parent )
, mPath( path )
, mHostName( hostName )
, mBaseDir( baseDir )
, mCmdLine( cmdLine )
, mThread( 0 )
{
	mIcon = AfxGetApp()->LoadIcon( IDI_PATCHER_ICON );

	mBoardView = 0;

	mStatus = PATCH_SEARCHING;
}

cPatcherDlg::~cPatcherDlg()
{
	if( mPatcher )
	{
		delete mPatcher;
		mPatcher = 0;
	}
}



int cPatcherDlg::OnCreate( LPCREATESTRUCT lpCreateStruct )
{
	lpCreateStruct->style |= WS_CLIPCHILDREN;

	if( cSkinDialog::OnCreate( lpCreateStruct ) == -1 )
		return -1;
	
	/// 윈도우 타이틀
	SetWindowText( "IrisPatcher" );

	/// Url 정보 로딩
	if( LoadUrl() == false )
	{
		MessageBox( "Failed to load url info", PATCHER );
		return -1;
	}

	/// 게임 실행 버튼
	mStartButton.Create( mResource->GetChild( "start" ), this, CID_OK );
	mStartButton.EnableWindow( 0 );

	/// 종료 버튼
	mCloseButton.Create( mResource->GetChild( "close" ), this, CID_CLOSE );

	/// 홈페이지 버튼
	mHomeButton.Create( mResource->GetChild( "home" ), this, CID_HOME );

	/// 회원가입 버튼
	mJoinButton.Create( mResource->GetChild( "join" ), this, CID_JOIN );

	/// 진행바
	mProgressBar.Create( mResource->GetChild( "probar" ), this, CID_PROGRESS );
	mProgressBar.SetValue( 0.0f );

	/// 게시물 뷰
	mBoardView = new cSkinHtmlView;
	mBoardView->Create( mResource->GetChild( "board" ), this, CID_BOARD );
	mBoardView->Go();

	RECT rc;
	rc.left = 21;
	rc.right = 128;
	rc.top = 394;
	rc.bottom = 408;

	mStatusStatic.Create( "", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, rc, this,  CID_STATUS );
	mStatusStatic.SetFont( &mFont );

	return 0;
}


BOOL cPatcherDlg::OnInitDialog()
{
	cSkinDialog::OnInitDialog();

	/// 아이콘을 설정
	SetIcon( mIcon, 1 );
	SetIcon( mIcon, 0 );

	/// 스레드를 시작
	mPatcher = new cPatcher( this );
	mPatcher->Init( GetSafeHwnd(), AfxGetInstanceHandle());
	BeginThread();

	return 1;
}

void cPatcherDlg::OnDestroy()
{
	/// 임시 패치 파일을 삭제
	//::FileRemove( PATCH_Z_FILENAME );


	// 공지 사항 뷰
	if( mBoardView )
	{
		mBoardView->DestroyWindow();
	}

	cSkinDialog::OnDestroy();
}

void cPatcherDlg::OnPaint()
{
	if( IsIconic() )
	{
		CPaintDC dc( this );

		SendMessage( WM_ICONERASEBKGND, reinterpret_cast<WPARAM>( dc.GetSafeHdc() ), 0 );

		/// 아이콘 드로잉
		int cxIcon = GetSystemMetrics( SM_CXICON );
		int cyIcon = GetSystemMetrics( SM_CYICON );
		CRect rect;
		GetClientRect( &rect );
		int x = ( rect.Width() - cxIcon + 1 ) / 2;
		int y = ( rect.Height() - cyIcon + 1 ) / 2;

		dc.DrawIcon( x, y, mIcon );
	}
	else
	{
		cSkinDialog::OnPaint();
	}
}

HCURSOR cPatcherDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>( mIcon );
}

void cPatcherDlg::OnOK()
{
	static bool first = true;

	if( first == false )
		return;
	else
		first = false;

	if( mStartButton.IsWindowEnabled() )
	{
		// 옵션 저장
		//SaveOptInfo();

		// 게임 실행
		RunGame();
		EndDialog( 0 );
		//cSkinDialog::OnOK();
	}
}

void cPatcherDlg::OnCancel()
{
	if( mThread )
	{
		DWORD ret = ::SuspendThread( mThread );
		assert( ret >= 0 );
		assert( mPatcher );

		mPatcher->StopWorking();
        ::ResumeThread( mThread );
		
		::Sleep( 0 );
		/// IO 작업이 끝날 때 까지 기다린다.
        while( mPatcher->IsEndIO() != true )
		{
			::Sleep( 0 );
			/// wait for IO END...
		}

		/// 스레드가 종료될 때까지 대기
		if( ::WaitForSingleObject( mThread, 5000 ) != WAIT_OBJECT_0 )
		{
			DWORD exitCode;
			::GetExitCodeThread( mThread, &exitCode );
			if ( exitCode == STILL_ACTIVE )
			{
				::TerminateThread( mThread, 0 );
			}
		}

		::CloseHandle( mThread );
		mThread = 0;
	}

	//if( mPatchStep == eSTEP_PATCH_COMPLETED )
	{
		cSkinDialog::OnCancel();
	}
}

void cPatcherDlg::OnOkButton()
{
	OnOK();
}

void cPatcherDlg::OnCloseButton()
{
	OnCancel();
}

void cPatcherDlg::OnHomeButton()
{
	ShellExecute( 0, 0, "Iexplore.exe", mUrlArray[URL_HOME].Cstr(), 0, SW_SHOWNORMAL );
}


void cPatcherDlg::OnJoinButton()
{
	ShellExecute( 0, 0, "Iexplore.exe", mUrlArray[URL_JOIN].Cstr(), 0, SW_SHOWNORMAL );
}

void cPatcherDlg::BeginThread()
{
	/// 이미 작업중인 스레드가 있는지를 검사
	if( mThread != 0 )
	{
		MessageBox( "Thread is working.", PATCHER );
		return;
	}

	/// 스레드를 생성
	DWORD threadId;
	mThread = ::CreateThread( 0, 0, ThreadProc, 0, 0, &threadId );

	if( mThread == 0 )
	{
		MessageBox( "Failed to create thread.", PATCHER );
		return;
	}
}

void cPatcherDlg::EndThread( bool result, bool updateSelf )
{
	if( updateSelf )
	{
		/// 런처를 실행하여 패처 자신을 패치
		RunLauncher();
		EndDialog( 0 );

//		MessageBox( "런처파일이 업데이트 되었습니다. 다시 실행 하여 주십시오.", PATCHER );
//		RunLauncher();
//		EndDialog( 0 );

		return;
	}

	if( result )
	{
		/// 게임 실행 준비
		mStartButton.EnableWindow( 1 );
		mProgressBar.SetValue( 1.0f );
		mProgressBar.Invalidate( 0 );

		mStatus = PATCH_COMPLETE;
	}

}

DWORD cPatcherDlg::ThreadProc( LPVOID /*param*/ )
{
	assert( mPatcher );
	return mPatcher->ThreadProc();
}

bool cPatcherDlg::LoadUrl()
{
	cString fileName = mPath;
	fileName += URLINFO_FILENAME;

	cFileLoader loader;
	if( loader.Open( fileName, true ) == false )
	{
		return false;
	}

	char temp[256];

	for( int i = 0; i < URL_COUNT; ++i )
	{
		if( loader.ReadLine( temp, 256 ) == 0 )
		{
			break;
		}
		mUrlArray[i] = temp;
	}
	return true;
}

bool cPatcherDlg::RunLauncher()
{
	//*
	STARTUPINFO	si;

	::memset( &si, 0, sizeof(STARTUPINFO) );
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_SHOW;

	PROCESS_INFORMATION pi;

	BOOL ret = ::CreateProcess( LAUNCHER_FILENAME,
		"-updatePatcher",
		0,
		0,
		0,
		CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS,
		0,
		0,
		&si,
		&pi );

	if(ret == 0)
	{
		//MessageBox( "Failed to run launcher", PATCHER );
		return false;
	}

	::CloseHandle( pi.hProcess );
	::CloseHandle( pi.hThread );
	return true;
	//*/

	/*
	int ret = (int)::ShellExecute( 0, "open", LAUNCHER_FILENAME, "-updatePatcher", 0, SW_HIDE );

	if( ret <= 32 )
		return false;
	else
		return true;
	*/
}

bool cPatcherDlg::RunGame()
{
	/*
	STARTUPINFO	si;

	memset( &si, 0, sizeof(STARTUPINFO) );
	si.cb = sizeof(STARTUPINFO);
	si.dwFlags = STARTF_USEPOSITION | STARTF_USESIZE | STARTF_USESTDHANDLES;
	si.wShowWindow = SW_SHOW;

	PROCESS_INFORMATION pi;

	BOOL ret = CreateProcess( GAMEEXE_FILENAME,
		"abc?",
		0,
		0,
		0,
		CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS,
		0,
		0,
		&si,
		&pi );

	if( ret == 0 )
	{
		MessageBox( "Failed to run game", PATCHER );
		return false;
	}

	CloseHandle( pi.hProcess );
	CloseHandle( pi.hThread );
	*/

	cString path;
	path.Format( ".\\%s", GAMEEXE_FILENAME );
	int ret = (int)::ShellExecute( 0, "open", path.Cstr(), CMD_LINE, 0, SW_SHOWNORMAL );

	if( ret <= 32 )
	{
		MessageBox( "Failed to run game", PATCHER );
		return false;
	}
	return true;
}

void cPatcherDlg::SetProgressMax( ePatchStatus status, int max )
{
	mProgressTotalNum = max;
	mProgressBar.SetValue( 0.f );
	mProgressBar.Invalidate( 0 );

	SetStatus( status );
}

void cPatcherDlg::SetProgressPos( const char* /*fileName*/, int pos )
{
	float r = float(pos) / float(mProgressTotalNum);

	mProgressBar.SetValue( r );
	mProgressBar.Invalidate( 0 );

	SetStatus( PATCH_PATCHING );
}

void cPatcherDlg::SetStatus( ePatchStatus status )
{
	mStatus = status;

	cString out;
	switch( mStatus )
	{
	case PATCH_SEARCHING:
		out = mResource->GetText( 0 );
		break;
	case PATCH_PATCHING:
		{
			unsigned int v = unsigned int(mProgressBar.GetValue() * 100.0f);
			out.Format( mResource->GetText(1).Cstr(), v);
		}
		break;
	case PATCH_COMPLETE:
		out = mResource->GetText( 2 );
		break;
	}

	mStatusStatic.SetWindowText( out.Cstr() );

	RECT rc;
	rc.left = 21;
	rc.right = 128;
	rc.top = 394;
	rc.bottom = 408;
	InvalidateRect( &rc, 0 );
}

HBRUSH cPatcherDlg::OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor )
{
	HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

	switch(nCtlColor)
	{
	case CTLCOLOR_STATIC:
		{
			pDC->SetTextColor(RGB(255, 255, 255));
			pDC->SetBkMode(TRANSPARENT);
			return hbr;
		}
	}
	return hbr;
}

LRESULT cPatcherDlg::OnUserMessage(WPARAM wParam, LPARAM lParam)
{
	if(mPatcher->IsWorking() == false)
		return 1;

	switch( wParam )
	{
	case _UMT_ERROR_INIT_ : 
		MessageBox("Init Error!", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_SAVE_ : 
		MessageBox("Fail to save file!", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_DOWNLOAD_:
		MessageBox("Fail to connect to patch server.", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_PARSE_:
		MessageBox("Fail to parse server patch list file.", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_MEMORY_ALLOC_:
		MessageBox( "Fail to allocation memory", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_MEMORY_FREE_:
		MessageBox( "Fail to free memory", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_UPDATE_:
		MessageBox( "Fail to Update", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_SEARCH_:
		MessageBox( "Fail to Search", PATCHER, MB_OK );
		break;
	case _UMT_ERROR_CREATE_FOLDER_:
		MessageBox( "Fail to Create Folder", PATCHER, MB_OK );
		break;
	
	default : 
		MessageBox("Wrong Message");
		break;
	}

	PostMessage( WM_CLOSE, 0, 0 );

// 	LPVOID lpMsgBuf;
// 	FormatMessage( 
// 		FORMAT_MESSAGE_ALLOCATE_BUFFER|
// 		FORMAT_MESSAGE_FROM_SYSTEM,
// 		NULL, (DWORD)lParam,
// 		MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// 		(LPSTR)&lpMsgBuf, 0, NULL);
// 	MessageBox( (LPCSTR)lpMsgBuf, msg, MB_ICONERROR);
// 	LocalFree(lpMsgBuf);


	return 1;
}
