#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "win32.h"
#include "unzip.h"
#include "misc.h"

#define SPI_GETFOREGROUNDLOCKTIMEOUT  0x2000
#define SPI_SETFOREGROUNDLOCKTIMEOUT  0x2001

static HICON FormatICOInMemoryToHICON(PBYTE ptrBuffer, UINT nBufferSize);

typedef struct
{
    BYTE    bWidth;               /* Width of the image */
    BYTE    bHeight;              /* Height of the image (times 2) */
    BYTE    bColorCount;          /* Number of colors in image (0 if >=8bpp) */
    BYTE    bReserved;            /* Reserved */
    WORD    wPlanes;              /* Color Planes */
    WORD    wBitCount;            /* Bits per pixel */
    DWORD   dwBytesInRes;         /* how many bytes in this resource? */
    DWORD   dwImageOffset;        /* where in the file is this image */
} ICONDIRENTRY, *LPICONDIRENTRY;

typedef struct
{
    UINT            Width, Height, Colors; /* Width, Height and bpp */
    LPBYTE          lpBits;                /* ptr to DIB bits */
    DWORD           dwNumBytes;            /* how many bytes? */
    LPBITMAPINFO    lpbi;                  /* ptr to header */
    LPBYTE          lpXOR;                 /* ptr to XOR image bits */
    LPBYTE          lpAND;                 /* ptr to AND image bits */
} ICONIMAGE, *LPICONIMAGE;


BOOL bErrorMsgBox = TRUE;


void __cdecl ErrorMsg(const char *fmt, ...)
{
    static FILE*    pFile = NULL;
    DWORD           dwWritten;
    char            buf[5000];
    va_list         va;

    va_start(va, fmt);

#ifdef BUILD_CONSOLE
    printf(fmt, va);
#else
    if (bErrorMsgBox == TRUE)
    {
        wvsprintf(buf, fmt, va);
        MessageBox(GetActiveWindow(), buf, MAME32App.m_Name, MB_OK | MB_ICONERROR);
    }
#endif

    lstrcpy(buf, MAME32App.m_Name);
    lstrcat(buf, ": ");

    wvsprintf(&buf[lstrlen(buf)], fmt, va);
    lstrcat(buf, "\n");

    OutputDebugString(buf);

    WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), buf, strlen(buf), &dwWritten, NULL);

    if (pFile == NULL)
        pFile = fopen("debug.txt", "wt");
    if (pFile != NULL)
        fprintf(pFile, buf);

    va_end(va);
}

UINT GetDepth(HWND hWnd)
{
    UINT    nBPP;
    HDC     hDC;

    hDC = GetDC(hWnd);
    
    nBPP = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);

    ReleaseDC(hWnd, hDC);

    return nBPP;
}

BOOL OnNT(void)
{
    OSVERSIONINFO version_info;

    version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&version_info);

    if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
        return TRUE;
    else
        return FALSE;
}

BOOL OnWin95(void)
{
    OSVERSIONINFO version_info;

    version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&version_info);

    if ((version_info.dwPlatformId == VER_PLATFORM_WIN32_NT)
    ||  (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && version_info.dwMajorVersion >= 0x410))
    {
        return FALSE;
    }
    else
    {
        return TRUE;
    }
}

void SetAbsoluteForegroundWindow(HWND hWnd)
{
    int nTargetID, nForegroundID;
    OSVERSIONINFO version_info;

    version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    GetVersionEx(&version_info);

    nForegroundID = GetWindowThreadProcessId(GetForegroundWindow(), NULL);
    nTargetID = GetWindowThreadProcessId(hWnd, NULL);

    AttachThreadInput(nTargetID, nForegroundID, TRUE);

    if ((version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 5)
    ||  (version_info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && version_info.dwMajorVersion >= 0x410))
    {
        DWORD sp_time;

        SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT, 0, &sp_time, 0);
        SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT, 0, (LPVOID)0, 0);
    }

    SetForegroundWindow(hWnd);
    AttachThreadInput(nTargetID, nForegroundID, FALSE);
}


char *ModifyThe(const char *str)
{
    static int bufno = 0;
    static char buffer[4][255];

    if (strncmp(str, "The ", 4) == 0)
    {
        char *s, *p;
        char temp[255];

        strcpy(temp, &str[4]);

        bufno = (bufno + 1) % 4;

        s = buffer[bufno];

        /* Check for version notes in parens */
        p = strchr(temp, '(');
        if (p)
        {
            p[-1] = '\0';
        }

        strcpy(s, temp);
        strcat(s, ", The");

        if (p)
        {
            strcat(s, " ");
            strcat(s, p);
        }

        return s;
    }
    return (char *)str;
}


HICON LoadIconFromFile(char *iconname)
{
    HICON         hIcon = 0;
    struct stat   file_stat;
    char          tmpStr[MAX_PATH];
    char          tmpIcoName[MAX_PATH];
    const char    *sDirName = GetIconDir();
    unsigned char *bufferPtr;
    unsigned int  bufferLen;
    HINSTANCE     hInst = GetModuleHandle(NULL);

    sprintf(tmpStr, "%s/%s.ico", sDirName, iconname);
    if (stat(tmpStr, &file_stat) != 0
    || (hIcon = ExtractIcon(hInst, tmpStr, 0)) == 0)
    {
        sprintf(tmpStr, "%s/icons.zip", sDirName);
        if (stat(tmpStr, &file_stat) == 0)
        {
            sprintf(tmpIcoName, "%s.ico", iconname);
            if (load_zipped_file(tmpStr, tmpIcoName, &bufferPtr, &bufferLen) == 0)
            {
                hIcon = FormatICOInMemoryToHICON(bufferPtr, bufferLen);
                free(bufferPtr);
            }
        }
    }
    return hIcon;
}


static HICON FormatICOInMemoryToHICON(PBYTE ptrBuffer, UINT nBufferSize)
{
    ICONIMAGE      IconImage;
    LPICONDIRENTRY lpIDE = NULL;
    int            nNumImages;
    int            nBufferIndex = 0;
    HICON          hIcon = NULL;

    if (nBufferSize < sizeof(WORD))
        return NULL;

    if ((WORD)(ptrBuffer[nBufferIndex]) != 0)
        return NULL;

    nBufferIndex += sizeof(WORD);

    if (nBufferSize - nBufferIndex < sizeof(WORD))
        return NULL;

    if ((WORD)(ptrBuffer[nBufferIndex]) != 1)
        return NULL;

    nBufferIndex += sizeof(WORD);

    if (nBufferSize - nBufferIndex < sizeof(WORD))
        return NULL;

    nNumImages = (WORD)(ptrBuffer[nBufferIndex]);

    if (nNumImages < 1)
        return NULL;

    nBufferIndex += sizeof(WORD);

    if ((nBufferIndex + nNumImages * sizeof(ICONDIRENTRY)) > nBufferSize)
        return NULL;

    lpIDE = (LPICONDIRENTRY)(&ptrBuffer[nBufferIndex]);
    nBufferIndex += nNumImages * sizeof(ICONDIRENTRY);

    IconImage.dwNumBytes = lpIDE->dwBytesInRes;

    if (lpIDE->dwImageOffset > nBufferSize)
        return NULL;

    nBufferIndex = lpIDE->dwImageOffset;

    if ((nBufferIndex + lpIDE->dwBytesInRes) > nBufferSize)
        return NULL;

    IconImage.lpBits = &ptrBuffer[nBufferIndex];
    nBufferIndex += lpIDE->dwBytesInRes;

    hIcon = CreateIconFromResourceEx(IconImage.lpBits,
                                     IconImage.dwNumBytes,
                                     TRUE,
                                     0x00030000,
                                     (*(LPBITMAPINFOHEADER)(IconImage.lpBits)).biWidth,
                                     (*(LPBITMAPINFOHEADER)(IconImage.lpBits)).biHeight / 2,
                                     0);

    if (hIcon == NULL)
        if (((LPBITMAPINFO)IconImage.lpBits)->bmiHeader.biBitCount != 16)
            hIcon = CreateIconFromResource(IconImage.lpBits, IconImage.dwNumBytes, TRUE, 0x00030000);

    return hIcon;
}
