#include <windows.h>
#include <strstrea.h>
#include <stdio.h>
#include "bool.h"
#include "parse.h"
#include "expr.h"
#include "asgn4.h"


LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
void Initialize();
void Uninitialize();
void ProcessMenuMsg(HWND, UINT, WPARAM, LPARAM);
void ProcessDestroyMsg(HWND, UINT, WPARAM, LPARAM);
void ProcessCloseMsg(HWND, UINT, WPARAM, LPARAM);
void ProcessPaintMsg(HWND, UINT, WPARAM, LPARAM);
void DoEnterExpr(HWND);
void DoClearExpr(HWND);
void DoJoinExpr(HWND);
void DoAbout(HWND);
BOOL CALLBACK EnterExprDialogFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK ClearExprDialogFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK JoinExprDialogFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK AboutDialogFunc(HWND, UINT, WPARAM, LPARAM);


static const int MaxExprLen = 100;
static const int NumOfExpr = 2;
static expr * exprs[NumOfExpr];
static char szWinName[] = "Assignment_4";
static HINSTANCE hInst;


int WINAPI WinMain(
   HINSTANCE hThisInst,
   HINSTANCE hPrevInst,
   LPSTR lpszArgs,
   int nWinMode)
{

   HWND     hwnd;
   MSG      msg;
   WNDCLASS wcl;

   Initialize();

   wcl.hInstance     = hThisInst;
   wcl.lpszClassName = szWinName;
   wcl.lpfnWndProc   = WindowFunc;
   wcl.style         = 0;

   wcl.hIcon         = LoadIcon(hThisInst, "MAINICON");
   wcl.hCursor       = LoadCursor(NULL, IDC_ARROW);
   wcl.lpszMenuName  = "MAINMENU";

   wcl.cbClsExtra    = 0;
   wcl.cbWndExtra    = 0;

   wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);

   if (!RegisterClass(&wcl)) {
      return 0;
      }

   hwnd = CreateWindow(
            szWinName,                       // name of window class.
            "CMPT 212 Sample Assignment 4",  // title.
            WS_OVERLAPPEDWINDOW,             // window style.
            CW_USEDEFAULT,                   // x coordinate.
            CW_USEDEFAULT,                   // y coordinate.
            CW_USEDEFAULT,                   // width.
            CW_USEDEFAULT,                   // height.
            HWND_DESKTOP,                    // parent window.
            NULL,                            // no menu.
            hThisInst,                       // handle to this instance.
            NULL);                           // no additional arguments.

   hInst = hThisInst;

   ShowWindow(hwnd, nWinMode);
   UpdateWindow(hwnd);

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

   return msg.wParam;
}


LRESULT CALLBACK WindowFunc(
   HWND hwnd,
   UINT message,
   WPARAM wParam,
   LPARAM lParam)
{
   switch (message) {

      case WM_DESTROY :
         ProcessDestroyMsg(hwnd, message, wParam, lParam);
         break;

      case WM_CLOSE :
         ProcessCloseMsg(hwnd, message, wParam, lParam);
         break;

      case WM_COMMAND :
         ProcessMenuMsg(hwnd, message, wParam, lParam);

      case WM_PAINT :
         ProcessPaintMsg(hwnd, message, wParam, lParam);

      default :
         return DefWindowProc(hwnd, message, wParam, lParam);

      }

   return 0;
}


void Initialize()
{
   for (int i=0; istr(), os->pcount());
      y = y + tm.tmHeight + tm.tmExternalLeading;
      delete os;

      TextOut(hdc, x, y, "", 0);
      y = y + tm.tmHeight + tm.tmExternalLeading;

      os = new ostrstream;
      exprs[i]->display(*os);
      TextOut(hdc, x, y, os->str(), os->pcount());
      y = y + tm.tmHeight + tm.tmExternalLeading;
      delete os;

      os = new ostrstream;
      (*os) << exprs[i]->evaluate();
      TextOut(hdc, x, y, os->str(), os->pcount());
      y = y + tm.tmHeight + tm.tmExternalLeading;
      delete os;

      TextOut(hdc, x, y, "", 0);
      y = y + tm.tmHeight + tm.tmExternalLeading;

      }

   EndPaint(hwnd, &paintstruct);
}


void DoEnterExpr(HWND hwnd) {
   DialogBox(hInst, "ENTER_EXPR_DIALOG", hwnd, (DLGPROC) EnterExprDialogFunc);
   InvalidateRect(hwnd, NULL, 1);
}


void DoClearExpr(HWND hwnd) {
   DialogBox(hInst, "CLEAR_EXPR_DIALOG", hwnd, (DLGPROC) ClearExprDialogFunc);
   InvalidateRect(hwnd, NULL, 1);
}


void DoJoinExpr(HWND hwnd) {
   DialogBox(hInst, "JOIN_EXPR_DIALOG", hwnd, (DLGPROC) JoinExprDialogFunc);
   InvalidateRect(hwnd, NULL, 1);
}


void DoAbout(HWND hwnd) {
   DialogBox(hInst, "ABOUT_DIALOG", hwnd, (DLGPROC) AboutDialogFunc);
}


BOOL CALLBACK EnterExprDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   char str[MaxExprLen];

   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

            case IDC_CANCEL_BUTTON :
               EndDialog(hdwnd, 0);
               return 1;

            case IDC_EXPR_1_BUTTON :
               GetDlgItemText(hdwnd, ID_EXPR_STR, str, MaxExprLen);
               delete exprs[0];
               exprs[0] = parse(str);
               EndDialog(hdwnd, 0);
               return 1;

            case IDC_EXPR_2_BUTTON :
               GetDlgItemText(hdwnd, ID_EXPR_STR, str, MaxExprLen);
               delete exprs[1];
               exprs[1] = parse(str);
               EndDialog(hdwnd, 0);
               return 1;

            }

      case WM_INITDIALOG :
         return 1;

      }

   return 0;
}


BOOL CALLBACK ClearExprDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

            case IDC_CANCEL_BUTTON :
               EndDialog(hdwnd, 0);
               return 1;

            case IDC_EXPR_1_BUTTON :
               delete exprs[0];
               exprs[0] = new constant(0.0);
               EndDialog(hdwnd, 0);
               return 1;

            case IDC_EXPR_2_BUTTON :
               delete exprs[1];
               exprs[1] = new constant(0.0);
               EndDialog(hdwnd, 0);
               return 1;

            }

      case WM_INITDIALOG :
         return 1;

      }

   return 0;
}


BOOL CALLBACK JoinExprDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   composite::operation oper = composite::Addition;
   bool operSelected = false;

   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

            case IDC_CANCEL_BUTTON :
               EndDialog(hdwnd, 0);
               return 1;

            case IDC_OK_BUTTON :
               if (SendDlgItemMessage(hdwnd, IDC_ADDITION, BM_GETCHECK, 0, 0)) {
                  oper = composite::Addition;
                  operSelected = true;
                  }
               if (SendDlgItemMessage(hdwnd, IDC_SUBTRACTION, BM_GETCHECK, 0, 0)) {
                  oper = composite::Subtraction;
                  operSelected = true;
                  }
               if (SendDlgItemMessage(hdwnd, IDC_MULTIPLICATION, BM_GETCHECK, 0, 0)) {
                  oper = composite::Multiplication;
                  operSelected = true;
                  }
               if (SendDlgItemMessage(hdwnd, IDC_DIVISION, BM_GETCHECK, 0, 0)) {
                  oper = composite::Division;
                  operSelected = true;
                  }
               if (!operSelected) {
                  MessageBox(hdwnd, "You must select an operation.", "No Operation", MB_ICONEXCLAMATION | MB_OK);
                  }
               else {
                  exprs[0] = new composite(oper, exprs[0], exprs[1]->clone());
                  EndDialog(hdwnd, 0);
                  }
               return 1;

            }

      case WM_INITDIALOG :
         return 1;

      }

   return 0;
}


BOOL CALLBACK AboutDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

            case IDOK :
               EndDialog(hdwnd, 0);
               return 1;

            }

      case WM_INITDIALOG :
         return 1;

      }

   return 0;
}