#ifndef __WINDOW_H
#include "windows.h"
#endif

#include <commdlg.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <string.h>

#ifndef _BASEWIND_
#include "basewind.h"   /* basetype */
#endif

#ifndef _HOSTERRS_
#include "hosterrs.h"
#endif

#ifndef _CLIULIB_
#include "cliulib.h"
#endif

#ifndef _CLISRV_
#include "clisrv.h"
#endif

#ifndef _HEAP_
#include "heap.h"
#endif

#ifndef _EVENT_
#include "event.h"
#endif

#include "memupm.h"

                /***********************
                *                      *
                *     DEFINITIONS      *
                *                      *
                ************************/
               /************************
               *                       *
               *     EXTERNAL          *
               *                       *
               *************************/
extern HANDLE hLib;
               /************************
               *                       *
               *       LOCAL           *
               *                       *
               *************************/
HANDLE hWndUPM[2];
char szAppName[20];
PRIVATE BOOLEAN registeredClasses[2] = {FALSE,FALSE};
int  nTop,nLeft,cxMaxChar,cxAveChar,cyHeight;
static HANDLE hInst;
CHAR szString[128];
int topDist,upmPos;
U32 upmBuff[2][64];
FARPROC lpfnOldEdit,lpUpmaProc,lpUpmbProc;
U8 upmFlag;
               /************************
               *                       *
               *       PROTOTYPE       *
               *                       *
               *************************/
BOOL FAR PASCAL UpmaDlgProc (HWND ,UINT ,UINT ,LONG );
BOOL FAR PASCAL UpmbDlgProc (HWND ,UINT ,UINT ,LONG );
U16 Swap(U8 *buf,U8 len);
               /************************
               *                       *
               *      EXECUTE CODE     *
               *                       *
               *************************/

/*****************************************************************************
**
**  CreateUPMPresenter
**
*****************************************************************************/
RETCODE CreateUPMPresenter(HINSTANCE hInstance, S16 left, S16 top,
                              S16 width, S16 height,U8 flag) {
   int nRc;  // return value from Register Classes
   RETCODE err;
   char szString00[2][10]={"UPMA","UPMB"};

   strcpy(szAppName, szString00[flag]);
   hInst = hInstance;
   nTop=top;
   nLeft=left;
   if(!registeredClasses[flag]) {
      /* register window classes if first instance of application */
      if ((nRc = nCwRegisterClasses(flag)) == -1) {
         // TODO: Replace this with ErrDisplayFormattedError
         strcpy(szString, "Error registering virtual listbox or peripheral");
         MessageBox(NULL, szString, NULL, MB_ICONEXCLAMATION);
         return nRc;
      }
      registeredClasses[flag] = TRUE;
   }

   if (!left && !width) {
      left = CW_USEDEFAULT;
      width = CW_USEDEFAULT;
   }
   
   /* create WatchPoint window */
   hWndUPM[flag] = CreateWindow((LPSTR) szAppName,    /* Window class name    */
                           (LPSTR) szString00[flag],  /* title         */
                           (WS_CAPTION     |     /* Title and Min/Max    */
                           WS_SYSMENU      |     /* Add system menu box  */
                           WS_MINIMIZEBOX  |     /* Add minimize box     */
                          /* WS_MAXIMIZEBOX  |      Add maximize box     */
                           WS_THICKFRAME   |
                           WS_CLIPCHILDREN |     /* don't draw in child ares */
                           WS_OVERLAPPED),
                           left, top,         
                           300, 200,
                           NULL,                 /* Parent window's handle */
                           NULL,                 /* Default to Class Menu */
                           hInst,                /* Instance of window */
                           NULL);       /* Create struct for WM_CREATE */

   UpdateWindow (hWndUPM[flag]);
   return GOOD;
}

/*****************************************************************
*                                                                *
*         UPMAWndProc                                             *
*                                                                *
******************************************************************/
long FAR PASCAL UPMAWndProc (HWND hWnd, UINT message,
         UINT wParam, LONG lParam) {
HDC hDc;
HFONT hFont, hOldFont;
HMENU hMenu;
TEXTMETRIC     tm;
PAINTSTRUCT    ps;
POINT cursorPos;
int cyChar,nResult,i,j;
char szString00[5];
char szString01[9]="00000000";
RECT winRect,cliRect;
U32 swapAddr;

   switch (message) {
      case WM_CREATE:
         hDc = GetDC(hWnd);
         hFont=GetStockObject(SYSTEM_FIXED_FONT);
         hOldFont=SelectObject(hDc,hFont);
         GetTextMetrics(hDc,&tm);
         cxMaxChar = tm.tmMaxCharWidth;
         cxAveChar = tm.tmAveCharWidth;
         cyChar = tm.tmHeight + 3 * tm.tmExternalLeading ;
         cyHeight = 1.4 * cyChar;
         ReleaseDC(hWnd,hDc);
         Sds2AbiFwGetUpm(0,upmBuff[0]);

         GetWindowRect(hWnd,&winRect);
         GetClientRect(hWnd,&cliRect);
         topDist=(winRect.bottom-winRect.top)-(cliRect.bottom-cliRect.top);
         MoveWindow(hWnd,nTop,nLeft,46*cxAveChar,
            16*cyHeight,1);
         return 0;
      case WM_LBUTTONDBLCLK:
         GetWindowRect(hWnd,&winRect);
         GetCursorPos(&cursorPos);
         cursorPos.x=cursorPos.x-winRect.left;
         cursorPos.y=cursorPos.y-winRect.top;
         upmPos=(cursorPos.x-5*cxAveChar)/(10*cxAveChar)+(cursorPos.y-topDist)/cyHeight*4;
         lpUpmaProc=MakeProcInstance((FARPROC)UpmaDlgProc,
             hInst);
         upmFlag=0;
         DialogBox(hInst,"UPM",hWnd,lpUpmaProc);
         Sds2AbiFwGetUpm(0,upmBuff[0]);
         InvalidateRect(hWnd,NULL,TRUE);
         UpdateWindow(hWnd);
         return 0;
      case WM_PAINT :
         hDc=BeginPaint(hWnd,&ps);
         //item name
         for (i=0;i<16;i++) {
           wsprintf(szString00,"%02x",i*4);
           strupr(szString00);
           TextOut(hDc,cxAveChar,i*cyHeight,szString00,
               strlen(szString00));
           for (j=0;j<4;j++) {
              //TextOut(hDc,5*cxAveChar+10*j*cxAveChar,i*cyHeight,szString01,
              //    strlen(szString01));
              swapAddr=upmBuff[0][i*4+j];
              Swap(&swapAddr,4);
              //wsprintf(szString01,"%08lx",upmBuff[0][i*4+j]);
              wsprintf(szString01,"%08lx",swapAddr);
              strupr(szString01);
              TextOut(hDc,5*cxAveChar+10*j*cxAveChar,i*cyHeight,szString01,
                  strlen(szString01));
              }
         }
         EndPaint(hWnd,&ps);
         return 0;

      case WM_CLOSE:
         DestroyWindow(hWnd);
         hWndUPM[0]=NULL;
         break;

      case WM_DESTROY :
         hWndUPM[0]=NULL;
         break;
   }
   return DefWindowProc (hWnd, message, wParam, lParam);
}

/*****************************************************************
*                                                                *
*         UPMBWndProc                                             *
*                                                                *
******************************************************************/
long FAR PASCAL UPMBWndProc (HWND hWnd, UINT message,
         UINT wParam, LONG lParam) {
HDC hDc;
HFONT hFont, hOldFont;
HMENU hMenu;
TEXTMETRIC     tm;
PAINTSTRUCT    ps;
POINT cursorPos;
int cyChar,nResult,i,j;
char szString00[5];
char szString01[9]="00000000";
RECT winRect,cliRect;
U32 swapAddr;

   switch (message) {
      case WM_CREATE:
         hDc = GetDC(hWnd);
         hFont=GetStockObject(SYSTEM_FIXED_FONT);
         hOldFont=SelectObject(hDc,hFont);
         GetTextMetrics(hDc,&tm);
         cxMaxChar = tm.tmMaxCharWidth;
         cxAveChar = tm.tmAveCharWidth;
         cyChar = tm.tmHeight + 3 * tm.tmExternalLeading ;
         cyHeight = 1.4 * cyChar;
         ReleaseDC(hWnd,hDc);
         Sds2AbiFwGetUpm(1,upmBuff[1]);

         GetWindowRect(hWnd,&winRect);
         GetClientRect(hWnd,&cliRect);
         topDist=(winRect.bottom-winRect.top)-(cliRect.bottom-cliRect.top);
         MoveWindow(hWnd,nTop,nLeft,46*cxAveChar,
            16*cyHeight,1);
         return 0;
      case WM_LBUTTONDBLCLK:
         GetWindowRect(hWnd,&winRect);
         GetCursorPos(&cursorPos);
         cursorPos.x=cursorPos.x-winRect.left;
         cursorPos.y=cursorPos.y-winRect.top;
         upmPos=(cursorPos.x-5*cxAveChar)/(10*cxAveChar)+(cursorPos.y-topDist)/cyHeight*4;
         upmFlag=1;
         lpUpmaProc=MakeProcInstance((FARPROC)UpmbDlgProc,
             hInst);
         DialogBox(hInst,"UPM",hWnd,lpUpmaProc);
         Sds2AbiFwGetUpm(1,upmBuff[1]);
         InvalidateRect(hWnd,NULL,TRUE);
         UpdateWindow(hWnd);
         return 0;
      case WM_PAINT :
         hDc=BeginPaint(hWnd,&ps);
         //item name
         for (i=0;i<16;i++) {
           wsprintf(szString00,"%02x",i*4);
           strupr(szString00);
           TextOut(hDc,cxAveChar,i*cyHeight,szString00,
               strlen(szString00));
           for (j=0;j<4;j++) {
              //TextOut(hDc,5*cxAveChar+10*j*cxAveChar,i*cyHeight,szString01,
              //    strlen(szString01));
              swapAddr=upmBuff[1][i*4+j];
              Swap(&swapAddr,4);
              wsprintf(szString01,"%08lx",swapAddr);
              strupr(szString01);
              TextOut(hDc,5*cxAveChar+10*j*cxAveChar,i*cyHeight,szString01,
                  strlen(szString01));
              }

         }
         EndPaint(hWnd,&ps);
         return 0;

      case WM_CLOSE:
         DestroyWindow(hWnd);
         hWndUPM[1]=NULL;
         break;

      case WM_DESTROY :
         hWndUPM[1]=NULL;
         break;
   }
   return DefWindowProc (hWnd, message, wParam, lParam);
}

/*****************************************************************************
**
**  nCwRegisterClasses
**
*****************************************************************************/
int nCwRegisterClasses(U8 flag) {
   WNDCLASS   wndclass;    /* struct to define a window class */
   HINSTANCE  hInstance;
   HWND hToolBar;
   memset(&wndclass, 0x00, sizeof(WNDCLASS));

   /* load WNDCLASS with window's characteristics */
   wndclass.style = CS_HREDRAW | CS_VREDRAW |CS_DBLCLKS; // | CS_BYTEALIGNWINDOW;
   if (flag == 0)
      wndclass.lpfnWndProc = UPMAWndProc;
   else
      wndclass.lpfnWndProc = UPMBWndProc;

   /* Extra storage for Class and Window objects  */
   wndclass.cbClsExtra = 0;
   wndclass.cbWndExtra = 0;
   wndclass.hInstance = hInst;
   wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);

   /* Create brush for erasing background */
   wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
   wndclass.lpszMenuName = NULL;   /* Menu Name is App Name */
   wndclass.lpszClassName = szAppName; /* Class Name is App Name */
   if(!RegisterClass(&wndclass))
      return -1;
   return(0);
}
/*****************************************************************************
**
**  UPMAOpenWindow
**
*****************************************************************************/
RETCODE EXPORT UPMAOpenWindow(HWND parent,int left,int top,int width,
     int height,DWORD dwStyle,DWORD dwExStyle,HWND *UPMWindow) {
RETCODE err=GOOD;

   if (hWndUPM[0] == NULL) {
      err = CreateUPMPresenter(hLib, left, top,
               width, height,0);
      *UPMWindow = hWndUPM[0];
   }
   return err;
}
/*****************************************************************************
**
**  UPMBOpenWindow
**
*****************************************************************************/
RETCODE EXPORT UPMBOpenWindow(HWND parent,int left,int top,int width,
     int height,DWORD dwStyle,DWORD dwExStyle,HWND *UPMWindow) {
RETCODE err=GOOD;


   if (hWndUPM[1] == NULL) {
      err = CreateUPMPresenter(hLib, left, top,
               width, height,1);
      *UPMWindow = hWndUPM[1];
   }
   return err;
}

/*****************************************************************************
**
**  UPMACloseWindow
**
*****************************************************************************/
RETCODE EXPORT UPMACloseWindow() {
   if (hWndUPM[0] != NULL) {
      //WhptWatchPointClose(theWatchPoint);
      hWndUPM[0] = NULL;
   }
   return GOOD;
}
/*****************************************************************************
**
**  UPMBCloseWindow
**
*****************************************************************************/
RETCODE EXPORT UPMBCloseWindow() {
   if (hWndUPM[1] != NULL) {
      //WhptWatchPointClose(theWatchPoint);
      hWndUPM[1] = NULL;
   }
   return GOOD;
}
/*****************************************************************************
**
**  UPMAExistsWindow
**
*****************************************************************************/
RETCODE EXPORT UPMAExistsWindow() {
   //*whptHandle = hWndWatchPoint;
   return GOOD;
}
/*****************************************************************************
**
**  UPMBExistsWindow
**
*****************************************************************************/
RETCODE EXPORT UPMBExistsWindow() {
   //*whptHandle = hWndWatchPoint;
   return GOOD;
}
/****************************************************************
**
**     UpmDlgProc
**
*****************************************************************/
BOOL FAR PASCAL UpmaDlgProc (HWND hDlg, UINT message,
                UINT wParam, LONG lParam) {
PAINTSTRUCT ps;
HDC hDc;
char szString00[15],ptr[15];
U32 tempValue;
U32 swapAddr;

   switch(message) {
      case WM_INITDIALOG:
         swapAddr=upmBuff[upmFlag][upmPos];
         Swap(&swapAddr,4);
         wsprintf(szString00,"0x%08lx",swapAddr);
         SetWindowText(GetDlgItem(hDlg,IDC_TEXT),szString00);
         return TRUE;
      case WM_COMMAND:
         switch(wParam) {
             case IDC_OK:
                SendMessage(GetDlgItem(hDlg,IDC_TEXT),WM_GETTEXT,sizeof(szString00),
                   szString00);
                tempValue=strtoul(szString00,&ptr,0);
                Swap(&tempValue,4);
                Sds2AbiFwSetUpm(upmFlag,upmPos,tempValue);
                upmBuff[upmFlag][upmPos]=tempValue;
             case IDC_CANCEL:
               EndDialog(hDlg,TRUE);
               return TRUE;
          }
          break;
      case WM_PAINT:
         hDc=BeginPaint(hDlg,&ps);
         wsprintf(szString00,"%02x : ",upmPos);
         TextOut(hDc,25,5,szString00,strlen(szString00));
         EndPaint(hDlg,&ps);
         return TRUE;
   }
   return FALSE;
}
/****************************************************************
**
**     UpmDlgProc
**
*****************************************************************/
BOOL FAR PASCAL UpmbDlgProc (HWND hDlg, UINT message,
                UINT wParam, LONG lParam) {
PAINTSTRUCT ps;
HDC hDc;
char szString00[15],ptr[15];
U32 tempValue;
U32 swapAddr;

   switch(message) {
      case WM_INITDIALOG:
         swapAddr=upmBuff[upmFlag][upmPos];
         Swap(&swapAddr,4);
         wsprintf(szString00,"0x%08lx",swapAddr);
         SetWindowText(GetDlgItem(hDlg,IDC_TEXT),szString00);
         return TRUE;
      case WM_COMMAND:
         switch(wParam) {
             case IDC_OK:
                SendMessage(GetDlgItem(hDlg,IDC_TEXT),WM_GETTEXT,sizeof(szString00),
                   szString00);
                tempValue=strtoul(szString00,&ptr,0);
                Swap(&tempValue,4);
                Sds2AbiFwSetUpm(upmFlag,upmPos,tempValue);
                upmBuff[upmFlag][upmPos]=tempValue;
             case IDC_CANCEL:
               EndDialog(hDlg,TRUE);
               return TRUE;
          }
          break;
      case WM_PAINT:
         hDc=BeginPaint(hDlg,&ps);
         wsprintf(szString00,"%02x : ",upmPos);
         TextOut(hDc,25,5,szString00,strlen(szString00));
         EndPaint(hDlg,&ps);
         return TRUE;
   }
   return FALSE;
}
U16 Swap(U8 *buf,U8 len) {
U8 temp,i;
    for (i=0;i<(len/2);i++) {
       temp=buf[i];
       buf[i]=buf[len-1-i];
       buf[len-1-i]=temp;
    }
}
