#include <stdio.h>
#include <windows.h>
#include <vector>
#include "readpak.h"
#include "gui_things.h"

// Simplified version of http://msdn2.microsoft.com/en-us/library/ms680582(VS.85).aspx
void DisplayError(HWND hDlg, TCHAR *errorMessage)
{
	LPVOID lpMsgBuf;
	DWORD error;

	error = GetLastError();

	MessageBox(hDlg, errorMessage, NULL, MB_OK | MB_ICONERROR);

	FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR) &lpMsgBuf, 0, NULL);

	MessageBox(hDlg, (LPCTSTR) lpMsgBuf, NULL, MB_OK | MB_ICONERROR);

	LocalFree(lpMsgBuf);
}

// Request file name (Maybe it should be divided?)
BOOL RequestPakName(HWND hDlg, PAKReturn *pakInfo, DWORD nameType)
{
	OPENFILENAME openPak;
	HANDLE openFile;
	TCHAR *stringName;

	if (nameType == NAME_PAK)
		stringName = pakInfo->pakFileName;
	else if (nameType == NAME_PAB)
		stringName = pakInfo->pabFileName;

	stringName[0] = '\0';
	openPak.lStructSize = sizeof(OPENFILENAME);
	openPak.hwndOwner = hDlg;
	openPak.hInstance = NULL;
	if (nameType == NAME_PAK)
		openPak.lpstrFilter = "Neversoft PAK-PS2 (PAK.PS2)\0*.pak.ps2;\0Neversoft PAK-NGC (PAK.NGC)\0*.pak.ngc;\0Neversoft PAK-XEN (PAK.XEN)\0*.pak.xen\0All PAK-PS2 files\0*.*\0All PAK-NGC files\0*.*\0All PAK-XEN files\0*.*\0\0";
	else if (nameType == NAME_PAB)
		openPak.lpstrFilter = "Neversoft PAB (PAB)\0*.pab.*\0All files\0*.*\0\0";

	openPak.lpstrCustomFilter = NULL;
	openPak.nMaxCustFilter = 0;
	openPak.nFilterIndex = 1;
	openPak.lpstrFile = stringName;

	openPak.nMaxFile = DEFAULT_BUFFER;
	openPak.lpstrFileTitle = NULL;
	openPak.nMaxFileTitle = 0;
	openPak.lpstrInitialDir = NULL;
	openPak.lpstrTitle = "Open file";
	openPak.Flags = 0;
	openPak.nFileOffset = 0;
	openPak.nFileExtension = 0;
	if (nameType == NAME_PAK)
		openPak.lpstrDefExt = "pak";
	else if (nameType == NAME_PAB)
		openPak.lpstrDefExt = "pab";

	openPak.lCustData = 0;
	openPak.lpfnHook = NULL;
	openPak.lpTemplateName = 0;

	if (GetOpenFileName(&openPak) == FALSE)
		return FALSE;

	// Big endian switch
	if (nameType == NAME_PAK && (openPak.nFilterIndex == 1 || openPak.nFilterIndex == 4))
		pakInfo->isBigEndian = FALSE;
	else if (nameType == NAME_PAK && (openPak.nFilterIndex == 2 || openPak.nFilterIndex == 3 || openPak.nFilterIndex == 5 || openPak.nFilterIndex == 6))
		pakInfo->isBigEndian = TRUE;

	// Platform switch
	if (nameType == NAME_PAK && (openPak.nFilterIndex == 1 || openPak.nFilterIndex == 4))
		pakInfo->platform = PLAT_PS2;
	else if (nameType == NAME_PAK && (openPak.nFilterIndex == 2 || openPak.nFilterIndex == 5))
		pakInfo->platform = PLAT_NGC;
	else if (nameType == NAME_PAK && (openPak.nFilterIndex == 3 || openPak.nFilterIndex == 6))
		pakInfo->platform = PLAT_XEN;

	openFile = CreateFile(stringName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

	if (openFile == INVALID_HANDLE_VALUE)
	{
		DisplayError(hDlg, "Can't open the specified file!");
		return FALSE;
	}

	if (nameType == NAME_PAK)
		pakInfo->pakFile = openFile;
	else if (nameType == NAME_PAB)
		pakInfo->pabFile = openFile;

	return TRUE;
}

void EndianSwap(LPDWORD x)
{
    *x = (*x>>24) | ((*x<<8) & 0x00FF0000) | ((*x>>8) & 0x0000FF00) | (*x<<24);
}

// Clone of ReadFile for big endian
BOOL WINAPI ReadFileBe(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead, LPOVERLAPPED lpOverlapped, BOOL isBigEndian)
{
	BOOL returnCode;

	returnCode = ReadFile(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);

	if (isBigEndian == TRUE && *lpNumberOfBytesRead == 4)
		EndianSwap((LPDWORD) lpBuffer);


	return returnCode;
}

BOOL WINAPI WriteFileBe(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, LPOVERLAPPED lpOverlapped, BOOL isBigEndian)
{
	BOOL returnCode;

	if (isBigEndian == TRUE && nNumberOfBytesToWrite == 4)
		EndianSwap((LPDWORD) lpBuffer);

	returnCode = WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);

	if (isBigEndian == TRUE && nNumberOfBytesToWrite == 4)
		EndianSwap((LPDWORD) lpBuffer);

	return returnCode;
}