#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

#include "resource.h"

#include "CU30Wrap.h"
#include "commctrl.h"

extern HINSTANCE hInst;								// current instance
extern void OpenEpromPanel (HWND hWnd, DWORD USBInstance,DWORD USBVersion,DWORD DevID,DWORD EEID);
void show_hide(HWND hDlg);
int CurrentEEID(HWND hWnd);

typedef struct delphiDevRec
{
  DWORD USBInstance;
  DWORD USBVersion;
  DWORD DevID;
  DWORD EEID;
} DeviceRec;
typedef struct stat
{
  BOOL Connected;
  BOOL DCDCOn;
  BOOL UseSteps;
  int Steps;
  int Velocity;
} HARDWARE_STATUS;
#define MAX_H 16
HARDWARE_STATUS Stats[MAX_H];

BOOL UseSteps = TRUE; // determines whether to use CU30Step or CU30Sweep function
int steps = 100;
int maxVelocity = 255;
int minVelocity = 1;
int maxSteps = 32640;
int minSteps = -32768;
HWND sOnx;
HHOOK HookHandle=NULL;

DeviceRec ddr;
void ResetStats()
{
  int i;
  for(i=0;i<MAX_H;i++)
  {
    Stats[i].Connected = FALSE;
    Stats[i].DCDCOn = TRUE;
    Stats[i].UseSteps = TRUE;
    Stats[i].Velocity = 10;
    Stats[i].Steps = 100;
  }
}        
void CloseAll()
{
  int i;
  for(i=0;i<MAX_H;i++)
  {    
    ddr.EEID = i;    
    CU30WClose(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
    Stats[i].Connected = FALSE;    
  }
  ddr.EEID = -1;
}
void CheckStats()
{
  int i;
  char * refStr;
  int currid = ddr.EEID;
  int firstE = -1;
  for(i=0;i<MAX_H;i++)
  {    
    ddr.EEID = i;    
    //CU30WClose(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
    refStr = CU30WOpen(&ddr.USBInstance,&ddr.USBVersion,&ddr.DevID,&ddr.EEID);
    if((refStr!=NULL)&&(refStr[0]!='\0'))//&&i!=3&&i!=5)
    {
      Stats[i].Connected = FALSE;    
    } 
    else
    {
      if(Stats[i].Connected == FALSE)
      {
        CU30WDCDCon(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
        Stats[i].Connected = TRUE;
        Stats[i].DCDCOn = TRUE; 
      }
      if(firstE == -1)
        firstE = i;
    }                
  }
  if(Stats[currid].Connected == FALSE)
    currid = firstE;
  ddr.EEID = currid;
}
void VisualizeStats(HWND hDlg)
{
  int i;
  for(i=0;i<MAX_H;i++)
  {    
    if(Stats[i].Connected == FALSE)
      EnableWindow(GetDlgItem(hDlg, IDC_RADIO1+i),FALSE);
    else
      EnableWindow(GetDlgItem(hDlg, IDC_RADIO1+i),TRUE);          
  }  
}
void ActivateIth(HWND hDlg)
{
  int i;
  if(ddr.EEID == -1)
    return;
  CheckDlgButton(hDlg,IDC_DCON,Stats[ddr.EEID].DCDCOn?BST_CHECKED:BST_UNCHECKED); 
  CheckDlgButton(hDlg,IDC_DCOFF,Stats[ddr.EEID].DCDCOn?BST_UNCHECKED:BST_CHECKED); 
  CheckDlgButton(hDlg,IDC_CHECK1,Stats[ddr.EEID].UseSteps?BST_CHECKED:BST_UNCHECKED); 
  for(i=0;i<MAX_H;i++)
    CheckDlgButton(hDlg,IDC_RADIO1 + i ,BST_UNCHECKED); 
  CheckDlgButton(hDlg,IDC_RADIO1 + ddr.EEID ,BST_CHECKED); 
  UseSteps = IsDlgButtonChecked(hDlg,IDC_CHECK1);
  show_hide(hDlg);
  SetDlgItemInt(hDlg,IDC_EDIT1,Stats[ddr.EEID].Steps,TRUE);
  SetDlgItemInt(hDlg,IDC_EDIT3,Stats[ddr.EEID].Velocity,FALSE);
}
void CollectStats(HWND hDlg)
{  
  BOOL to;  
  if(ddr.EEID == -1)
    return;
  Stats[ddr.EEID].DCDCOn = IsDlgButtonChecked(hDlg,IDC_DCON);
  Stats[ddr.EEID].UseSteps = IsDlgButtonChecked(hDlg,IDC_CHECK1);    
  Stats[ddr.EEID].Steps = GetDlgItemInt(hDlg,IDC_EDIT1,&to,TRUE);
  Stats[ddr.EEID].Velocity = GetDlgItemInt(hDlg,IDC_EDIT3,&to,FALSE);
      
}
void removeBMP(HWND hDlg,HINSTANCE hInst, UINT ID, UINT BMP_ID)
{
  HANDLE APrevious=(HANDLE)SendDlgItemMessage(hDlg,ID,BM_SETIMAGE,IMAGE_BITMAP,(LPARAM)NULL); 
  if(APrevious)
    DeleteObject(APrevious);
}
void addBMP(HWND hDlg,HINSTANCE hInst, UINT ID, UINT BMP_ID)
{
  
  HWND hTmp=GetDlgItem(hDlg,ID);
  if(!hTmp)
    return; 
  
  HANDLE uBmp=LoadImage(hInst,(LPCTSTR)BMP_ID,
	                    IMAGE_BITMAP,0,0,LR_DEFAULTCOLOR);
  if(!uBmp)
	  return;
  BITMAP bmp;     
  if (GetObject(uBmp, sizeof(BITMAP), (LPSTR)&bmp)) 
  {
	  RECT Rect;
    HWND hW=GetDlgItem(hDlg,ID);
	  GetWindowRect(hW,&Rect);
	  POINT me;
	  me.x=Rect.left;
	  me.y=Rect.top;
	  ScreenToClient(hDlg,&me);
    if(MoveWindow(hW,me.x,me.y,bmp.bmWidth+1,bmp.bmHeight+1,TRUE))
	  {
	  }
  }
  HANDLE APrevious=(HANDLE)SendDlgItemMessage(hDlg,ID,BM_SETIMAGE,IMAGE_BITMAP,(LPARAM)uBmp); 
  if(APrevious)
    DeleteObject(APrevious);    
} 
void show_hide(HWND hDlg)
{
    ShowWindow(GetDlgItem(hDlg,IDC_EDIT1),UseSteps?SW_SHOW:SW_HIDE);
    ShowWindow(GetDlgItem(hDlg,IDC_SPIN1),UseSteps?SW_SHOW:SW_HIDE);
    ShowWindow(GetDlgItem(hDlg,IDD_STEPS1),UseSteps?SW_SHOW:SW_HIDE);
    ShowWindow(GetDlgItem(hDlg,IDD_STEPS2),UseSteps?SW_SHOW:SW_HIDE);
}
int CurrentEEID(HWND hWnd)
{
  if(IsDlgButtonChecked(hWnd,IDC_RADIO1))  return 0;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO2))  return 1;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO3))  return 2;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO4))  return 3;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO5))  return 4;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO6))  return 5;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO7))  return 6;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO8))  return 7;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO9))  return 8;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO10)) return 9;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO11)) return 10;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO12)) return 11;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO13)) return 12;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO14)) return 13;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO15)) return 14;
  if(IsDlgButtonChecked(hWnd,IDC_RADIO16)) return 15;
  return -1;
}
NMHDR nmHdr;
int CALLBACK GHooker(int code, WPARAM wParam, LPARAM lParam)
{
  MSG * poCW=(MSG *)lParam; 
  int ID = 0;
  HWND Parent=GetParent(poCW->hwnd);
  if(sOnx!=NULL)
  {
    if(Parent==sOnx)
    {
        if(poCW->hwnd== GetDlgItem(sOnx,IDB_XMINUS))
            ID = IDB_XMINUS;
        if(poCW->hwnd== GetDlgItem(sOnx,IDB_XPLUS))
            ID = IDB_XPLUS;
        if(poCW->hwnd== GetDlgItem(sOnx,IDB_YMINUS))
            ID = IDB_YMINUS;
        if(poCW->hwnd== GetDlgItem(sOnx,IDB_YPLUS))
            ID = IDB_YPLUS;
        if(poCW->hwnd== GetDlgItem(sOnx,IDB_ZMINUS))
            ID = IDB_ZMINUS;
        if(poCW->hwnd== GetDlgItem(sOnx,IDB_ZPLUS)) 
            ID = IDB_ZPLUS;
    }
    switch(poCW->message)
    {
       case WM_LBUTTONDOWN:
         SendMessage(sOnx,WM_COMMAND,MAKELONG(ID,0xfa),0l);
       break;
       case WM_LBUTTONUP:
         SendMessage(sOnx,WM_COMMAND,MAKELONG(ID,0xfb),0l);
       break;
     }
  }    
  return CallNextHookEx(HookHandle,code,wParam,lParam);
}

// Mesage handler for the dialog box.
LRESULT CALLBACK tPanel(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  int steps_v;
  int vel_v;
  BOOL to;
  BOOL lDown;
  BOOL lUp;
  switch (message)
	{
		case WM_INITDIALOG:
		    ResetStats();
        addBMP(hDlg,hInst,IDB_XMINUS,IDB_XMINUS);
        addBMP(hDlg,hInst,IDB_YMINUS,IDB_YMINUS);
        addBMP(hDlg,hInst,IDB_ZMINUS,IDB_ZMINUS);
        addBMP(hDlg,hInst,IDB_XPLUS,IDB_XPLUS);
        addBMP(hDlg,hInst,IDB_YPLUS,IDB_YPLUS);
        addBMP(hDlg,hInst,IDB_ZPLUS,IDB_ZPLUS);
        addBMP(hDlg,hInst,IDB_XMINUS4,IDB_BITMAP3);
        addBMP(hDlg,hInst,IDB_XMINUS3,IDB_BITMAP3);
        addBMP(hDlg,hInst,IDB_XMINUS2,IDB_BITMAP2);        
        SendDlgItemMessage(hDlg,IDC_SPIN1,UDM_SETRANGE,0,(LPARAM)MAKELONG(maxSteps,minSteps));
        SendDlgItemMessage(hDlg,IDC_SPIN2,UDM_SETRANGE,0,(LPARAM)MAKELONG(maxVelocity,minVelocity));
      
        sOnx=hDlg;
         
        ddr.DevID = 1;
        ddr.EEID = 0;
        ddr.USBInstance = 0;
        ddr.USBVersion = 1;
        SetDlgItemInt(hDlg,IDC_EDIT1,steps,TRUE);
        SetDlgItemInt(hDlg,IDC_EDIT3,10,FALSE);
        CheckStats();
        ActivateIth(hDlg);
        VisualizeStats(hDlg);
    return TRUE;  
    case WM_COMMAND:			
      steps_v = GetDlgItemInt(hDlg,IDC_EDIT1,&to,TRUE);
      vel_v = GetDlgItemInt(hDlg,IDC_EDIT3,&to,FALSE);
      lDown = (HIWORD(wParam) == 0xfa);
      lUp   = (HIWORD(wParam) == 0xfb);
      switch(LOWORD(wParam))
      {
          case IDTEST:
            CloseAll();
            CU30WrapperDispose();
            CU30WrapperInit();
            ResetStats();
            ddr.DevID = 1;
            ddr.EEID = 0;
            ddr.USBInstance = 0;
            ddr.USBVersion = 1;        
            CheckStats();
            ActivateIth(hDlg);
            VisualizeStats(hDlg);
          break;
          case IDC_RADIO1:
          case IDC_RADIO2:
          case IDC_RADIO3:
          case IDC_RADIO4:
          case IDC_RADIO5:
          case IDC_RADIO6:
          case IDC_RADIO7:
          case IDC_RADIO8:
          case IDC_RADIO9:
          case IDC_RADIO10:
          case IDC_RADIO11:
          case IDC_RADIO12:
          case IDC_RADIO13:
          case IDC_RADIO14:
          case IDC_RADIO15:
          case IDC_RADIO16:
            CollectStats(hDlg);
            ddr.EEID = CurrentEEID(hDlg);
            ActivateIth(hDlg);            
          break;      
          case IDC_DCON:
          case IDC_DCOFF:
            if(IsDlgButtonChecked(hDlg,IDC_DCON))
              CU30WDCDCon(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
            else              
              CU30WDCDCoff(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
          break;
          case IDC_CHECK1:
            UseSteps = IsDlgButtonChecked(hDlg,IDC_CHECK1);
            show_hide(hDlg);
          break;          
          case IDB_XMINUS:
            if(UseSteps)
            {
              if(!lDown&&!lUp)
                CU30WStep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,1,-steps_v,vel_v);
            }
            else
            {
              if(lUp)
                CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
              if(lDown)
                CU30WSweep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,-vel_v,1,0);
            }
          break;
          case IDB_XPLUS:
            if(UseSteps)
            {
              if(!lDown&&!lUp)
                CU30WStep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,1,steps_v,vel_v);
            }
            else
            {
              if(lUp)
                CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
              if(lDown)
                CU30WSweep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,vel_v,1,0);
            }
          break;
          case IDB_YMINUS:
            if(UseSteps)
            {
			  if(!lDown&&!lUp)
				 CU30WStep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,2,-steps_v,vel_v);             
            }
            else
            {
              if(lUp)
                CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
              if(lDown)
                CU30WSweep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,-vel_v,2,0); 
            }
          break;
          case IDB_YPLUS:
            if(UseSteps)
            {
              if(!lDown&&!lUp)
                CU30WStep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,2, steps_v,vel_v);             
            }
            else
            {
              if(lUp)
                CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
              if(lDown)
                CU30WSweep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,vel_v,2,0); 
            }
          break;
          case IDB_ZMINUS:
            if(UseSteps)
            {
              if(!lDown&&!lUp)
                CU30WStep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,3,-steps_v,vel_v);             
            }
            else
            {
              if(lUp)
                CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
              if(lDown)
                CU30WSweep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,-vel_v,3,0); 
            }
          break;
          case IDB_ZPLUS:
            if(UseSteps)
            {
              if(!lDown&&!lUp)
                CU30WStep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,3, steps_v,vel_v);             
            }
            else
            {
              if(lUp)
                CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
              if(lDown)
                CU30WSweep(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID,vel_v,3,0);               
            }
          break;       
          case IDB_XMINUS2: // stop
             CU30WStop(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
          break;  
          case IDINFO:
             // Display of additional info panel with the data,
             // collected from GetUSBEEPromInfo()
             if(ddr.EEID == -1 || Stats[ddr.EEID].Connected == FALSE)
                break; 
             OpenEpromPanel (hDlg, ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
          break;       
          case IDC_EDIT1:
             if(HIWORD(wParam) == EN_KILLFOCUS)
             {
                  int curVal = GetDlgItemInt(hDlg,IDC_EDIT1,&to,TRUE);
                  if(curVal < minSteps)
                    curVal = minSteps;
                  if(curVal > maxSteps)
                    curVal = maxSteps;
                  SetDlgItemInt(hDlg,IDC_EDIT1,curVal,TRUE);
              }
          break;
          case IDC_EDIT3:
             if(HIWORD(wParam) == EN_KILLFOCUS)
             {
                  int curVal = GetDlgItemInt(hDlg,IDC_EDIT3,&to,TRUE);
                  if(curVal < minVelocity)
                    curVal = minVelocity;
                  if(curVal > maxVelocity)
                    curVal = maxVelocity;
                  SetDlgItemInt(hDlg,IDC_EDIT3,curVal,FALSE);
              }
          break;
      }
      if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) 
			{
				removeBMP(hDlg,hInst,IDB_XMINUS,IDB_XMINUS);
        removeBMP(hDlg,hInst,IDB_YMINUS,IDB_YMINUS);
        removeBMP(hDlg,hInst,IDB_ZMINUS,IDB_ZMINUS);
        removeBMP(hDlg,hInst,IDB_XPLUS,IDB_XPLUS);
        removeBMP(hDlg,hInst,IDB_YPLUS,IDB_YPLUS);
        removeBMP(hDlg,hInst,IDB_ZPLUS,IDB_ZPLUS);
        removeBMP(hDlg,hInst,IDB_XMINUS4,IDB_BITMAP2);
        removeBMP(hDlg,hInst,IDB_XMINUS3,IDB_BITMAP2);
        removeBMP(hDlg,hInst,IDB_XMINUS2,IDB_BITMAP2); 
        CU30WDCDCoff(ddr.USBInstance,ddr.USBVersion,ddr.DevID,ddr.EEID);
        EndDialog(hDlg, LOWORD(wParam));
				return TRUE;
			}
      
			break;
	}
    return FALSE;
}


void OpenPanel (HWND hWnd)
{
    InitCommonControls(); 
    HookHandle = SetWindowsHookEx(WH_GETMESSAGE, (HOOKPROC) GHooker, 
      (HINSTANCE)NULL, (DWORD)GetCurrentThreadId());
    DialogBox(hInst, (LPCTSTR)IDD_DIALOG1, NULL, (DLGPROC)tPanel);
    UnhookWindowsHookEx(HookHandle);
    sOnx=NULL;
    HookHandle=NULL;     
}