#include <windows.h>
#include <commctrl.h>
#include <commdlg.h>
#include <richedit.h>
#include <stdio.h>
#include <ctype.h>

#include "header.h"
#include "operands.h"
#include "opcodes.h"

typedef struct {
   TCData ptrs;
   int *olddataptr;
   int *currentdataptr ;
   HTREEITEM hTreeItem ;
   enum { floating = 1, editable = 2 } flags ;
} REGDATA ;

LRESULT  CALLBACK _export YesNoProc( HWND hwnd, UINT iMessage, WPARAM wParam,
                                 LPARAM lParam ) ;
extern HINSTANCE hInstance ;
extern HWND hwndClient,hwndStatus,hwndFrame ;
extern int childxpos, childypos ;
extern PROCESS DebugProcess ;
extern enum DebugState uState;
extern HWND hwndTab ;
extern CONTEXT StoppedRegs ;

HWND hwndRegister ;
static HWND hwndTree ;
static char szRegisterClassName[] = "xccRegisterClass" ;
static char szRegisterTitle[] = "" ;
static LOGFONT fontdata = {
	16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,ANSI_CHARSET,OUT_DEFAULT_PRECIS,
	CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_DONTCARE,
	"Courier New"
} ;
static HANDLE registerHandle ;
static CONTEXT oldContext ;
static HBITMAP valueBitmap, itemBitmap ;

static char xeax[] = "EAX" ;
static char xebx[] = "EBX" ;
static char xecx[] = "ECX" ;
static char xedx[] = "EDX" ;
static char xesi[] = "ESI" ;
static char xedi[] = "EDI" ;
static char xesp[] = "ESP" ;
static char xebp[] = "EBP" ;
static char xeip[] = "EIP" ;
static char xst0[] = "ST0" ;
static char xst1[] = "ST1" ;
static char xst2[] = "ST2" ;
static char xst3[] = "ST3" ;
static char xst4[] = "ST4" ;
static char xst5[] = "ST5" ;
static char xst6[] = "ST6" ;
static char xst7[] = "ST7" ;
static char xeflags[] = "EFLAGS" ;
static char eaxbuf[20] ;
static char ebxbuf[20] ;
static char ecxbuf[20] ;
static char edxbuf[20] ;
static char esibuf[20] ;
static char edibuf[20] ;
static char espbuf[20] ;
static char ebpbuf[20] ;
static char eipbuf[20] ;
static char eflagsbuf[20] ;
static char st0buf[40] ;
static char st1buf[40] ;
static char st2buf[40] ;
static char st3buf[40] ;
static char st4buf[40] ;
static char st5buf[40] ;
static char st6buf[40] ;
static char st7buf[40] ;

static char regst[] = "Arithmetic" ;
static char control[] = "Control" ;
static char floatingname[] = "Floating" ;
static REGDATA regs[] = {
   { { &regst, 0 } , 0, 0, 0, } ,
   { { &xeax, &eaxbuf } , &oldContext.Eax, &StoppedRegs.Eax,0,editable },
   { { &xebx, &ebxbuf } , &oldContext.Ebx, &StoppedRegs.Ebx,0,editable },
   { { &xecx, &ecxbuf } , &oldContext.Ecx, &StoppedRegs.Ecx,0,editable },
   { { &xedx, &edxbuf } , &oldContext.Edx, &StoppedRegs.Edx,0,editable },
   { { &xesi, &esibuf } , &oldContext.Esi, &StoppedRegs.Esi,0,editable },
   { { &xedi, &edibuf } , &oldContext.Edi, &StoppedRegs.Edi,0,editable },
   { { &control, 0 }, 0, 0, 0, } ,
   { { &xesp, &espbuf } , &oldContext.Esp, &StoppedRegs.Esp,0,editable },
   { { &xebp, &ebpbuf } , &oldContext.Ebp, &StoppedRegs.Ebp,0,editable },
   { { &xeip, &eipbuf } , &oldContext.Eip, &StoppedRegs.Eip,0,editable },
   { { &xeflags, &eflagsbuf } , &oldContext.EFlags,&StoppedRegs.EFlags,0,editable },
   { { &floatingname, 0 }, 0, 0, 0, } ,
   { { &xst0, &st0buf } , &oldContext.FloatSave.RegisterArea[0], &StoppedRegs.FloatSave.RegisterArea[0],0,editable | floating },
   { { &xst1, &st1buf } , &oldContext.FloatSave.RegisterArea[10], &StoppedRegs.FloatSave.RegisterArea[10],0,editable | floating },
   { { &xst2, &st2buf } , &oldContext.FloatSave.RegisterArea[20], &StoppedRegs.FloatSave.RegisterArea[20],0,editable | floating },
   { { &xst3, &st3buf } , &oldContext.FloatSave.RegisterArea[30], &StoppedRegs.FloatSave.RegisterArea[30],0,editable | floating },
   { { &xst4, &st4buf } , &oldContext.FloatSave.RegisterArea[40], &StoppedRegs.FloatSave.RegisterArea[40],0,editable | floating },
   { { &xst5, &st5buf } , &oldContext.FloatSave.RegisterArea[50], &StoppedRegs.FloatSave.RegisterArea[50],0,editable | floating },
   { { &xst6, &st6buf } , &oldContext.FloatSave.RegisterArea[60], &StoppedRegs.FloatSave.RegisterArea[60],0,editable | floating },
   { { &xst7, &st7buf } , &oldContext.FloatSave.RegisterArea[70], &StoppedRegs.FloatSave.RegisterArea[70],0,editable | floating },
} ;     

static TCHeader tch = { "Register", "Value", 0, 0 } ;
static int drawn ;
void SaveRegisterContext(void)
{	
   memcpy(&oldContext,&StoppedRegs,sizeof(CONTEXT)) ;
}
LRESULT  CALLBACK _export RegisterProc( HWND hwnd, UINT iMessage, WPARAM wParam,
																		LPARAM lParam)
{
	static int charwidth ;
	HDC dc ;
	TEXTMETRIC metric ;
	DEBUG_EVENT *xc ;
	HFONT oldFont ;
	LOGBRUSH brushstr ;
   RECT r ;
   int i ;
   NM_TREEVIEW *nmt ;
	switch(iMessage) {
      case WM_NOTIFY:
         nmt = (NM_TREEVIEW *)lParam ;
         switch(nmt->hdr.code) {
            case TCN_EDITQUERY:
               if (uState != atBreakpoint)
                  return 0 ;
               for (i=0; i < sizeof(regs)/ sizeof(REGDATA); i++)
                  if (regs[i].hTreeItem == nmt->itemNew.hItem)
                     if (regs[i].flags & editable)
                        return (LRESULT) regs[i].ptrs.col2Text ;
               return 0 ;
            case TCN_EDITDONE:
               for (i=0; i < sizeof(regs)/ sizeof(REGDATA); i++)
                  if (regs[i].hTreeItem == nmt->itemNew.hItem) {
                     char *buf = (char *)nmt->itemNew.pszText ;
                     if (regs[i].flags & floating) {
                        float val ;
                        int pos = regs[i].currentdataptr ;
                        sscanf(buf,"%f",&val) ;
                        asm fld dword ptr [val] ;
                        asm mov eax,[pos]
                        asm fstp tbyte ptr [eax]
                        sprintf(regs[i].ptrs.col2Text,"%f",(double)val) ;
                     } else {
                        if (buf[0] == '0' && buf[1] == 'x')
                           sscanf(buf+2,"%x",regs[i].currentdataptr) ;
                        else
                           sscanf(buf,"%d",regs[i].currentdataptr) ;
                        sprintf(regs[i].ptrs.col2Text,"0x%08x",*regs[i].currentdataptr) ;
                     }
                     regs[i].ptrs.col2Color = 0xff ;
                  }
               return 0 ;
         }
         break ;
		case WM_SYSCOMMAND :
			if (wParam == SC_CLOSE)
				SendMessage(hwnd,WM_CLOSE,0,0) ;
			break ;
		case WM_COMMAND:
			switch(LOWORD(wParam)) {
            case ID_SETCONTEXT:
               SaveRegisterContext() ;
               break ;
				case ID_SETADDRESS:
					registerHandle = (HANDLE)lParam ;
               if (lParam) {
                  int i ;
                  for (i=0; i < sizeof(regs)/sizeof(REGDATA); i++)
                     if (regs[i].currentdataptr)  {
                        if (regs[i].flags & floating) {
                           double val ;
                           int pos = regs[i].currentdataptr ;
                           asm mov eax,[pos]
                           asm fld tbyte ptr [eax] 
                           asm fstp qword ptr [val]
                           sprintf(regs[i].ptrs.col2Text,"%f",val) ;
                           if (!memcmp(regs[i].currentdataptr,regs[i].olddataptr,10)) 
                              regs[i].ptrs.col2Color = 0 ;
                           else
                              regs[i].ptrs.col2Color = 0xff ;
                        } else {
                           sprintf(regs[i].ptrs.col2Text,"0x%08x",*regs[i].currentdataptr) ;
                           if (*regs[i].currentdataptr == *regs[i].olddataptr)
                              regs[i].ptrs.col2Color = 0 ;
                           else
                              regs[i].ptrs.col2Color = 0xff ;
                        }
                     }
                  if (!drawn) {
                     HTREEITEM after1=0,after2 = 0 ;
                     for (i=0; i < sizeof(regs)/sizeof(REGDATA); i++) {
                        TV_INSERTSTRUCT t;
                        memset(&t,0,sizeof(t)) ;
                        t.hParent = regs[i].currentdataptr ? after1 : 0 ;
                        t.hInsertAfter = regs[i].currentdataptr ? after2 : after1 ;
                        t.item.mask = 0;
                        t.item.hItem = 0; 
                        t.item.lParam = (int)&regs[i].ptrs;
                        regs[i].hTreeItem =  TreeView_InsertItem(hwndTree,&t) ;
                        if (!regs[i].currentdataptr) {
                           after1 = regs[i].hTreeItem ;
                           after2 = 0 ;
                        } else
                           after2 = regs[i].hTreeItem ;
                     }   
                     drawn = TRUE ;
                  }
               } else if (!lParam && drawn) {
                  TreeView_DeleteAllItems(hwndTree) ;
                  drawn = FALSE ;
               }
               InvalidateRect(hwndTree,0,0) ;
					break ;
				default:
					return DefMDIChildProc(hwnd,iMessage,wParam,lParam) ;
			}
			break ;
		case WM_SETFOCUS:
			break ;
		case WM_KILLFOCUS:
			break ;
		case WM_LBUTTONDOWN:
			break ;
		case WM_CREATE:
			hwndRegister = hwnd ;
         GetClientRect(hwnd,&r) ;
//         valueBitmap = LoadBitmap(hInstance, "ID_VALUEBMP") ;
//         itemBitmap = LoadBitmap(hInstance, "ID_ITEMBMP") ;
         tch.colBmp1 = itemBitmap ;
         tch.colBmp2 = valueBitmap ;
         hwndTree = CreateextTreeWindow(hwnd,TCS_LINE,&r,&tch);
         break ;
				
		case WM_CLOSE:
			break ;
		case WM_DESTROY:
         DestroyWindow(hwndTree) ;
//         DeleteObject(itemBitmap) ;
//         DeleteObject(valueBitmap) ;
			hwndRegister = 0 ;
			registerHandle = 0 ;
			break ;
		case WM_SIZE:       
         MoveWindow(hwndTree,0,0,LOWORD(lParam),HIWORD(lParam),1) ;
			break ;
		case WM_INITMENUPOPUP:
         break ;
		default: 
			break ;
	}
	return DefMDIChildProc(hwnd,iMessage,wParam,lParam) ;
}
void RegisterRegisterWindow(void)
{
		WNDCLASS wc ;
      memset(&wc,0,sizeof(wc)) ;
      wc.style = 0;
		wc.lpfnWndProc = &RegisterProc ;
		wc.cbClsExtra = 0;
		wc.cbWndExtra = 0;
		wc.hInstance = hInstance ;
		wc.hIcon = LoadIcon(0,IDI_APPLICATION) ;
		wc.hCursor = LoadCursor(0,IDC_ARROW) ;
		wc.hbrBackground = GetStockObject(WHITE_BRUSH) ;
		wc.lpszMenuName = 0 ;
		wc.lpszClassName = szRegisterClassName ;
		RegisterClass(&wc) ;
}
HWND CreateRegisterWindow(DEBUG_EVENT *dbe, HWND parent)
{
	MDICREATESTRUCT mc ;
	HWND rv ;
   RECT rect ;
   if (hwndRegister)
		return hwndRegister ;
   GetTabRect(&rect) ;
   hwndRegister = CreateWindow( szRegisterClassName, szRegisterTitle,
         WS_VISIBLE | WS_CHILD | WS_BORDER,
         rect.left,                               
         rect.top,
         rect.right-rect.left,
         rect.bottom-rect.top, parent, 0 ,hInstance, 0) ;

   return hwndRegister ;
}
