/*
 * w_dialog.c : sub windows
 *
 * Copyright (c) Yukihiko Aoki 1999-2000
 * NetHack may be freely redistributed.  See license for details.
 *
 */

#include "hack.h"

#ifdef NH2K_EXTENDS

#include "win32api.h"
#include "w_main.h"
#include "res/resource.h"

/*
 * constants
 */
#define YN_INDENT_X         50
#define YN_INDENT_Y         10
#define YN_BUTTON_CX        96
#define YN_BUTTON_CY        24

#define INPUT_NUMSHOW       50
/* 
 * use in AskWnd for yn_function
 */
typedef struct tagWINYNINFO {
    char     *query;                    /* query string */
    char     *choices;                  /* selectable characters */
    char     def;                       /* default answer */
    BOOL     ordinary;                  /* true if window has buttons */
    FONTINFO font;                      /* font information */
}WINYNINFO;

/*
 * use in InputWnd for getlin
 */
typedef struct tagWININPUTINFO {
    char    *query;                     /* query string */
    char    *answer;                    /* answer */
    int	    maxlen;                     /* max length of answer */
    BOOL    done;                       /* */
}WININPUTINFO;

/*
 * use in CmdWnd
 */
typedef struct tagWINCMDINFO {
    HBITMAP hbmp;
}WINCMDINFO;

/*
 * local functions
 */
static void FDECL(AskWnd_OnPaint, (HWND));
static void FDECL(AskWnd_OnLButtonDown, (HWND,BOOL,int,int,UINT));
static void FDECL(AskWnd_draw, (WINDESC *, HDC));
static BOOL CALLBACK FDECL(InputWndProc, (HWND,UINT,WPARAM,LPARAM));

/***************************************************************************************
 * yn_function
 ***************************************************************************************/
char AskWnd_doModal(const char *query, const char *choices, char def)
{
    WINYNINFO yn;
    char      buf[BUFSZ];
    char      ch;
    HWND      hwnd;

    ch = def;
    Font_load(&yn.font, g_propFile, "AskWnd");
    if(choices && 
        (strcmp(choices, ynchars)
        || strcmp(choices, ynqchars)
        || strcmp(choices, ynqchars)
        || strcmp(choices, ynaqchars)
        || strcmp(choices, ynNaqchars))) {
        yn.ordinary = TRUE;
    }else {
        yn.ordinary = FALSE;
    }

    if(!yn.ordinary && choices) {
        sprintf(buf, "%s[%s](%c)", query, choices, def);
        yn.query = buf;
    }else {
        yn.query = query;
    }

    yn.choices = choices;
    yn.def     = def;
    hwnd = CreateWindowEx(0, "NHASK", "", 
        WS_CHILD|WS_CLIPSIBLINGS, 
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        g_baseHwnd, (HMENU)1024, g_hInstance, (LPVOID)&yn);
    AskWnd_resize(hwnd);
    while(TRUE) {
        ch = Key_getChar();
        if(ch == 0x1b) {
            if(choices) {
                ch = strchr(choices, 'q') ? 'q' : strchr(choices,'n') ? 'n' : def;
            }else {
                ch = def;
            }
            break;
        }else if(ch == 0x20 || ch == 0x0d || ch == 0x0a) {
            ch = def;
            break;
        }else if(!choices || (choices && strchr(choices, ch))) {
            break;
        }
    }
    DestroyWindow(hwnd);
    Font_delete(&yn.font);
    NHWnd_newLayout();

    return ch;
}

/***************************************************************************************
 *
 ***************************************************************************************/
void AskWnd_resize(HWND hwnd)
{
    WINYNINFO *yn = (WINYNINFO *)GetWindowLong(hwnd, GWL_USERDATA);
    HFONT oldFont;
    RECT  rc;
    HDC   hdc;
    int   width, height;
    int   x, y;

    hdc = GetDC(hwnd);
    oldFont = SelectObject(hdc, yn->font.font_handle);

    /*
     * calculate window size
     */
    DrawText(hdc, yn->query, -1, &rc, DT_SINGLELINE|DT_CALCRECT);
    width = rc.right - rc.left;
    height = rc.bottom - rc.top;
    if(yn->ordinary) {
        height += YN_BUTTON_CY + YN_INDENT_Y;
        width = max(width, strlen(yn->choices) * YN_BUTTON_CX);
    }
    width += (YN_INDENT_X * 2);
    height += (YN_INDENT_Y * 2);
    
    /* calculate position */
    GetClientRect(g_baseHwnd, &rc);
    x = (rc.right - width) / 2;
    y = (rc.bottom - height) / 2;

    SelectObject(hdc, oldFont);
    ReleaseDC(hwnd, hdc);

    MoveWindow(hwnd, x, y, width, height, FALSE);
    BringWindowToTop(hwnd);
    ShowWindow(hwnd, SW_SHOW);
}

/*-------------------------------------------------------------------------------------
 * WM_PAINT
 *-------------------------------------------------------------------------------------*/
static void AskWnd_OnPaint(HWND hwnd)
{
    WINDESC     wd; /* dummy */

    wd.hwnd        = hwnd;
    wd.procDraw    = AskWnd_draw;
    wd.draw_memory = TRUE;
    wd.more        = FALSE;

    ValidateRect(hwnd, NULL);
    NHWnd_display(&wd);
}

/*-------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void AskWnd_draw(WINDESC *wd, HDC hdc)
{
    WINYNINFO   *yn;
    HDC         dcMem;
    HFONT       oldFont;
    RECT        rc, rcBtn;
    COLORREF    oldColor;
    int         numbutton;
    int         oldMode;
    int         indent, i, y, x;
    HBITMAP     hbmp, oldBmp;
    POINT       pt;
    HWND        hwnd;

    hwnd = wd->hwnd;
    yn = (WINYNINFO *)GetWindowLong(hwnd, GWL_USERDATA);
    GetClientRect(hwnd, &rc);
    FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH));
    oldMode = SetBkMode(hdc, TRANSPARENT);
    oldColor = SetTextColor(hdc, colormap[CLR_WHITE]);
    oldFont = SelectObject(hdc, yn->font.font_handle);
    rc.top += YN_INDENT_Y;
    rc.left += YN_INDENT_X;
    rc.right -= YN_INDENT_X;
    rc.bottom -= YN_INDENT_Y;
    DrawText(hdc, yn->query, -1, &rc, DT_SINGLELINE|DT_TOP|DT_CENTER);
    if(yn->ordinary) {

        GetCursorPos(&pt);
        ScreenToClient(hwnd, &pt);

        numbutton = strlen(yn->choices);
        indent = ((rc.right - rc.left) - (numbutton * YN_BUTTON_CX)) / 2;
        hbmp = LoadImage(g_hInstance, "YN_BMP", IMAGE_BITMAP, 0, 0, 0);
        dcMem = CreateCompatibleDC(hdc);
        oldBmp = SelectObject(dcMem, hbmp);
        for(i = 0; i < numbutton; i++) {
            rcBtn.left = YN_INDENT_X + indent + (i * YN_BUTTON_CX);
            rcBtn.top  = rc.bottom - YN_BUTTON_CY;
            rcBtn.right = rcBtn.left + YN_BUTTON_CX;
            rcBtn.bottom = rcBtn.top + YN_BUTTON_CY;
            x = PtInRect(&rcBtn, pt) ? YN_BUTTON_CX * 2 : (yn->choices[i] == yn->def) ? 0 : YN_BUTTON_CX;
            y = (yn->choices[i] == 'y') ? 0 : (yn->choices[i] == 'n') ? 1 :
                (yn->choices[i] == 'a') ? 2 : (yn->choices[i] == 'q') ? 3 :
                (yn->choices[i] == '#') ? 4 : 0;
            y *= YN_BUTTON_CY;
            BitBlt(hdc, rcBtn.left, rcBtn.top, YN_BUTTON_CX, YN_BUTTON_CY,
                dcMem, x, y, SRCCOPY);
        }
        SelectObject(dcMem, oldBmp);
        DeleteDC(dcMem);
        DeleteObject(hbmp);
    }
    SelectObject(hdc, oldFont);
    SetBkMode(hdc, oldMode);
}

/*-------------------------------------------------------------------------------------
 * WM_LBUTTONDOWN
 *-------------------------------------------------------------------------------------*/
void AskWnd_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
    WINYNINFO *yn = (WINYNINFO *)GetWindowLong(hwnd, GWL_USERDATA);
    int numbutton;
    int indent;
    int index;
    RECT rc;
    POINT pt;
    
    if(yn->ordinary) {
        GetClientRect(hwnd, &rc);
        rc.bottom -= YN_INDENT_Y;
        rc.top = rc.bottom - YN_BUTTON_CY;
        numbutton = strlen(yn->choices);
        indent = ((rc.right - rc.left) - (numbutton * YN_BUTTON_CX)) / 2;
        rc.left = indent;
        rc.right = rc.left + (numbutton * YN_BUTTON_CX);
        pt.x = x;
        pt.y = y;

        if(PtInRect(&rc, pt)) {
            index = (pt.x - rc.left) / YN_BUTTON_CX;
            Key_put(yn->choices[index]);
        }
    }
}

/***************************************************************************************
 * 
 ***************************************************************************************/
LRESULT CALLBACK AskWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    switch(msg) {
        HANDLE_MSG(hwnd, WM_CREATE,      NHWnd_OnCreate);
        HANDLE_MSG(hwnd, WM_ERASEBKGND,  NHWnd_OnEraseBkgnd);
        HANDLE_MSG(hwnd, WM_NCHITTEST,   NHWnd_OnNCHitTest);
        HANDLE_MSG(hwnd, WM_PAINT,       AskWnd_OnPaint);
        HANDLE_MSG(hwnd, WM_LBUTTONDOWN, AskWnd_OnLButtonDown);
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
}

/***************************************************************************************
 * getline
 ***************************************************************************************/
void InputWnd_doModal(const char *ques, char *input, int maxlen)
{
	WININPUTINFO wii;

	wii.query = ques;
	wii.answer = input;
	wii.maxlen = maxlen;
	wii.done = FALSE;

	/* create modal dialog */
	DialogBoxParam(
		g_hInstance,		/* instance handle */
		"INPUT_LINE",		/* window name */
		g_baseHwnd,			/* parent window */
		InputWndProc,		/* window procedure */
		(LPARAM)&wii);		/* creation parameter */
}

/*-------------------------------------------------------------------------------------
 * Input window procedure
 *-------------------------------------------------------------------------------------*/
static BOOL CALLBACK InputWndProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    static WININPUTINFO* wii;
    FONTINFO font;
	HWND hEditBox;
	HWND hStatic;
	RECT rc;
    HDC hdc;
    int width, height;

	switch(Msg)	{
    case WM_INITDIALOG:
        wii = (WININPUTINFO*)lParam;

        Font_load(&font, g_propFile, "InputWnd");
        hdc = GetDC(hDlg);
        width = Font_width(&font, hdc);
        height = Font_height(&font, hdc);
        ReleaseDC(hDlg, hdc);

	    rc.left = rc.top = 0;
	    rc.right = width * INPUT_NUMSHOW + GetSystemMetrics(SM_CXDLGFRAME) * 2;
	    rc.bottom = height * 2 + (GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) * 2);
	    SetWindowPos(hDlg, NULL, 0, 0, rc.right, rc.bottom, SWP_NOZORDER|SWP_NOMOVE);
	    NHWnd_moveCenter(hDlg, g_baseHwnd);

	    hEditBox = GetDlgItem(hDlg, EDIT_ANSWER);
	    SendMessage(hEditBox, WM_SETFONT, (WPARAM)font.font_handle, (LPARAM)0);
	    SendMessage(hEditBox, EM_SETLIMITTEXT, (WPARAM)wii->maxlen, (LPARAM)0);
	    MoveWindow(hEditBox, 0, height, width * INPUT_NUMSHOW, height, TRUE);

	    hStatic = GetDlgItem(hDlg, STATIC_QUERY);
	    SendMessage(hStatic, WM_SETFONT, (WPARAM)font.font_handle, (LPARAM)0);
	    SetWindowText(hStatic, wii->query);
	    MoveWindow(hStatic, 0, 0, width * INPUT_NUMSHOW, height, TRUE);

        SetFocus(hEditBox);
        break;
    case WM_CTLCOLOREDIT:
    case WM_CTLCOLORSTATIC:
        hdc = (HDC)wParam;
    	SetTextColor(hdc, colormap[CLR_WHITE]);
	    SetBkMode(hdc, TRANSPARENT);
	    return (BOOL)GetStockObject(BLACK_BRUSH);
    case WM_COMMAND:
	    switch(LOWORD(wParam)) {
	    case IDOK:
		    /* Get number of characters */
		    width = GetDlgItemText(hDlg, EDIT_ANSWER, wii->answer, wii->maxlen);
		    /* Get the characters */
		    if(width <= 0) {
			    strcpy(wii->answer, "\033\000");
		    }
		    EndDialog(hDlg,1);
		    break;
	    case IDCANCEL:
		    strcpy(wii->answer, "\033\000");
		    EndDialog(hDlg,1);
		    break;
        default:
            return FALSE;
	    }
        break;
	default:
		return FALSE;
	}
    return TRUE;
}

HWND CmdWnd_create()
{
    WINCMDINFO *cmd;
    HWND hwnd = NULL;
    BITMAP bm;

    cmd = (WINCMDINFO *)NEWMEMORY(sizeof(WINCMDINFO));
    if(cmd) {
        cmd->hbmp = LoadImage(g_hInstance, "CMD_BMP", IMAGE_BITMAP, 0, 0, 0);
        GetObject(cmd->hbmp, sizeof(BITMAP), &bm);
        hwnd = CreateWindowEx(
            WS_EX_TOOLWINDOW,
            "NHCMD", "NetHack Command", 
            WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_VISIBLE|WS_THICKFRAME,
            0, 0, bm.bmWidth, bm.bmHeight / 2,
            g_baseHwnd, 0, g_hInstance, (LPVOID)cmd);
    }

    return hwnd;
}

const static struct {
    int  l, t, r, b;
    char ch;
}cmdbtns[] = {
    { 0,  0,  47, 11, 0x1B },
    { 48, 0,  95, 11, 0x0D },
    { 0,  12, 23, 47, '<'  },
    { 0,  48, 23, 83, '>'  },
    { 24, 12, 47, 35, '7'  },
    { 48, 12, 71, 35, '8'  },
    { 72, 12, 95, 35, '9'  },
    { 24, 36, 47, 59, '4'  },
    { 48, 36, 71, 59, '.'  },
    { 72, 36, 95, 59, '6'  },
    { 24, 60, 47, 83, '1'  },
    { 48, 60, 71, 83, '2'  },
    { 72, 60, 95, 83, '3'  },
    { 0,  0,  0,  0,  0    }
};

/*-------------------------------------------------------------------------------------
 *
 *-------------------------------------------------------------------------------------*/
static void CmdWnd_draw(WINDESC *wd, HDC hdc)
{
    WINCMDINFO  *cmd;
    HDC         dcMem;
    RECT        rcBtn;
    int         i, y, x;
    HBITMAP     oldBmp;
    POINT       pt;
    HWND        hwnd;

    hwnd = wd->hwnd;
    cmd = (WINCMDINFO *)GetWindowLong(hwnd, GWL_USERDATA);
    GetCursorPos(&pt);
    ScreenToClient(hwnd, &pt);
    dcMem = CreateCompatibleDC(hdc);
    oldBmp = SelectObject(dcMem, cmd->hbmp);
    for(i = 0; i < cmdbtns[i].ch != 0; i++) {
        rcBtn.left = cmdbtns[i].l;
        rcBtn.top  = cmdbtns[i].t;
        rcBtn.right = cmdbtns[i].r;
        rcBtn.bottom = cmdbtns[i].b;
        x = rcBtn.left;
        y = PtInRect(&rcBtn, pt) ? rcBtn.top + 84: rcBtn.top;
        BitBlt(hdc, rcBtn.left, rcBtn.top, 
            (rcBtn.right - rcBtn.left), 
            (rcBtn.bottom - rcBtn.top),
            dcMem, x, y, SRCCOPY);
    }
    SelectObject(dcMem, oldBmp);
    DeleteDC(dcMem);
}

/*-------------------------------------------------------------------------------------
 * WM_PAINT
 *-------------------------------------------------------------------------------------*/
static void CmdWnd_OnPaint(HWND hwnd)
{
    WINDESC     wd; /* dummy */

    wd.hwnd        = hwnd;
    wd.procDraw    = CmdWnd_draw;
    wd.draw_memory = TRUE;
    wd.more        = FALSE;

    ValidateRect(hwnd, NULL);
    NHWnd_display(&wd);
}

/*-------------------------------------------------------------------------------------
 * WM_LBUTTONDOWN
 *-------------------------------------------------------------------------------------*/
void CmdWnd_OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
    int i;
    RECT rcBtn;
    POINT pt;

    pt.x = x;
    pt.y = y;
    for(i = 0; i < cmdbtns[i].ch != 0; i++) {
        rcBtn.left = cmdbtns[i].l;
        rcBtn.top  = cmdbtns[i].t;
        rcBtn.right = cmdbtns[i].r;
        rcBtn.bottom = cmdbtns[i].b;
        if(PtInRect(&rcBtn, pt)) {
            Key_put(cmdbtns[i].ch);
            break;
        }
    }

}

/***************************************************************************************
 * 
 ***************************************************************************************/
LRESULT CALLBACK CmdWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
    switch(msg) {
        HANDLE_MSG(hwnd, WM_CREATE,      NHWnd_OnCreate);
        HANDLE_MSG(hwnd, WM_ERASEBKGND,  NHWnd_OnEraseBkgnd);
        HANDLE_MSG(hwnd, WM_NCHITTEST,   NHWnd_OnNCHitTest);
        HANDLE_MSG(hwnd, WM_PAINT,       CmdWnd_OnPaint);
        HANDLE_MSG(hwnd, WM_LBUTTONDOWN, CmdWnd_OnLButtonDown);
    default:
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
}

/*-------------------------------------------------------------------------------------
 * change progress bar value
 *-------------------------------------------------------------------------------------*/
void DisplayProgress(int op, int pos)
{
    static HWND hwndProgress = NULL;

    switch(op) {
    case PROGRESS_SETHWND:
        /* force cast int to hwnd */
        hwndProgress = (HWND)pos;
        break;
    case PROGRESS_SETRANGE:
        /* set initial value */
        SendMessage(hwndProgress, PBM_SETRANGE, 0, MAKELPARAM(0, pos));
        break;
    case PROGRESS_SETPOS:
        /* set current status */
        SendMessage(hwndProgress, PBM_SETPOS, pos, 0);
        break;
    default:
        break;
    }
}

/***************************************************************************************
 * copyright dialog box procedure
 ***************************************************************************************/
BOOL CALLBACK CopyrightProc(HWND hDlg, UINT msg, UINT wParam, LONG lParam)
{
    static HBITMAP   hbmp = NULL;
    static HPALETTE  hpal = NULL;
    char             buf[BUFSZ];
    WINCONTROL      *info = NULL;
    char            *res;
    int              success = 0;
    int              idx;
    int              i = 1;

    switch (msg) {
    case WM_INITDIALOG:
        setrandom();
        idx = rnd(3);
        switch(idx) {
        case 1:  
            res = "TITLE_BMP1";
            break;
        case 2:
            res = "TITLE_BMP2";
            break;
        case 3:
            res = "TITLE_BMP3";
            break;
        default: break;
        }

        hbmp = LoadImage(g_hInstance, res, IMAGE_BITMAP, 0, 0, 0);
        hpal = CreateBitmapPalette(hbmp);
        SendDlgItemMessage(
            hDlg, STATIC_TITLE, STM_SETIMAGE, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp);
        info = (WINCONTROL *)lParam;
        while(info) {
            sprintf(buf, "%d) %s", i++, info->name);
            idx = SendDlgItemMessage(
                hDlg, LIST_CONTROL, LB_ADDSTRING, 0, (LPARAM)buf);
            SendDlgItemMessage(
                hDlg, LIST_CONTROL, LB_SETITEMDATA, (WPARAM)idx, (LPARAM)info);
            info = info->next;
        }
        SetFocus(GetDlgItem(hDlg, LIST_CONTROL));
        EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
        break;

    case WM_COMMAND:
        switch (LOWORD(wParam)) {
        case IDOK:
            idx = SendDlgItemMessage(hDlg, LIST_CONTROL, LB_GETCURSEL, 0, 0);
            if(idx != LB_ERR) {
                info = (WINCONTROL *)SendDlgItemMessage(
                    hDlg, LIST_CONTROL, LB_GETITEMDATA, idx, 0);
                DisplayProgress(PROGRESS_SETHWND, (int)GetDlgItem(hDlg, PROGRESS_LOAD));
                if(InitDisplayMode(info, DisplayProgress)) {
                    success = 1;
                }else {
                    PrintError("Failed to load bitmap!");
                }
            }
        case IDCANCEL:
            EndDialog(hDlg, success);
            if(hbmp) {
                DeleteObject(hbmp);
            }
	    if(hpal) {
		DeleteObject(hpal);
	    }
            break;
        case LIST_CONTROL:
            switch(HIWORD(wParam)) {
            case LBN_SELCHANGE:
                idx = SendDlgItemMessage(hDlg, LOWORD(wParam), LB_GETCURSEL, 0, 0);
                if(idx != LB_ERR) {
                    EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
                }
                break;
            default:
                return FALSE;
            }
            break;
        default:
            break;
        }
		break;
	default:
		return FALSE;
	}

	return TRUE;
}

#endif /* NH2K_EXTENDS */
