// PatchApplyDlg.cpp : implementation file
//


#include "stdafx.h"
#include "PatchApply.h"
#include "PatchApplyDlg.h"

#include "patchwin.h"

#define PATCHFILE "mw4.rtp"

extern bool EnglishErrors;

#define LNG_ENGLISH		0x0409
#define LNG_FRENCH		0x040C
#define LNG_GERMAN		0x0407
#define LNG_KOREAN		0x0412
#define LNG_SPANISH		0x0C0A
#define LNG_CHINESE		0x0404

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
void PatchApply(const char *);
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();
	
	// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA
	
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL
	
	// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPatchApplyDlg dialog
CPatchApplyDlg *g_DlgPtr;

CPatchApplyDlg::CPatchApplyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CPatchApplyDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CPatchApplyDlg)
	m_StatText = _T("");
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	g_DlgPtr=this;
	InSetup=false;
	IsEnglish=false;
	Patching=false;
	ErrorProcessed=false;

}

void CPatchApplyDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CPatchApplyDlg)
	DDX_Control(pDX, IDC_FILEPROG, m_FileProg);
	DDX_Control(pDX, IDC_EXIT, m_But);
	DDX_Control(pDX, IDC_PATCHPROG, m_PatchProg);
	DDX_Text(pDX, IDC_STATTEXT, m_StatText);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CPatchApplyDlg, CDialog)
//{{AFX_MSG_MAP(CPatchApplyDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_EXIT, OnExit)
ON_WM_CLOSE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPatchApplyDlg message handlers

BOOL CPatchApplyDlg::OnInitDialog()
{
	CDialog::OnInitDialog();
	
	// Add "About..." menu item to system menu.
	
	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);
	
	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}
	
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	SetWindowText(GetTransString(IDS_ENG_WINTITLE));
	m_But.SetWindowText(GetTransString(IDS_ENG_EXIT));
	
	IsEnglish=false;
	Patching=false;
	m_PatchProg.SetRange(0,100);
	m_PatchProg.SetPos(0);
	m_FileProg.SetPos(0);
	
	ErrorProcessed=false;
	
	CRect deskrect,rect;
	
	
	SystemParametersInfo(SPI_GETWORKAREA, NULL, (LPVOID) &deskrect, false);
	GetWindowRect(rect);
	SetWindowPos(NULL,deskrect.CenterPoint().x-rect.Width()/2,
		deskrect.CenterPoint().y-rect.Height()/2,-1,-1,SWP_NOZORDER|SWP_NOSIZE);
	
	
	ShowWindow(SW_SHOW);
	
	
	if(InSetup|| (MessageBox(GetTransString(IDS_ENG_PTTIT),GetTransString(IDS_ENG_PTMSG),MB_OKCANCEL)==IDOK))
	{
		ApplyPatch();
	}
	else
		PostQuitMessage(0);
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CPatchApplyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CPatchApplyDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting
		
		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
		
		// Center icon in client rectangle
		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;
		
		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CPatchApplyDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

struct LANGANDCODEPAGE {
	WORD wLanguage;
	WORD wCodePage;
} ;

LPVOID CALLBACK CallBack( UINT Id, LPVOID Parm)
{
	return g_DlgPtr->PatchCallBack(Id,Parm);
	//MessageBox(NULL,(LPCSTR)Parm,"RTPatch",MB_OK);
	return NULL;
}


void CPatchApplyDlg::ApplyPatch()
{
	Patching=true;
	m_But.EnableWindow(FALSE);
	
	HKEY pathkey;
	if(ERROR_SUCCESS !=RegOpenKey(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Microsoft Games\\MechWarrior Vengeance",&pathkey))
	{
		FatalError(IDS_ENG_REGERROR);	
		
		return;
	}
	
	DWORD ktype;
	DWORD size=	MAX_PATH;
	char dbuf[MAX_PATH];
	if(ERROR_SUCCESS !=RegQueryValueEx(pathkey,"EXE Path",NULL,&ktype,(BYTE *)dbuf,&size) || size<=0 || ktype!=REG_SZ) 
	{
		FatalError(IDS_ENG_REGERROR);	
		
		return;
	}
	
	RegCloseKey(pathkey);
	
	CString game_path(dbuf);
	CString file_path;
	
	
	m_StatText=GetTransString(IDS_ENG_PTLSF);	UpdateData(FALSE);
	
	
	file_path=game_path+"\\MissionLang.dll";
	
	
	DWORD bufsize=GetFileVersionInfoSize((char *)(LPCSTR)file_path,NULL);
	if(!bufsize) 
	{
		FatalError(IDS_ENG_REGERROR);
		return;
	}
	
	BYTE *pBlock=new BYTE[bufsize];
	GetFileVersionInfo((char *)(LPCSTR)file_path,NULL,bufsize,pBlock);
	
	void *lpBuffer;
	UINT dwBytes;
	
	
	
	// Read the list of languages and code pages.
	UINT cbTranslate;
	LANGANDCODEPAGE *lpTranslate;
	VerQueryValue(pBlock, 
		TEXT("\\VarFileInfo\\Translation"),
		(LPVOID*)&lpTranslate,
		&cbTranslate);
	
	// Read the file description for each language and code page.
	char SubBlock[512];
	
	
	wsprintf( SubBlock, 
		TEXT("\\StringFileInfo\\%04x%04x\\FileDescription"),
		lpTranslate->wLanguage,
		lpTranslate->wCodePage);
	
	// Retrieve file description for language and code page "i". 
	VerQueryValue(pBlock, 
		SubBlock, 
		&lpBuffer, 
		&dwBytes); 
	
	CString source_dir;
	
	switch(lpTranslate->wLanguage)
	{
	case LNG_ENGLISH:	source_dir="English"; break;
	case LNG_FRENCH:	source_dir="French"; break;
	case LNG_GERMAN:	source_dir="German"; break;
	case LNG_KOREAN:	source_dir="Korean"; break;
	case LNG_SPANISH:	source_dir="Spanish"; break;
	case LNG_CHINESE:	source_dir="Taiwan"; break;
	default:
		FatalError(IDS_ENG_UDL);
	}
	
	//copy or patch files from sourcedir here;
	
	//	CopyFile(source_dir+"\\missionlang.dll",game_path+"\\missionlang.dll",NULL);
	//	CopyFile(source_dir+"\\ScriptStrings.dll",game_path+"\\ScriptStrings.dll",NULL);
	
	
	delete pBlock;
	

	char tstr[MAX_PATH];
	CString old_cwd;
	GetCurrentDirectory(MAX_PATH,tstr);
	old_cwd=tstr;
	source_dir=old_cwd+"\\"+source_dir;
	SetCurrentDirectory(game_path);

	m_StatText=GetTransString(IDS_ENG_PGF);		UpdateData(FALSE);
	//Apply Pros/exe Patch here
	CString cmdline;
	WIN32_FIND_DATA finddat;
	cmdline.Format("\"%s\" \"%s\\mw4\"",game_path,source_dir);

	
	if(INVALID_HANDLE_VALUE==FindFirstFile(source_dir+"\\"+PATCHFILE,&finddat))
	{
		if(InSetup && lpTranslate->wLanguage!=LNG_ENGLISH)
		{
			FatalError(IDS_LANGMISSING);
		}
		else
			FatalError(IDS_ENG_PATCHERROR);
		
		SetCurrentDirectory(tstr);
		return;
	}
	
	UINT res=RTPatchApply32((char *)(LPCSTR)cmdline,CallBack,0);
	if(res) 
	{
		FatalError(IDS_ENG_PATCHERROR);
		SetCurrentDirectory(tstr);
		return;
	}

	SetCurrentDirectory(tstr);

	/*
	HKEY verkey;
	if(ERROR_SUCCESS !=RegOpenKey(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Microsoft Games\\MechWarrior Vengeance",&verkey))
	{	FatalError(IDS_ENG_REGERROR);	return ; }
	
	  if(ERROR_SUCCESS !=RegSetValueEx(verkey,"Version",NULL,REG_SZ,(BYTE *)"4.0a",strlen("4.0a")+1)) 
	  {		FatalError(IDS_ENG_REGERROR);	return; }
	  
		RegCloseKey(verkey);
	*/
		m_PatchProg.SetPos(100);
		m_StatText=GetTransString(IDS_ENG_OPCOM);	UpdateData(FALSE);
	
	m_But.EnableWindow(TRUE);
	DisplayReadMe();

	Patching=false;
	OnOK();
}

bool CPatchApplyDlg::NeedUpgrade()
{
	bool ret=false;
	char str[256];
	DWORD len=256;
	DWORD type=REG_SZ;


	HKEY verkey;
	if(ERROR_SUCCESS !=RegOpenKey(HKEY_LOCAL_MACHINE,"SOFTWARE\\Microsoft\\Microsoft Games\\MechWarrior Vengeance",&verkey))
	{	ret=true; }
	else
		if(ERROR_SUCCESS !=RegQueryValueEx(verkey,"Version",NULL,&type,(BYTE *)str,&len)) 
		{	ret=true; }
		else
		{
			if(len<=0 || strcmp(str,"4.0c")<0) ret=true;
			else ret=false;
		}
		RegCloseKey(verkey);
		
		
		return ret;
}


static LPCSTR LoadStringEx(UINT id)
{
	if(!EnglishErrors)
	{
		LANGID lid=GetSystemDefaultLangID();
		HRSRC hres = FindResourceEx(NULL, RT_STRING, MAKEINTRESOURCE((id >> 4) + 1), lid);
		if (hres) {
			HGLOBAL hmem = LoadResource(NULL, hres);
			if (hmem) {
				LPWSTR pwz = (LPWSTR)LockResource(hmem);
				for (UINT u = id & 15; u > 0; u--)
					pwz += *pwz + 1;
				if (!*pwz)
					return NULL;
				static char szMultiByte[1024];
				int iRc = WideCharToMultiByte(CP_ACP, 0, pwz + 1, *pwz, szMultiByte, sizeof(szMultiByte), NULL, NULL);
				szMultiByte[iRc] = 0;
				return szMultiByte;
			}
		}
		DWORD dwErr = GetLastError();
	}
	CString str;
	str.LoadString(id);
	return str;
}

CString CPatchApplyDlg::GetTransString(UINT  id)
{
	CString str;
#if 0
	UINT baseid;
	LCID lid=GetSystemDefaultLCID();
	
	switch(lid)
	{
	case LNG_FRENCH:	baseid=IDS_FRN_TABLESTART; break;
	case LNG_GERMAN:	baseid=IDS_GER_TABLESTART; break;
	case LNG_KOREAN:	baseid=IDS_KOR_TABLESTART; break;
	case LNG_SPANISH:	baseid=IDS_SPN_TABLESTART; break;
	case LNG_CHINESE:	baseid=IDS_TAI_TABLESTART; break;
	default:
	case LNG_ENGLISH:	baseid=IDS_ENG_TABLESTART; IsEnglish=true; break;
		
	}
	str.LoadString((id-IDS_ENG_TABLESTART)+baseid);
#endif
	str = LoadStringEx(id);
#if 0
	LCID lcid = GetThreadLocale();
	char szString[1024];
	int iRc = ::LoadString(AfxGetInstanceHandle(), id, szString, sizeof(szString));
	if (iRc)
		str = szString;
#endif
	return str;
}

void CPatchApplyDlg::FatalError(UINT id)
{
	if(!ErrorProcessed)
			MessageBox(GetTransString(id)+"\n"+GetTransString(IDS_ENG_UCP),GetTransString(IDS_ENG_ERROR),MB_OK|MB_ICONERROR); 
	PostQuitMessage(0);
}

bool CPatchApplyDlg::DoesFileExist(LPCSTR fname)
{
	return 0xffffffff!=GetFileAttributes( fname );
}


bool CPatchApplyDlg::DisplayReadMe()
{
	CString readmefile;
	readmefile.LoadString(IDS_READMEFNAME);
	if(DoesFileExist( readmefile ))
	{
		SHELLEXECUTEINFO info;
		ZeroMemory(&info,sizeof(info));
		info.cbSize=sizeof(info);
		info.lpVerb="open";
		info.lpFile=readmefile;
		info.nShow=SW_SHOWNORMAL;
		info.fMask=SEE_MASK_NOCLOSEPROCESS;
		ShellExecuteEx(&info);
		
		DWORD eflag;
		do
		{		
			if(GetExitCodeProcess(info.hProcess,&eflag)==0) return true;
		}
		while(eflag==STILL_ACTIVE);
		
		return true;
	}
	return false;
}

void CPatchApplyDlg::OnExit() 
{
	OnOK();	
}

#define MAX_MESSAGES 10
LPVOID CPatchApplyDlg::PatchCallBack( UINT Id, LPVOID Parm)
{
	MSG msg;
	UINT MsgCount;
	LPVOID RetVal;
	
	//  CallBackParam = Parm; 
	//  InCallBack=TRUE;	// this flag is checked by our message loop
	//  to insure that it doesn't respond to the
	//  menu and try to start one patch in the middle
	//  of another one...
	RetVal = "";
	
	// do a few messages while we're here...
	
	for ( MsgCount = MAX_MESSAGES;
	MsgCount && PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
	MsgCount--)
	{
		TranslateMessage( &msg );
		DispatchMessage( &msg );
	}
	
	
	switch( Id )
	{
    case 1:
		// Warning message header
		break;
    case 2:
		// Warning message text
		break;
    case 3:
		if(!IsEnglish)
		{
			CString errnum=(char *) Parm;
			errnum=errnum.Mid(10,4);
			MessageBox(GetTransString(IDS_ENG_SEETXT)+"\n"+errnum+"\n"+GetTransString(IDS_ENG_UCP),GetTransString(IDS_ENG_ERROR),MB_OK|MB_ICONERROR);
			ErrorProcessed=true;
			PostQuitMessage(0);
			// Error message header
		}
		break;
	case 4:
		//	Error message text
		if(IsEnglish)
		{
			CString err=(char *) Parm;
			err+=GetTransString(IDS_ENG_UCP);
			MessageBox(err,"RTP Error",MB_OK|MB_ICONERROR);
			ErrorProcessed=true;
			PostQuitMessage(0);
		}
		break;
    case 9:
		// progress message
    case 0xa:
		// help message
    case 0xb:
		// patch file comment
    case 0xc:
		// copyright message
		//      WriteIt( (char *) Parm );	// for all these callbacks, we just
		break;			//   write the associated text to the 
		//   text pane
		
		
		
    case 5:
		// % completed
		{
			int prog=(int) (((long)(0xffff & *((UINT *) Parm))*100L)/0x8000L);
			m_PatchProg.SetPos( prog);
		}
		break;
		
    case 6:
		{
			int pnum=*((UINT *) Parm);
			m_FileProg.SetRange(0,pnum);
			
		}
		
		// Number of patch files
		// PATCHGUI ignores this
		break;
		
    case 7:
		// begin patch
        {
			CString str=GetTransString(IDS_ENG_PROC);
			str+=(char *) Parm ;
			m_StatText=str;
				UpdateData(FALSE);
				m_PatchProg.SetPos(0);
		}
		break;
		
    case 8:
		{
			// end patch
			m_StatText="";
				UpdateData(FALSE);
			 m_PatchProg.SetPos(0);
			m_FileProg.SetPos(m_FileProg.GetPos()+1);
		}
		break;
		
    case 0xd:
		// this one shouldn't happen (only occurs if the command line
		//   doesn't have a patch file in it, and we insure that it does).
		break;
		
    case 0xe:
		// this one shouldn't happen either (same reason)
		break;
		
    case 0xf:
		// Password Dialog
		break;
		
    case 0x10:
		// Invalid Password Alert
		
		break;
		
    case 0x11:
		
		break;
		
    case 0x12:
		break;
		
    case 0x13:
		break;
		
    case 0x14:
		break;
		
    case 0x16:
		break;
		
    case 0x15:
		// Idle...
    default:
		break;
		
  } 
  
  // do a few more messages while we're here...
  
  for ( MsgCount = MAX_MESSAGES;
  MsgCount && PeekMessage( &msg, NULL, 0, 0, PM_REMOVE );
  MsgCount--)
  {
	  TranslateMessage( &msg );
	  DispatchMessage( &msg );
  }
  
  
  return (RetVal);
}

void CPatchApplyDlg::OnClose() 
{
	// TODO: Add your message handler code here and/or call default
	
	if(!Patching)	CDialog::OnClose();
}
