#include <windows.h>
#include <stdio.h>
#include "bool.h"
#include "person.h"
#include "plist.h"
#include "asgn4.h"


LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
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 DoAddStudent(HWND);
void DoAddInstructor(HWND);
void DoAddProgrammer(HWND);
void DoClear(HWND);
void DoCopy(HWND);
void DoSelectList(HWND, int);
void DoAbout(HWND);
BOOL CALLBACK AddStudentDialogFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK AddInstructorDialogFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK AddProgrammerDialogFunc(HWND, UINT, WPARAM, LPARAM);
BOOL CALLBACK AboutDialogFunc(HWND, UINT, WPARAM, LPARAM);


static const int NumOfLists = 2;
static plist lists[NumOfLists];
static int currentList = 0;
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;

   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 (David J. Simpson)",  // 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)
{
   static plist lists[NumOfLists];
   static int   currentList = 0;

   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 ProcessDestroyMsg(
   HWND   hwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   PostQuitMessage(0);
}


void ProcessCloseMsg(
   HWND   hwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   int response = MessageBox(hwnd,
                             "Do you want to quit?",
                             "Quit",
                             MB_ICONQUESTION | MB_YESNO);

   switch (response) {

      case IDYES :
         DestroyWindow(hwnd);
         break;

      case IDNO :
         break;

      }
}


void ProcessMenuMsg(
   HWND   hwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   switch (LOWORD(wParam)) {

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

      case IDM_ADD_STUDENT :
         DoAddStudent(hwnd);
         break;

      case IDM_ADD_INSTRUCTOR :
         DoAddInstructor(hwnd);
         break;

      case IDM_ADD_PROGRAMMER :
         DoAddProgrammer(hwnd);
         break;

      case IDM_CLEAR :
         DoClear(hwnd);
         break;

      case IDM_COPY :
         DoCopy(hwnd);
         break;

      case IDM_LIST_1 :
         DoSelectList(hwnd, 0);
         break;

      case IDM_LIST_2 :
         DoSelectList(hwnd, 1);
         break;

      case IDM_ABOUT :
         DoAbout(hwnd);
         break;

      }
}


void ProcessPaintMsg(
   HWND   hwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   person *    p;
   char        buffer[100];
   HDC         hdc;
   PAINTSTRUCT paintstruct;
   TEXTMETRIC  tm;
   int         x = 1;
   int         y = 1;
   int         count = 0;

   hdc = BeginPaint(hwnd, &paintstruct);
   GetTextMetrics(hdc, &tm);

   sprintf(buffer, "List %d", currentList + 1);
   TextOut(hdc, x, y, buffer, strlen(buffer));
   y = y + tm.tmHeight + tm.tmExternalLeading;

   sprintf(buffer, "");
   TextOut(hdc, x, y, buffer, strlen(buffer));
   y = y + tm.tmHeight + tm.tmExternalLeading;

   p = lists[currentList].getFirst();
   while (p != NULL) {
      p->display(buffer);
      TextOut(hdc, x, y, buffer, strlen(buffer));
      y = y + tm.tmHeight + tm.tmExternalLeading;
      count++;
      p = lists[currentList].getNext();
      }

   if (count > 0) {
      sprintf(buffer, "");
      TextOut(hdc, x, y, buffer, strlen(buffer));
      y = y + tm.tmHeight + tm.tmExternalLeading;
      }

   if (count == 1) {
      sprintf(buffer, "There is 1 person in the list.");
      }
   else {
      sprintf(buffer, "There are %d people in the list.", count);
      }
   TextOut(hdc, x, y, buffer, strlen(buffer));

   EndPaint(hwnd, &paintstruct);
}


void DoAddStudent(HWND hwnd) {
   DialogBox(hInst, "ADD_STUDENT_DIALOG", hwnd, (DLGPROC) AddStudentDialogFunc);
   InvalidateRect(hwnd, NULL, 1);
}


void DoAddInstructor(HWND hwnd) {
   DialogBox(hInst, "ADD_INSTRUCTOR_DIALOG", hwnd, (DLGPROC) AddInstructorDialogFunc);
   InvalidateRect(hwnd, NULL, 1);
}


void DoAddProgrammer(HWND hwnd) {
   DialogBox(hInst, "ADD_PROGRAMMER_DIALOG", hwnd, (DLGPROC) AddProgrammerDialogFunc);
   InvalidateRect(hwnd, NULL, 1);
}


void DoClear(HWND hwnd) {
   int response = MessageBox(hwnd,
                             "Do you want to clear this list?",
                             "Clear List",
                             MB_ICONQUESTION | MB_YESNO);

   switch (response) {

      case IDYES :
         lists[currentList].clearList();
         InvalidateRect(hwnd, NULL, 1);
         break;

      case IDNO :
         break;

      }
}


void DoCopy(HWND hwnd) {
   int response = MessageBox(hwnd,
                             "Do you want to copy list 1 to list 2?",
                             "Copy List",
                             MB_ICONQUESTION | MB_YESNO);

   switch (response) {

      case IDYES :
         lists[1] = lists[0];
         InvalidateRect(hwnd, NULL, 1);
         break;

      case IDNO :
         break;

      }
}


void DoSelectList(HWND hwnd, int newList) {
   HMENU menu = GetMenu(hwnd);

   currentList = newList;

   switch (newList) {
      case 0:
         CheckMenuItem(menu, IDM_LIST_1, MF_CHECKED);
         CheckMenuItem(menu, IDM_LIST_2, MF_UNCHECKED);
         break;
      case 1:
         CheckMenuItem(menu, IDM_LIST_1, MF_UNCHECKED);
         CheckMenuItem(menu, IDM_LIST_2, MF_CHECKED);
         break;
      }

   InvalidateRect(hwnd, NULL, 1);
}


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


BOOL CALLBACK AddStudentDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   student s;
   char    name[student::nameLen + 1];
   char    dept[student::deptLen + 1];

   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

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

            case IDC_ADD_BUTTON :
               GetDlgItemText(hdwnd, ID_NAME, name, student::nameLen + 1);
               s.setName(name);
               GetDlgItemText(hdwnd, ID_DEPT, dept, student::deptLen + 1);
               s.setDept(dept);
               lists[currentList].addToEnd(&s);
               EndDialog(hdwnd, 0);
               return 1;

            }

      case WM_INITDIALOG :
         return 1;

      }

   return 0;
}


BOOL CALLBACK AddInstructorDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   const int  salaryBufferLen = 15;
   instructor i;
   char       name[instructor::nameLen + 1];
   char       dept[instructor::deptLen + 1];
   char       salaryBuffer[salaryBufferLen];

   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

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

            case IDC_ADD_BUTTON :
               GetDlgItemText(hdwnd, ID_NAME, name, instructor::nameLen + 1);
               i.setName(name);
               GetDlgItemText(hdwnd, ID_DEPT, dept, instructor::deptLen + 1);
               i.setDept(dept);
               GetDlgItemText(hdwnd, ID_SALARY, salaryBuffer, salaryBufferLen);
               i.setSalary(atoi(salaryBuffer));
               lists[currentList].addToEnd(&i);
               EndDialog(hdwnd, 0);
               return 1;

            }

      case WM_INITDIALOG :
         return 1;

      }

   return 0;
}


BOOL CALLBACK AddProgrammerDialogFunc(
   HWND   hdwnd,
   UINT   message,
   WPARAM wParam,
   LPARAM lParam)
{
   const int  salaryBufferLen = 15;
   programmer p;
   char       name[programmer::nameLen + 1];
   char       company[programmer::companyLen + 1];
   char       salaryBuffer[salaryBufferLen];

   switch (message) {

      case WM_COMMAND :

         switch (LOWORD(wParam)) {

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

            case IDC_ADD_BUTTON :
               GetDlgItemText(hdwnd, ID_NAME, name, programmer::nameLen + 1);
               p.setName(name);
               GetDlgItemText(hdwnd, ID_COMPANY, company, programmer::companyLen + 1);
               p.setCompany(company);
               GetDlgItemText(hdwnd, ID_SALARY, salaryBuffer, salaryBufferLen);
               p.setSalary(atoi(salaryBuffer));
               lists[currentList].addToEnd(&p);
               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;
}