#include <windows.h>
#include <commctrl.h>
#include <process.h>
#include <stdio.h>
#include <wsqllib.h>
#include <winlib/winlib.h>

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



void MoveControls(VARS *v, int xPos, int yPos)
{
       int i, xStart, yStart;
       RECT rect;
       SQLFIELD *f;

       xStart = -xPos;
       yStart = -yPos;

       for (i = 0, f = v->fields; i < v->nFields;
                       i++, f = f->next) {
               MoveWindow(v->hwndLabel[i],
                       f->x + xStart, f->y + yStart + 3, f->labelWidth, 24,
                       FALSE);

               MoveWindow(v->hwndEdit[i],
                       f->x + f->labelWidth + 15 + xStart,
                       f->y + yStart, f->editWidth, 24,
                       FALSE);
       }

       (void) GetClientRect(v->hwndCont, &rect);
       InvalidateRect(v->hwndCont, &rect, TRUE);
}


void ResizeChildren(VARS *v)
{
       RECT mainRect;

       (void) GetClientRect(v->hwndMain, &mainRect);

       MoveWindow(v->hwndCont,
               0, 0, mainRect.right, mainRect.bottom - 24,
               TRUE);
}


void CreateChildren(VARS *v, HWND hwnd)
{
       int i;
       HFONT hfnt = GetStockObject(ANSI_VAR_FONT);
       SQLFIELD *f;

       v->hwndCont = CreateWindowEx(
               WS_EX_CLIENTEDGE, "ContWndClass", (LPCTSTR)NULL,
               WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL,
               0, 0, 0, 0,
               hwnd, NULL, v->hInst, (LPVOID)v);

       for (i = 0, f = v->fields; i < v->nFields;
                       i++, f = f->next) {
               v->hwndLabel[i] = CreateWindowEx(
                       0, "STATIC", (LPCTSTR)f->title,
                       WS_CHILD | WS_VISIBLE | SS_RIGHT,
                       0, 0, 0, 0,
                       v->hwndCont, NULL, v->hInst, NULL);

               SendMessage(v->hwndLabel[i], WM_SETFONT, (WPARAM)hfnt,
                               MAKELPARAM(1, 0));

               v->hwndEdit[i] = CreateWindowEx(
                       WS_EX_CLIENTEDGE, "EDIT", (LPCTSTR)NULL,
                       WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL,
                       0, 0, 0, 0,
                       v->hwndCont, NULL, v->hInst, NULL);

               SendMessage(v->hwndEdit[i], WM_SETFONT, (WPARAM)hfnt,
                               MAKELPARAM(1, 0));
       }
}


BOOL CALLBACK AboutDlgProc(HWND hDlg, UINT msg,
               WPARAM wParam, LPARAM lParam)
{
       switch (msg) {
               case WM_INITDIALOG:
                       return TRUE;

               case WM_COMMAND :
                       switch (LOWORD (wParam)) {
                               case IDOK:
                               case IDCANCEL:
                                       EndDialog (hDlg, 0);
                                       return TRUE ;
                       }
                       break;
       }
       return FALSE;
}


LRESULT CALLBACK ContWndProc(HWND hwnd, UINT msg, WPARAM wParam,
               LPARAM lParam)
{
       int iVertPos, iHorzPos;
       SCROLLINFO si;
       RECT rect;
       static VARS *v;
       HWND hwndParent;

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

               case WM_VSCROLL:
                       // Get all the vertical scroll bar information

                       si.cbSize = sizeof (si) ;
                       si.fMask  = SIF_ALL ;
                       GetScrollInfo (hwnd, SB_VERT, &si);

                       // Save the position for comparison later on

                       iVertPos = si.nPos ;

                       switch (LOWORD (wParam)) {
                               case SB_TOP:
                                       si.nPos = si.nMin;
                                       break ;

                               case SB_BOTTOM:
                                       si.nPos = si.nMax;
                                       break ;

                               case SB_LINEUP:
                                       si.nPos -= 1;
                                       break ;

                               case SB_LINEDOWN:
                                       si.nPos += 1;
                                       break ;

                               case SB_PAGEUP:
                                       si.nPos -= si.nPage;
                                       break ;

                               case SB_PAGEDOWN:
                                       si.nPos += si.nPage;
                                       break ;

                               case SB_THUMBTRACK:
                                       si.nPos = si.nTrackPos;
                                       break ;

                               default:
                                       break ;
                       }
                       // Set the position and then retrieve it.  Due to adjustments
                       // by Windows it may not be the same as the value set.

                       si.fMask = SIF_POS;
                       SetScrollInfo (v->hwndCont, SB_VERT, &si, TRUE);
                       GetScrollInfo (v->hwndCont, SB_VERT, &si);

                       // If the position has changed, scroll the window

                       if (si.nPos != iVertPos) {
                               ScrollWindow(hwnd, 0, 20 * (iVertPos - si.nPos),
                                               NULL, NULL);
                               UpdateWindow(hwnd);
                       }
                       break;

               case WM_HSCROLL:
                       // Get all the horizontal scroll bar information

                       si.cbSize = sizeof (si);
                       si.fMask  = SIF_ALL;

                       // Save the position for comparison later on

                       GetScrollInfo (hwnd, SB_HORZ, &si);
                       iHorzPos = si.nPos;

                       switch (LOWORD (wParam)) {
                               case SB_LINELEFT:
                                       si.nPos -= 1;
                                       break;

                               case SB_LINERIGHT:
                                       si.nPos += 1;
                                       break;

                               case SB_PAGELEFT:
                                       si.nPos -= si.nPage;
                                       break;

                               case SB_PAGERIGHT:
                                       si.nPos += si.nPage;
                                       break;

                               case SB_THUMBTRACK:
                                       si.nPos = si.nTrackPos;
                                       break ;

                               default:
                                       break;
                       }
                       // Set the position and then retrieve it.  Due to adjustments
                       // by Windows it may not be the same as the value set

                       si.fMask = SIF_POS;
                       SetScrollInfo (hwnd, SB_HORZ, &si, TRUE);
                       GetScrollInfo (hwnd, SB_HORZ, &si);

                       // If the position has changed, scroll the window

                       if (si.nPos != iHorzPos) {
                               ScrollWindow(hwnd, 20 * (iHorzPos - si.nPos), 0,
                                               NULL, NULL);
                               UpdateWindow(hwnd);
                       }
                       break;

               default:
                       return DefWindowProc(hwnd, msg, wParam, lParam);
       }
       return 0;
}


LRESULT CALLBACK MainWndProc(HWND hwnd, UINT msg, WPARAM wParam,
               LPARAM lParam)
{
       int i, iVertPos, iHorzPos;
       WORD id, wScrollNotify;
       static int cxClient, cyClient, iMaxWidth;
       HDC hdc;
       SCROLLINFO si;
       RECT rect;
       PAINTSTRUCT ps ;
       HWND focus;
       static HWND oldFocus;
       static VARS *v;
       char *p;
       char tmp[80];

       switch (msg) {
               case WM_CREATE:
                       v = (VARS*)(((LPCREATESTRUCT)lParam)->lpCreateParams);
                       v->hwndStatus = CreateStatusWnd(v->hInst, hwnd, 2);
                       CreateChildren(v, hwnd);
                       break;

               case WM_SIZE:
                       ResizeChildren(v);
                       SendMessage(v->hwndStatus, WM_SIZE, wParam, lParam);
                       SetStatusParts(v->hwndStatus, 2);

                       GetClientRect(v->hwndCont, &rect);
                       cxClient = rect.right;
                       cyClient = rect.bottom;

                       // Set vertical scroll bar range and page size

                       si.cbSize = sizeof(si);
                       si.fMask  = SIF_RANGE | SIF_PAGE;
                       si.nMin   = 0;
                       si.nMax   = (v->yMax + 40) / 20;
                       si.nPage  = cyClient / 20;
                       SetScrollInfo (v->hwndCont, SB_VERT, &si, TRUE);

                       // Set horizontal scroll bar range and page size

                       si.cbSize = sizeof (si);
                       si.fMask  = SIF_RANGE | SIF_PAGE;
                       si.nMin   = 0;
                       si.nMax   = v->xMax / 20;
                       si.nPage  = cxClient / 20;
                       SetScrollInfo(v->hwndCont, SB_HORZ, &si, TRUE);

                       // Show scroll bars in case they were hidden
                       ShowScrollBar(v->hwndCont, SB_VERT, TRUE);
                       ShowScrollBar(v->hwndCont, SB_HORZ, TRUE);
                       break;

               case WM_PAINT:
                       hdc = BeginPaint(hwnd, &ps);

                       // Get vertical scroll bar position

                       si.cbSize = sizeof(si);
                       si.fMask  = SIF_POS;
                       GetScrollInfo(v->hwndCont, SB_VERT, &si);
                       iVertPos = si.nPos;

                       // Get horizontal scroll bar position

                       GetScrollInfo (v->hwndCont, SB_HORZ, &si);
                       iHorzPos = si.nPos;

                       // Move controls
                       MoveControls(v, iHorzPos * 20, iVertPos * 20);

                       EndPaint(hwnd, &ps);
               break;

               case WM_COMMAND:
                       id = LOWORD(wParam);
                       switch (id) {
                               case IDM_EXIT:
                                       PostQuitMessage(0);
                                       break;

                               case IDM_ADD:
                                       if (! v->sqlCmdActive)
                                               AddRow(v);
                                       break;

                               case IDM_UPDATE:
                                       if (! v->sqlCmdActive)
                                               UpdateRow(v);
                                       break;

                               case IDM_DELETE:
                                       if (! v->sqlCmdActive)
                                               DeleteRow(v);
                                       break;

                               case IDM_CLEAR:
                                       ClearFields(v);
                                       break;

                               case IDM_SEARCH:
                                       if (! v->sqlCmdActive)
                                               _beginthread(Search, 0, (void*)v);
                                       break;

                               case IDM_ORDERBY:
                                       OrderBy(v);
                                       break;

                               case IDM_SQLCMD:
                                       if (! v->sqlCmdActive) {
                                               if ((p = GetInput(v->hwndMain, "SQL Command",
                                                               v->sqlCmd, 600))) {
                                                       strcpy(v->sqlCmd, p);
                                                       _beginthread(SQLCmd, 0, (void*)v);
                                               }
                                       }
                                       break;

                               case IDM_FIRST:
                               case IDM_PREV:
                               case IDM_NEXT:
                               case IDM_LAST:
                                       if (! v->sqlCmdActive)
                                               GetRow(v, id - IDM_FIRST);
                                       break;

                               case IDM_ABOUT:
                                       DialogBox(v->hInst, "AboutBox", v->hwndMain,
                                                       AboutDlgProc);
                                       break;

                               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->hwndCont, WM_VSCROLL,
                                       MAKELONG(wScrollNotify, 0), 0L);
                                       break;

                               case ID_FOCUS_NEXT:
                               case ID_FOCUS_PREV:
                                       if ((focus = GetFocus())) {
                                               for (i = 0; i < v->nFields; i++) {
                                                       if (focus == v->hwndEdit[i])
                                                               break;
                                               }
                                               if (id == ID_FOCUS_NEXT) {
                                                       if ((++i) == 15)
                                                               i = 0;
                                               } else {
                                                       if ((--i) == -1)
                                                               i = 14;
                                               }
                                               SetFocus(v->hwndEdit[i]);
                                       }
                                       break;

                               case ID_TOTITLE:
                                       ToTitle(v);
                                       break;

                               case ID_TOUPPER:
                                       ToUpper(v);
                                       break;
                       }

                       if (v->CheckExtraAccel)
                               v->CheckExtraAccel(id, v);
                       break;

               case WM_ACTIVATE:
                       if (LOWORD(wParam) == WA_INACTIVE)
                               oldFocus = GetFocus();
                       else
                               if (oldFocus)
                                       SetFocus(oldFocus);
                       break;

               case WM_CLOSE:
                       if (! Prompt(hwnd, "SQLBase",
                                       "Do you really want to quit?", 1))
                               break;
                       DestroyWindow(hwnd);
                       break;

               case WM_DESTROY:
                       SavePlacement(hwnd, "Software\\SQLBase");
                       SetRegVal("Software\\SQLBase", "SQLCmd", (void*)(v->sqlCmd),
                               strlen(v->sqlCmd));
                       SQLDisconnect(0);
                       PostQuitMessage(0);
                       break;

               default:
                       return DefWindowProc(hwnd, msg, wParam, lParam);
       }
       return 0;
}


static VARS* Init(HINSTANCE hInst, LPSTR cmdLine, INT nCmdShow)
{
       WNDCLASS wc;
       HWND hwnd;
       VARS *v;
       RECT rect;
       int x = CW_USEDEFAULT, y = 0, w = CW_USEDEFAULT, h = 0;

       v = (VARS*)malloc(sizeof(VARS));

       v->hInst = hInst;
       v->result = NULL;
       v->numRows = 0;
       v->sqlCmdActive = FALSE;
       v->sqlResWndReg = FALSE;
       v->lastWidth = v->lastHeight = 0;

       memset(v->sqlCmd, 0, 4096);
       if (! GetRegVal("Software\\SQLBase", "SQLCmd", (void*)(v->sqlCmd),
                       4096)) {
               strcpy(v->sqlCmd, "");
       }

       if (! InitDB(v, cmdLine))
               return NULL;

       if (! LoadLibrary("riched20.dll")) {
               MessageBox(NULL, "Couldn't load riched20.dll", "SQLBase",
                               MB_OK | MB_ICONERROR);
               return NULL;
       }

       wc.style = CS_HREDRAW | CS_VREDRAW;
       wc.lpfnWndProc = (WNDPROC)MainWndProc;
       wc.cbClsExtra = 0;
       wc.cbWndExtra = 0;
       wc.hInstance = hInst;
       wc.hIcon = LoadIcon(hInst, "Icon");
       wc.hCursor = LoadCursor(NULL, IDC_ARROW);
       wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
       wc.lpszMenuName = "MainMenu";
       wc.lpszClassName = "MainWndClass";
       if (! RegisterClass(&wc))
               return NULL;

       wc.lpfnWndProc = (WNDPROC)ContWndProc;
       wc.lpszClassName = "ContWndClass";
       wc.lpszMenuName = (HMENU)NULL;
       if (! RegisterClass(&wc))
               return NULL;

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

       v->hwndMain = CreateWindow(
               "MainWndClass", v->title,
               WS_OVERLAPPEDWINDOW,
               x, y, w, h,
               NULL, NULL, hInst, (LPVOID)v);

       ShowWindow(v->hwndMain, nCmdShow);
       SetFocus(v->hwndEdit[0]);
       return v;
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
       MSG msg;
       HWND hwnd;
       VARS *v;

       if (! (v = Init(hInstance, lpCmdLine, nCmdShow)))
               return 0;

       if (! (v->hAccel = DefineAccel(v)))
               return 0;

       while (GetMessage(&msg, (HWND)NULL, 0, 0)) {
               if (! TranslateAccelerator(v->hwndMain, v->hAccel, &msg)) {
               TranslateMessage(&msg);
               DispatchMessage(&msg);
       }
   }

       DestroyAcceleratorTable(v->hAccel);
       return msg.wParam;
}