/*------------------------------------------------------------------------*/
/*                                                                        */
/*  Copyright (c) 2008 by MESA Imaging SA,                                */
/*                     http://www.mesa-imaging.ch                         */
/*------------------------------------------------------------------------*/
// $Author$
//    $URL$
//    $Rev$
//   $Date$
/*------------------------------------------------------------------------*/
//!\file
//!Example Win32 application
#pragma once

#include "resource.h"
#include "PreciseTimer.h"
#include "libMesaSR.h"
#pragma comment( lib, "libMesaSR" )

//!\addtogroup swissRangerSampleGui
//!@{

//!returns the instance handle of the executable
HINSTANCE AfxGetInstanceHandle();

//! About dialog window for SwissRangerSampleGui
class CDlgAbout
{
public:
  CDlgAbout():_hWnd(0){}
  ~CDlgAbout(){}
  INT_PTR DoModal(HINSTANCE hInstance, HWND hParentWnd);
private:
  static BOOL CALLBACK SWindowProc(HWND hDlg, UINT message, WPARAM wP, LPARAM lParam);
#pragma warning(disable : 4312)  //64 bit Portability Warning
  static inline CDlgAbout *GetObjectFromWindow(HWND hWnd){return(CDlgAbout*)GetWindowLong(hWnd, GWL_USERDATA);}//!<gets the object pointer from a window handle
#pragma warning(default : 4312)
  BOOL CALLBACK WindowProc(HWND hDlg, UINT message, WPARAM wP, LPARAM lParam);
  void OnInitialUpdate(){}//!<When the window is created this function will be called
  HWND _hWnd;//!<window handle
};


class CWndSwissranger;
//! This is the camera thread class for SwissRangerSampleGui.\n
//! it is used to allow acquisition,display and simultanious user interactions.
//! Detail Description
class CCameraThread
{
public:
  CCameraThread():_stop(true),_hThread(0){}
  ~CCameraThread(){Stop(10000);}
  void Run(CWndSwissranger* srWnd);
  void Stop(DWORD timeout=INFINITE);
  bool IsRunning(){return !_stop;}//!< tests if thread is running
private:
  static DWORD WINAPI SCameraLoop(LPVOID lpV) {return((CCameraThread*)lpV)->CameraLoop();}//!<redirects the call from this static function to the method CameraLoop
  DWORD WINAPI CameraLoop();

  HANDLE _hThread;         //!<handle to the running thread
  CWndSwissranger* _srWnd; //!<pointer to the CWndSwissranger window, that owns this class
  bool _stop;              //!<boolean that indicates that the thread should stop
};

//! Main Application window for SwissRangerSampleGui
class CWndSwissranger
{
public:
  CWndSwissranger();
  ~CWndSwissranger();
  void Create(HINSTANCE hInstance, HWND hParentWnd);
  void Acquire();
private:
  void Free();
  void Initialize();
  ATOM RegisterClass(HINSTANCE hInstance);
  HWND HWnd();
  static BOOL CALLBACK SWindowProc(HWND hDlg, UINT message, WPARAM wP, LPARAM lParam);
#pragma warning(disable : 4312)  //64 bit Portability Warning
  static inline CWndSwissranger *GetObjectFromWindow(HWND hWnd){return(CWndSwissranger*)GetWindowLong(hWnd, GWL_USERDATA);}//!<gets the object pointer from a window handle
#pragma warning(default : 4312)
  BOOL CALLBACK WindowProc(HWND hDlg, UINT message, WPARAM wP, LPARAM lParam);
  void OnInitialUpdate();

  static int SSRFuncCB(SRCAM srCam, unsigned int msg, unsigned int param, void* data);
  int SRFuncCB(SRCAM srCam, unsigned int msg, unsigned int param, void* data);

  void OnCloseDev();
  void OnOpenDlg(int mode);
  void OnPaint();
  void SetColorLim(int idx);
  void SetMode(int mode);

  void SetDib();
  float Rctngl(int PositionAreaX,int PositionAreaY, int SizeArea, int img); 
  void AllocObj();
  HWND _hWnd;                     //!<window handle
  static const TCHAR* _wndClass;  //!<window class name
  static const TCHAR* _wndTitle;  //!<window title string

  float        *_z;               //!<z valzes when _coordTrf is activated
  BITMAPINFO   *_bmiCam;          //!<bitmap infos structure for the camera images (bmis are 32bit)
  BITMAPINFO   *_bmiScale;        //!<bitmap infos structure for the scale bar and the camera images (bmis are 32bit)
  RGBQUAD      *_dibCam;          //!<DIB for the camera image
  BYTE         *_dibScale;        //!<DIB for the scale image
  SIZE          _imgSz;           //!<size of the image
  float         _timePerFrame;    //!<time per frame
  ImgEntry     *_imgEntryArray;   //!<image entry array
  int           _numImg;          //!<number of images
  bool          _coordTrf;        //!<true is coordinate transformation must be calculated
  int           _acquMode;         //!<acquisition mode

  float _minVal[8];               //!<minimal color values for up to 8 images
  float _maxVal[8];               //!<maximal color values for up to 8 images

  SRCAM _srCam;                   //!<handle to the swissranger camers
  CCameraThread _camThread;       //!<camera thread instance
  void EnterCritSec(){EnterCriticalSection(&_cs);}//!<entering the critical section
  void LeaveCritSec(){LeaveCriticalSection(&_cs);}//!<leaving the critical section
  CRITICAL_SECTION _cs;                //!<the critical section
  static CWndSwissranger* _cbInstance; //!<the CWndSwissranger instance where the callback is sent to
};

//!@} swissRangerSampleGui
//------------------------------ inline functions ------------------------------
//! opends the About dialog box
__inline INT_PTR CDlgAbout::DoModal(HINSTANCE hInstance, HWND hParentWnd)
{
    return DialogBoxParam(hInstance, (LPCTSTR)IDD_ABOUTBOX, hParentWnd, (DLGPROC)SWindowProc,(LPARAM)this);
}

//!creates a camera thread and starts the function CameraLoop
void __inline CCameraThread::Run(CWndSwissranger* srWnd)
{
  Stop();
  DWORD dwReadStatId;
  _stop=false;
  _srWnd=srWnd;
  _hThread =  CreateThread( 0, 0, SCameraLoop,(LPVOID)this, 0, &dwReadStatId);
}

//!Stops the CameraLoop and returns when the thread is really finished
void __inline CCameraThread::Stop(DWORD timeout)
{
  if(_hThread)
  {
    _stop=true;                 //force thread to stop
    WaitForSingleObject(_hThread,timeout);
    CloseHandle(_hThread);
    _hThread=0;
  }
}

//!returns the window handle
__inline HWND CWndSwissranger::HWnd()
{
  return _hWnd;
}

//! CWndSwissranger constructor: calls Initialize() and initializes the critical section
__inline CWndSwissranger::CWndSwissranger():_hWnd(0),_z(0),_dibScale(0),_dibCam(0),_srCam(0),_timePerFrame(.02f)
{
  Initialize();
  InitializeCriticalSection(&_cs);
  ASSERT(_cbInstance==0);//multiple instances not yet supported. SSRFuncCB must be changed
  _cbInstance=this;
  SR_SetCallback(SSRFuncCB);
}

//! CWndSwissranger destructor: calls Free and deletes the critical section
__inline CWndSwissranger::~CWndSwissranger()
{
  Free();
  DeleteCriticalSection(&_cs);
  _cbInstance=0;
  SR_SetCallback(SR_GetDefaultCallback());
}

//!Creates the window and displays it
__inline void CWndSwissranger::Create(HINSTANCE hInstance, HWND hParentWnd)
{
  _hWnd=CreateDialogParam(hInstance, MAKEINTRESOURCE(IDD_SWISSRANGERSAMPLE), hParentWnd, SWindowProc,(LPARAM)this);
  SetWindowPos(_hWnd, 0, 340, 20, 0,0, SWP_NOZORDER|SWP_NOSIZE);

  char buf[256];
  int len;

  unsigned short version[4];
  if(!SR_GetVersion(version))
  {
    printf("Version %d.%d.%d.%d\n",version[3],version[2],version[1],version[0]);
    len=GetWindowText(_hWnd,buf,_countof(buf));
    _snprintf(&buf[len],_countof(buf)-len," %d.%d.%d.%d",version[3],version[2],version[1],version[0]);
    SetWindowText(_hWnd,buf);
  }
  ShowWindow(_hWnd,SW_SHOW);
}

