#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wsqllib.h>
#include <winlib/winlib.h>

#include "sqlbase.h"
#include "dbinit.h"
#include "dbroutes.h"
#include "dbutil.h"
#include "sqlcmd.h"


static void CreateChildren(VARS *v, HWND hwndParent)
{
       CHARFORMAT cf;
       PARAFORMAT pf;
       HFONT hfnt = GetStockObject(ANSI_FIXED_FONT);

       memset(&cf, 0, sizeof(CHARFORMAT));
       cf.cbSize = sizeof(CHARFORMAT);
       cf.dwMask = CFM_FACE | CFM_SIZE | CFM_BOLD;
       cf.dwEffects = 0;
       cf.yHeight = 8 * 20;
       strcpy(cf.szFaceName, "Andale Mono");

       memset(&pf, 0, sizeof(PARAFORMAT));
       pf.cbSize = sizeof(PARAFORMAT);
       pf.dwMask = PFM_STARTINDENT;
       pf.dxStartIndent = 50;

       v->hwndSQLResText = CreateWindow(
               "RichEdit20A", NULL,
               WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE |
               ES_MULTILINE | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
               0, 0, 0, 0,
               hwndParent, NULL, v->hInst, NULL);

       SendMessage(v->hwndSQLResText, EM_SETCHARFORMAT, SCF_ALL,
                       (LPARAM)&cf);
       SendMessage(v->hwndSQLResText, EM_SETPARAFORMAT,
               (WPARAM)0, (LPARAM)&pf);
}


LRESULT CALLBACK SQLResWndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
       WORD id, wScrollNotify;
       RECT rect;
       static VARS *v;

       switch (msg) {
               case WM_CREATE:
                       v = (VARS*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
                       return 0;

               case WM_SIZE:
                       GetClientRect(hwnd, &rect);
                       MoveWindow(v->hwndSQLResText, 0, 0, rect.right,
                                       rect.bottom, TRUE);
                       return 0;

               case WM_COMMAND:
                       id = LOWORD(wParam);
                       switch (id) {
                               case ID_SB_PAGEUP:
                               case ID_SB_PAGEDOWN:
                               case ID_SB_TOP:
                               case ID_SB_BOTTOM:
                                       switch (id) {
                                       case ID_SB_PAGEUP:
                                       wScrollNotify = SB_PAGEUP;
                                               break;
                                       case ID_SB_PAGEDOWN:
                                       wScrollNotify = SB_PAGEDOWN;
                                       break;
                               case ID_SB_TOP:
                                       wScrollNotify = SB_TOP;
                                                       break;
                                               case ID_SB_BOTTOM:
                                                       wScrollNotify = SB_BOTTOM;
                                       break;
                       }
                                       SendMessage(v->hwndSQLResText, WM_VSCROLL,
                                       MAKELONG(wScrollNotify, 0), 0L);
               }
               return 0;

               case WM_CLOSE:
                       SavePlacement(hwnd, "Software\\SQLBase\\SQLCmd");
                       DestroyWindow(hwnd);
                       return 0;

               case WM_DESTROY:
                       PostQuitMessage(0);
                       return 0;
       }

       return DefWindowProc(hwnd, msg, wParam, lParam);
}


static BOOL ShowResultWnd(VARS *v)
{
       WNDCLASS wc;
       RECT rect;
       int x = CW_USEDEFAULT, y = 0, w = CW_USEDEFAULT, h = 0;

       if (! v->sqlResWndReg) {
               wc.style = CS_HREDRAW | CS_VREDRAW;
               wc.lpfnWndProc = (WNDPROC)SQLResWndProc;
               wc.cbClsExtra = 0;
               wc.cbWndExtra = 0;
               wc.hInstance = v->hInst;
               wc.hIcon = LoadIcon(v->hInst, "Icon");
               wc.hCursor = LoadCursor(NULL, IDC_ARROW);
               wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
               wc.lpszMenuName = (HMENU)NULL;
               wc.lpszClassName = "sqlResWndClass";
               if (! RegisterClass(&wc))
                       return FALSE;
               v->sqlResWndReg = TRUE;
       }

       if (GetPlacement("Software\\SQLBase\\SQLCmd", &rect)) {
               x = rect.left;
               y = rect.top;
               w = rect.right - rect.left;
               h = rect.bottom - rect.top;
       }

       v->hwndSQLResWnd = CreateWindow(
               "sqlResWndClass", "SQL Results",
               WS_OVERLAPPEDWINDOW,
               x, y, w, h,
               NULL, NULL, v->hInst, (LPVOID)v);

       CreateChildren(v, v->hwndSQLResWnd);

       ShowWindow(v->hwndSQLResWnd, SW_SHOWDEFAULT);
       UpdateWindow(v->hwndSQLResWnd);
       SetForegroundWindow(v->hwndSQLResWnd);
       return TRUE;
}


BOOL AddText(char **result, char *s, int *bytes)
{
       int len;

       len = strlen(s);
       if (! (*result = realloc(*result, (*bytes) + len))) {
               MessageBox(NULL, "Realloc failed", "SQLBase",
                               MB_OK | MB_ICONERROR | MB_SETFOREGROUND);
               return FALSE;
       }
       memcpy((*result) + (*bytes), s, len);
       *bytes += len;
       return TRUE;
}


void SQLCmd(void *arg)
{
       MYSQL_ROW row;
       MYSQL_FIELD *field[100], *fld;
       int i, j, r, nf, fw;
       char fmt[30];
       int bytes;
       MSG msg;
       char *result;
       VARS *v = (VARS*)arg;

       v->sqlCmdActive = TRUE;

       ShowStatus(v->hwndStatus, 0, "Processing...");

       r = SQLQuery(0, v->sqlCmd);
       if ((! r) || (r == 2))
               goto end;

       fw = nf = 0;
       while (fld = SQLFetchField(0)) {
               if (strlen(fld->name) > fw)
                       fw = strlen(fld->name);
               field[nf++] = fld;
       }

       sprintf(fmt, "%%-%ds: %%s\r\n", fw + 2);

       result = (char*)malloc(1);
       bytes = 0;

       i = 0;
       while ((row = SQLFetchRow(0))) {
               if (i) {
                       if (! AddText(&result, "\r\n", &bytes))
                               goto endQuery;
               }
               sprintf(v->buf, "[%d] ------------------------------------------------------------\r\n\r\n",
                               (i++) + 1);
               if (! AddText(&result, v->buf, &bytes))
                       goto endQuery;
               for (j = 0; j < nf; j++) {
                       sprintf(v->buf, fmt, field[j]->name, row[j] ? row[j] : "");
                       if (! AddText(&result, v->buf, &bytes))
                               goto endQuery;
               }
       }

       if (! (result = realloc(result, bytes + 1)))
               goto endQuery;
       *(result + bytes) = '\0';

       if (! bytes) {
               ShowStatus(v->hwndStatus, 0, "No rows found");
               goto endQuery;
       }

       if (! ShowResultWnd(v))
               goto endQuery;

       ShowStatus(v->hwndStatus, 0, "");
       SetWindowText(v->hwndSQLResText, result);
       SetFocus(v->hwndSQLResText);

       while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
   }

endQuery:
       SQLEndQuery(0);
       free(result);
       goto end2;
end:
       ShowStatus(v->hwndStatus, 0, "");
end2:
       v->sqlCmdActive = FALSE;
}