// Main Window is Dialog Box

#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include "editdbf.h"
#include "dbftable.h"
#include "..\zdate\zdate.h"

#define BUTTONS(B) \
        case B:    \
        case B+1:  \
        case B+2:  \
        case B+3:  \
        case B+4:  \
        case B+5:  \
        case B+6:  \
        case B+7:  \
        case B+8:  \
        case B+9:  \
        case B+10: \
        case B+11: \
        case B+12: \
        case B+13: \
        case B+14: \
        case B+15: \
        case B+16: \
        case B+17: \
        case B+18: \
        case B+19: \
        case B+20: \
        case B+21: \
        case B+22: \
        case B+23: \
        case B+24: \


static char APPLICATION_NAME[] = "Edit DBF File";

void error(char *f, ...)  // error message
{
    static char s[256];
    wvsprintf(s, f, (char *)(&f + 1));
    MessageBox(NULL, s, "Edit DBF", MB_OK);
}

static dbf_table table;
static int number_of_fields;
static HWND window;

static void set_control(int control, long value)
{
  char buffer[20];
  wsprintf(buffer, "%ld", value);
  SetDlgItemText(window, control, buffer);
}

static void set_control(int control, const char *value)
{
  SetDlgItemText(window, control, value);
}

static void set_control(int control, zdate zd)
{
  if (zd.valid())
  {
    char buffer[50];
    strcpy(buffer, zd.name_of_month());
    strcat(buffer, " ");
    sprintf(buffer + strlen(buffer), "%d, %d", zd.day(), zd.year());
    set_control(control, buffer);
    set_control(control-DATEBOX+DAYOFWEEKBOX, zd.name_of_day_of_week());
  }
  else
  {
    set_control(control, "");
    set_control(control-DATEBOX+DAYOFWEEKBOX, "");
  }
}

static void get_control(int control, char *value)
{
  GetDlgItemText(window, control, value, 255);
}

static bool isblank(const char *s)
{
  for (; *s != 0; s++)
  {
    if (*s != ' ' && *s != '\t')
      return false;
  }
  return true;
}

static bool get_control(int control, zdate &d, bool &isnull)
{
  char buffer[256];
  get_control(control, buffer);
  if (isblank(buffer))
  {
    isnull = true;
    return true;
  }
  isnull = false;
  return d.scan(buffer);
}

static bool get_control(int control, long &value)
{
  char buffer[256];
  get_control(control, buffer);
  return sscanf(buffer, "%ld", &value) == 1;
}

static bool get_control(int control, __int64 &value, int precision)
{
  char buffer[256];
  get_control(control, buffer);
  dbf_table::scan(value, buffer, precision);
  return true;
}

static void set_control(int control, __int64 value, int precision)
{
  char buffer[25];
  (void) dbf_table::edit(buffer, value, precision);
  SetDlgItemText(window, control, buffer);
}

static void set_field_values()
{

  CheckDlgButton(window, DELETEDBOX, table.deleted ? BST_CHECKED :
    BST_UNCHECKED);
  for (int i = 0; i < number_of_fields; i++)
  {
    const dbf_field_descriptor *p = table.field_info(i);
    switch (p->type)
    {
      case 'C':
      {
        char value[255];
        table.get(value, sizeof(value), p);
        set_control(CHARACTERBOX + i, value);
        break;
      }
      case 'N':
      {
        if (table.isblank(p))
          set_control(NUMERICBOX + i, "");
        else
        {
          __int64 n;
          table.get(n, p);
          char buffer[25];
          (void) dbf_table::edit(buffer, n, p->precision);
          set_control(NUMERICBOX + i, buffer);
        }
        break;
      }
      case 'D':
      {
        struct date dd;
        static struct date defdate = {0, 0, 0};
        table.get(dd, p, defdate);
        set_control(DATEBOX + i, zdate(dd.da_year, dd.da_mon, dd.da_day));
        break;
      }
      case 'L':
      {
        bool value;
        table.get(value, p);
        CheckDlgButton(window, LOGICALBOX + i, value ? BST_CHECKED :
          BST_UNCHECKED);
        break;
      }
    }
  }
}


static void update_field_values()
{
  table.deleted = IsDlgButtonChecked(window, DELETEDBOX) == BST_CHECKED;
  for (int i = 0; i < number_of_fields; i++)
  {
    const dbf_field_descriptor *p = table.field_info(i);
    switch (p->type)
    {
      case 'C':
      {
        char value[255];
        get_control(CHARACTERBOX + i, value);
        table.put(value, p);
        break;
      }
      case 'N':
      {
        char value[255];
        get_control(NUMERICBOX + i, value);
        __int64 n;
        dbf_table::scan(n, value, p->precision);
        if (isblank(value))
          table.put(value, p);
        else
          table.put(n, p);
        break;
      }
      case 'D':
      {
        zdate zd;
        bool isnull;
        // static struct date defdate = {0, 0, 0};
        get_control(DATEBOX + i, zd, isnull);
        if (isnull)
          table.put("        ", p);
        else
        {
          struct date dd;
          dd.da_mon = zd.month();
          dd.da_day = zd.day();
          dd.da_year = zd.year();
          table.put(dd, p);
        }
        break;
      }
      case 'L':
      {
        bool value =
          IsDlgButtonChecked(window, LOGICALBOX + i) == BST_CHECKED;
        table.put(value, p);
        break;
      }
    }
  }
  table.update();
}


BOOL CALLBACK MainProc(HWND window, UINT message, WPARAM wParam,
  LPARAM lParam)
{
  switch (message)
  {
    // WM_INITDIALOG is not called
    case WM_CREATE:
      return 0;
    case WM_COMMAND:
      switch (LOWORD(wParam))
      {
        case CLOSEBUTTON:
          DestroyWindow(window);
          return 0;
        case UPDATEBUTTON:
          update_field_values();
          // return 0;
        case NEXTBUTTON:
          if (table.record_number < table.number_of_records)
          {
            table.record_number = table.record_number + 1;
            set_control(RECORDNUMBER, table.record_number);
            set_field_values();
          }
          return 0;
        case PREVIOUSBUTTON:
          if (table.record_number > 1)
          {
            table.record_number = table.record_number - 1;
            set_control(RECORDNUMBER, table.record_number);
            set_field_values();
          }
          return 0;
        case LASTBUTTON:
          if (table.record_number < table.number_of_records)
          {
            table.record_number = table.number_of_records;
            set_control(RECORDNUMBER, table.record_number);
            set_field_values();
          }
          return 0;
        BUTTONS(TODAYBUTTON)
          set_control(LOWORD(wParam) - TODAYBUTTON + DATEBOX, zdate::today());
          return 0;
        BUTTONS(BACKBUTTON)
        {
          int control = LOWORD(wParam) - BACKBUTTON + DATEBOX;
          bool isnull;
          zdate d;
          if (get_control(control, d, isnull) && !isnull)
          {
            --d;
            set_control(control, d);
          }
          return 0;
        }
        BUTTONS(NUMERICBOX)
          if (HIWORD(wParam) == EN_KILLFOCUS)
          {
            int control = LOWORD(wParam);
            char value[256];
            get_control(control, value);
            if (!isblank(value))
            {
              int precision = table.field_info(control-NUMERICBOX)->precision;
              __int64 n;
              if (get_control(control, n, precision))
                set_control(control, n, precision);
              else
              {
                error("Invalid number");
                SetFocus(GetDlgItem(window, control));
              }
            }
          }
          return 0;
        BUTTONS(DATEBOX)
          if (HIWORD(wParam) == EN_KILLFOCUS)
          {
            int control = LOWORD(wParam);
            bool isnull;
            zdate d;
            if (get_control(control, d, isnull))
            {
              if (isnull)
                set_control(control, " ");
              else
                set_control(control, d);
            }
            else
            {
              error("Invalid date");
              SetFocus(GetDlgItem(window, control));
            }
          }
          return 0;
        BUTTONS(FORWARDBUTTON)
        {
          int control = LOWORD(wParam) - FORWARDBUTTON + DATEBOX;
          bool isnull;
          zdate d;
          if (get_control(control, d, isnull) && !isnull)
          {
            ++d;
            set_control(control, d);
          }
          return 0;
        }
        case RECORDNUMBER:
        {
          if (HIWORD(wParam) == EN_KILLFOCUS)
          {
            long n;
            if (get_control(RECORDNUMBER, n))
            {
              if (1 <= n && n <= table.number_of_records && n !=
                table.record_number)
              {
                table.record_number = n;
                set_control(RECORDNUMBER, table.record_number);
                set_field_values();
              }
            }
          }
          return 0;
        }
      }
      break;
    case WM_CLOSE:
      DestroyWindow(window);
      return 0;
    case WM_DESTROY:
      PostQuitMessage(0);
      return 0;
  }
  return DefDlgProc (window, message, wParam, lParam);
}

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{

  if (!hPrevInstance)
  {
    WNDCLASSEX w;
    w.cbSize = sizeof(WNDCLASSEX);
    w.style = 0;
    w.lpfnWndProc = (WNDPROC) MainProc;
    w.cbClsExtra = 0;
    w.cbWndExtra = DLGWINDOWEXTRA;
    w.hInstance = hInstance;
    // w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    w.hIcon = LoadIcon(hInstance, "MAINICON");
    w.hIconSm = NULL;
    // w.hIconSm = LoadIcon(hInstance, "MAINICONSMALL");
    w.hCursor = LoadCursor (NULL, IDC_ARROW);
    // w.hCursor = LoadCursor (hInstance, "MYCURSOR");
    w.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    w.lpszMenuName = NULL;
    w.lpszClassName = "MAINDIALCLASS";
    RegisterClassEx(&w);
  }

  if (lpszCmdLine[0] == 0)
  {
    MessageBox(NULL, "No file", APPLICATION_NAME, MB_OK);
    return 1;
  }

  if (!table.open(lpszCmdLine, DBF_UPDATE))
  {
    MessageBox(NULL, "Can't open file", APPLICATION_NAME, MB_OK);
    return 1;
  }

  window = CreateDialog(hInstance, "MAINDIALBOX", NULL, NULL);
  SetWindowText(window, lpszCmdLine);

  // intialize window and controls
  // {
  //   char buffer[10];
  //   wsprintf(buffer, "%ld", table.number_of_records);
  //   SetDlgItemText(window, RECORDNUMBER, "0");
  //   SetDlgItemText(window, TOTALRECORDS, buffer);
  // }

  set_control(TOTALRECORDS, table.number_of_records);

  for (number_of_fields = 0; ; number_of_fields++)
  {
    if (number_of_fields > MAX_FIELDS)
    {
      MessageBox(NULL, "File has too many fields", APPLICATION_NAME, MB_OK);
      return 1;
    }

    const dbf_field_descriptor *p = table.field_info(number_of_fields);
    if (p == NULL)
      break;
    switch (p->type)
    {
      case 'C':
        set_control(NAMEBOX + number_of_fields, p->name);
        ShowWindow(GetDlgItem(window, NAMEBOX + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, CHARACTERBOX + number_of_fields),
          SW_SHOW);
        break;
      case 'N':
        set_control(NAMEBOX + number_of_fields, p->name);
        ShowWindow(GetDlgItem(window, NAMEBOX + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, NUMERICBOX + number_of_fields),
          SW_SHOW);
        break;
      case 'D':
        set_control(NAMEBOX + number_of_fields, p->name);
        ShowWindow(GetDlgItem(window, NAMEBOX + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, BACKBUTTON + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, TODAYBUTTON + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, FORWARDBUTTON + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, DATEBOX + number_of_fields),
          SW_SHOW);
        ShowWindow(GetDlgItem(window, DAYOFWEEKBOX + number_of_fields),
          SW_SHOW);
        break;
      case 'L':
        set_control(LOGICALBOX + number_of_fields, p->name);
        ShowWindow(GetDlgItem(window, LOGICALBOX + number_of_fields),
          SW_SHOW);
        break;
    }

  }

  if (table.number_of_records != 0)
  {
    table.record_number = 1;
    set_control(RECORDNUMBER, 1);
    set_field_values();
  }

  if (table.number_of_records < 2)
  {
    EnableWindow(GetDlgItem(window, PREVIOUSBUTTON), FALSE);
    EnableWindow(GetDlgItem(window, NEXTBUTTON), FALSE);
    EnableWindow(GetDlgItem(window, RECORDNUMBER), FALSE);
  }

  if (table.number_of_records == 0)
    EnableWindow(GetDlgItem(window, UPDATEBUTTON), FALSE);

  {
    RECT r;
    GetWindowRect(GetDlgItem(window, CHARACTERBOX+number_of_fields-1), &r);
    MoveWindow(window, 20, 20, r.right, r.bottom, true);
  }

  {
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0))
    {
      if (!IsDialogMessage(window, &msg))
      {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
      }
    }
    return msg.wParam;
  }

}

