#ifndef __toupcam_h__
#define __toupcam_h__

#ifdef _WIN32
#ifndef _INC_WINDOWS
#include <windows.h>
#endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

#ifdef _WIN32

#pragma pack(push, 8)
#ifdef TOUPCAM_EXPORTS
#define toupcam_ports(x)    __declspec(dllexport)   x   __stdcall
#elif !defined(TOUPCAM_NOIMPORTS)
#define toupcam_ports(x)    __declspec(dllimport)   x   __stdcall
#pragma comment(lib, "toupcam.lib")
#else
#define toupcam_ports(x)    x   __stdcall
#endif

#else

#define toupcam_ports(x)    x

#ifndef HRESULT
#define HRESULT int
#endif

#ifndef __stdcall
#define __stdcall
#endif

#ifndef CALLBACK
#define CALLBACK
#endif

#ifndef BOOL
#define BOOL int
#endif

#ifndef __BITMAPINFOHEADER_DEFINED__
#define __BITMAPINFOHEADER_DEFINED__
typedef struct {
    unsigned        biSize;
    int             biWidth;
    int             biHeight;
    unsigned short  biPlanes;
    unsigned short  biBitCount;
    unsigned        biCompression;
    unsigned        biSizeImage;
    int             biXPelsPerMeter;
    int             biYPelsPerMeter;
    unsigned        biClrUsed;
    unsigned        biClrImportant;
} BITMAPINFOHEADER;
#endif

#ifndef __RECT_DEFINED__
#define __RECT_DEFINED__
typedef struct {
    int left;
    int top;
    int right;
    int bottom;
} RECT, *PRECT;
#endif

#endif

/* handle */
typedef struct ToupcamT { int unused; } *HToupCam;

#define TOUPCAM_MAX                     16

#define TOUPCAM_FLAG_CMOS               0x0001  /* cmos sensor */
#define TOUPCAM_FLAG_CCD_PROGRESSIVE    0x0002  /* progressive ccd sensor */
#define TOUPCAM_FLAG_CCD_INTERLACED     0x0004  /* interlaced ccd sensor */
#define TOUPCAM_FLAG_MONO               0x0010  /* monochromatic */
#define TOUPCAM_FLAG_BINSKIP_SUPPORTED  0x0020  /* support bin/skip mode, see Toupcam_put_Mode and Toupcam_get_Mode */
#define TOUPCAM_FLAG_USB30              0x0040  /* USB 3.0 */
#define TOUPCAM_FLAG_COOLED             0x0080  /* Cooled */
#define TOUPCAM_FLAG_USB30_OVER_USB20   0x0100  /* usb3.0 camera connected to usb2.0 port */

typedef struct{
    unsigned    width;
    unsigned    height;
}ToupcamResolution;

typedef struct{
#ifdef _WIN32
    const wchar_t*      name;       /* model name */
#else
    const char*         name;
#endif
    unsigned            flag;       /* TOUPCAM_FLAG_xxx */
    unsigned            maxspeed;   /* number of speed level, Toupcam_get_MaxSpeed, the speed range = [0, max], closed interval */
    unsigned            preview;    /* number of preview resolution, Toupcam_get_ResolutionNumber */
    unsigned            still;      /* number of still resolution, Toupcam_get_StillResolutionNumber */
    ToupcamResolution   res[TOUPCAM_MAX];
}ToupcamModel;

typedef struct{
#ifdef _WIN32
    wchar_t             displayname[64];    /* display name */
    wchar_t             id[64];     /* unique id, for Toupcam_Open */
#else
    char                displayname[64];    /* display name */
    char                id[64];     /* unique id, for Toupcam_Open */
#endif
    const ToupcamModel* model;
}ToupcamInst;

/*
    enumerate the cameras connected to the computer, return the number of enumerated.

    ToupcamInst arr[TOUPCAM_MAX];
    unsigned cnt = Toupcam_Enum(arr);
    for (unsigned i = 0; i < cnt; ++i)
        ...

    if pti == NULL, then, only the number is returned.
*/
toupcam_ports(unsigned) Toupcam_Enum(ToupcamInst pti[TOUPCAM_MAX]);

/* use the id of ToupcamInst, which is enumerated by Toupcam_Enum.
    if id is NULL, Toupcam_Open will open the first camera.
*/
#ifdef _WIN32
toupcam_ports(HToupCam) Toupcam_Open(const wchar_t* id);
#else
toupcam_ports(HToupCam) Toupcam_Open(const char* id);
#endif

/*
    the same with Toupcam_Open, but use the index as the parameter. such as:
    index == 0, open the first camera,
    index == 1, open the second camera,
    etc
*/
toupcam_ports(HToupCam) Toupcam_OpenByIndex(unsigned index);

toupcam_ports(void)     Toupcam_Close(HToupCam h); /* close the handle */

#define TOUPCAM_EVENT_EXPOSURE      0x01    /* exposure time changed */
#define TOUPCAM_EVENT_TEMPTINT      0x02    /* white balance changed */
#define TOUPCAM_EVENT_CHROME        0x03    /* reversed, do not use it */
#define TOUPCAM_EVENT_IMAGE         0x04    /* live image arrived, use Toupcam_PullImage to get this image */
#define TOUPCAM_EVENT_STILLIMAGE    0x05    /* snap (still) frame arrived, use Toupcam_PullStillImage to get this frame */
#define TOUPCAM_EVENT_ERROR         0x80    /* somthing error happens */

#ifdef _WIN32
toupcam_ports(HRESULT)      Toupcam_StartPullModeWithWndMsg(HToupCam h, HWND hWnd, UINT nMsg);
#endif

typedef void (__stdcall*    PTOUPCAM_EVENT_CALLBACK)(unsigned nEvent, void* pCallbackCtx);
toupcam_ports(HRESULT)      Toupcam_StartPullModeWithCallback(HToupCam h, PTOUPCAM_EVENT_CALLBACK pEventCallback, void* pCallbackContext);

/*
    bits: 24 (RGB24), 32 (RGB32), or 8 (Grey)
*/
toupcam_ports(HRESULT)      Toupcam_PullImage(HToupCam h, void* pImageData, int bits, unsigned* pnWidth, unsigned* pnHeight);
toupcam_ports(HRESULT)      Toupcam_PullStillImage(HToupCam h, void* pImageData, int bits, unsigned* pnWidth, unsigned* pnHeight);

/*
    (NULL == pData) means that something is error
    pCallbackCtx is the callback context which is passed by Toupcam_Start
    bSnap: TRUE if Toupcam_Snap

    pDataCallback is callbacked by an internal thread of toupcam.dll, so please pay attention to multithread problem
*/
typedef void (__stdcall*    PTOUPCAM_DATA_CALLBACK)(const void* pData, const BITMAPINFOHEADER* pHeader, BOOL bSnap, void* pCallbackCtx);
toupcam_ports(HRESULT)  Toupcam_StartPushMode(HToupCam h, PTOUPCAM_DATA_CALLBACK pDataCallback, void* pCallbackCtx);

toupcam_ports(HRESULT)  Toupcam_Stop(HToupCam h);
toupcam_ports(HRESULT)  Toupcam_Pause(HToupCam h, BOOL bPause);

/*  for pull mode: TOUPCAM_EVENT_STILLIMAGE, and then Toupcam_PullStillImage
    for push mode: the snapped image will be return by PTOUPCAM_DATA_CALLBACK, with the parameter 'bSnap' set to 'TRUE' */
toupcam_ports(HRESULT)  Toupcam_Snap(HToupCam h, unsigned nResolutionIndex);

/*
    put_Size, put_eSize, can be used to set the video output resolution BEFORE ToupCam_Start.
    put_Size use width and height parameters, put_eSize use the index parameter.
    for example, UCMOS03100KPA support the following resolutions:
            index 0:    2048,   1536
            index 1:    1024,   768
            index 2:    680,    510
    so, we can use put_Size(h, 1024, 768) or put_eSize(h, 1). Both have the same effect.
*/
toupcam_ports(HRESULT)  Toupcam_put_Size(HToupCam h, int nWidth, int nHeight);
toupcam_ports(HRESULT)  Toupcam_get_Size(HToupCam h, int* pWidth, int* pHeight);
toupcam_ports(HRESULT)  Toupcam_put_eSize(HToupCam h, unsigned nResolutionIndex);
toupcam_ports(HRESULT)  Toupcam_get_eSize(HToupCam h, unsigned* pnResolutionIndex);

toupcam_ports(HRESULT)  Toupcam_get_ResolutionNumber(HToupCam h);
toupcam_ports(HRESULT)  Toupcam_get_Resolution(HToupCam h, unsigned nResolutionIndex, int* pWidth, int* pHeight);

/*
    ------------------------------------------------------------|
    | Parameter         |   Range       |   Default             |
    |-----------------------------------------------------------|
    | AutoExpoTarget    |   10~230      |   120                 |
    | Temp              |   2000~15000  |   6503                |
    | Tint              |   200~2500    |   1000                |
    | LevelRange        |   0~255       |   Low = 0, High = 255 |
    | Contrast          |   -100~100    |   0                   |
    | Hue               |   -180~180    |   0                   |
    | Saturation        |   0~255       |   128                 |
    | Brightness        |   -64~64      |   0                   |
    | Gamma             |   20~180      |   100                 |
    -------------------------------------------------------------
*/

#ifndef __TOUPCAM_CALLBACK_DEFINED__
typedef void (CALLBACK*     PITOUPCAM_EXPOSURE_CALLBACK)(void* pCtx);
typedef void (CALLBACK*     PITOUPCAM_TEMPTINT_CALLBACK)(const int nTemp, const int nTint, void* pCtx);
typedef void (CALLBACK*     PITOUPCAM_HISTOGRAM_CALLBACK)(const double aHistY[256], const double aHistR[256], const double aHistG[256], const double aHistB[256], void* pCtx);
typedef void (CALLBACK*     PITOUPCAM_CHROME_CALLBACK)(void* pCtx);
#endif

toupcam_ports(HRESULT)  Toupcam_get_AutoExpoEnable(HToupCam h, BOOL* bAutoExposure);
toupcam_ports(HRESULT)  Toupcam_put_AutoExpoEnable(HToupCam h, BOOL bAutoExposure);
toupcam_ports(HRESULT)  Toupcam_get_AutoExpoTarget(HToupCam h, unsigned short* Target);
toupcam_ports(HRESULT)  Toupcam_put_AutoExpoTarget(HToupCam h, unsigned short Target);

/*set the maximum auto exposure time and analog agin. The default maximum auto exposure time is 350ms */
toupcam_ports(HRESULT)  Toupcam_put_MaxAutoExpoTimeAGain(HToupCam h, unsigned maxTime, unsigned short maxAGain);

toupcam_ports(HRESULT)  Toupcam_get_ExpoTime(HToupCam h, unsigned* Time)/* in microseconds */;
toupcam_ports(HRESULT)  Toupcam_put_ExpoTime(HToupCam h, unsigned Time)/* inmicroseconds */;
toupcam_ports(HRESULT)  Toupcam_get_ExpTimeRange(HToupCam h, unsigned* nMin, unsigned* nMax, unsigned* nDef);

toupcam_ports(HRESULT)  Toupcam_get_ExpoAGain(HToupCam h, unsigned short* AGain);/* percent, such as 300 */
toupcam_ports(HRESULT)  Toupcam_put_ExpoAGain(HToupCam h, unsigned short AGain);/* percent */
toupcam_ports(HRESULT)  Toupcam_get_ExpoAGainRange(HToupCam h, unsigned short* nMin, unsigned short* nMax, unsigned short* nDef);

/* Auto white balance */
toupcam_ports(HRESULT)  Toupcam_AwbOnePush(HToupCam h, PITOUPCAM_TEMPTINT_CALLBACK fnTTProc, void* pTTCtx); /* auto white balance "one push". The function must be called AFTER Toupcam_StartXXXX */

toupcam_ports(HRESULT)  Toupcam_put_TempTint(HToupCam h, int nTemp, int nTint);
toupcam_ports(HRESULT)  Toupcam_get_TempTint(HToupCam h, int* nTemp, int* nTint);

toupcam_ports(void)     Toupcam_TempTint2RGB(int nTemp, int nTint, int nRGB[3]);
toupcam_ports(void)     Toupcam_RGB2TempTint(const int nRGB[3], int* nTemp, int* nTint);

toupcam_ports(HRESULT)  Toupcam_put_Hue(HToupCam h, int Hue);
toupcam_ports(HRESULT)  Toupcam_get_Hue(HToupCam h, int* Hue);
toupcam_ports(HRESULT)  Toupcam_put_Saturation(HToupCam h, int Saturation);
toupcam_ports(HRESULT)  Toupcam_get_Saturation(HToupCam h, int* Saturation);
toupcam_ports(HRESULT)  Toupcam_put_Brightness(HToupCam h, int Brightness);
toupcam_ports(HRESULT)  Toupcam_get_Brightness(HToupCam h, int* Brightness);
toupcam_ports(HRESULT)  Toupcam_get_Contrast(HToupCam h, int* Contrast);
toupcam_ports(HRESULT)  Toupcam_put_Contrast(HToupCam h, int Contrast);
toupcam_ports(HRESULT)  Toupcam_get_Gamma(HToupCam h, int* Gamma); /* percent */
toupcam_ports(HRESULT)  Toupcam_put_Gamma(HToupCam h, int Gamma);  /* percent */

toupcam_ports(HRESULT)  Toupcam_get_Chrome(HToupCam h, BOOL* bChrome);  /* monochromatic mode */
toupcam_ports(HRESULT)  Toupcam_put_Chrome(HToupCam h, BOOL bChrome);

toupcam_ports(HRESULT)  Toupcam_get_VFlip(HToupCam h, BOOL* bVFlip);  /* vertical flip */
toupcam_ports(HRESULT)  Toupcam_put_VFlip(HToupCam h, BOOL bVFlip);
toupcam_ports(HRESULT)  Toupcam_get_HFlip(HToupCam h, BOOL* bHFlip);
toupcam_ports(HRESULT)  Toupcam_put_HFlip(HToupCam h, BOOL bHFlip); /* horizontal flip */

toupcam_ports(HRESULT)  Toupcam_get_Negative(HToupCam h, BOOL* bNegative);
toupcam_ports(HRESULT)  Toupcam_put_Negative(HToupCam h, BOOL bNegative);

toupcam_ports(HRESULT)  Toupcam_put_Speed(HToupCam h, unsigned short nSpeed);
toupcam_ports(HRESULT)  Toupcam_get_Speed(HToupCam h, unsigned short* pSpeed);
toupcam_ports(HRESULT)  Toupcam_get_MaxSpeed(HToupCam h);/* get the maximum speed, see "Frame Speed Level", the speed range = [0, max], closed interval */

        /* power supply: 
                0 -> 60HZ AC
                1 -> 50Hz AC
                2 -> DC
        */
toupcam_ports(HRESULT)  Toupcam_put_HZ(HToupCam h, int nHZ);
toupcam_ports(HRESULT)  Toupcam_get_HZ(HToupCam h, int* nHZ);

toupcam_ports(HRESULT)  Toupcam_put_Mode(HToupCam h, BOOL bSkip); /* skip or bin */
toupcam_ports(HRESULT)  Toupcam_get_Mode(HToupCam h, BOOL* bSkip); /* If the model don't support bin/skip mode, return E_NOTIMPL */

toupcam_ports(HRESULT)  Toupcam_put_AWBAuxRect(HToupCam h, RECT* pAuxRect); /* auto white balance ROI */
toupcam_ports(HRESULT)  Toupcam_get_AWBAuxRect(HToupCam h, RECT* pAuxRect);
toupcam_ports(HRESULT)  Toupcam_put_AEAuxRect(HToupCam h, RECT* pAuxRect);  /* auto exposure ROI */
toupcam_ports(HRESULT)  Toupcam_get_AEAuxRect(HToupCam h, RECT* pAuxRect);

        /*
            S_FALSE:    color mode
            S_OK:       mono mode, such as EXCCD00300KMA and UHCCD01400KMA
        */
toupcam_ports(HRESULT)  Toupcam_get_MonoMode(HToupCam h);

toupcam_ports(HRESULT)  Toupcam_get_StillResolutionNumber(HToupCam h);
toupcam_ports(HRESULT)  Toupcam_get_StillResolution(HToupCam h, unsigned nIndex, int* pWidth, int* pHeight);

/*
    set or get the process mode: TOUPCAM_PROCESSMODE_FULL or TOUPCAM_PROCESSMODE_FAST. default is TOUPCAM_PROCESSMODE_FULL.
*/
#ifndef __TOUPCAM_PROCESSMODE_DEFINED__
#define __TOUPCAM_PROCESSMODE_DEFINED__
#define TOUPCAM_PROCESSMODE_FULL        0x00    /* better image quality, more cpu usage. this is the default value */
#define TOUPCAM_PROCESSMODE_FAST        0x01    /* lower image quality, less cpu usage */
#endif
toupcam_ports(HRESULT)  Toupcam_put_ProcessMode(HToupCam h, unsigned nProcessMode);
toupcam_ports(HRESULT)  Toupcam_get_ProcessMode(HToupCam h, unsigned* pnProcessMode);

/* default: FALSE */
toupcam_ports(HRESULT)  Toupcam_put_RealTime(HToupCam h, BOOL bEnable);
toupcam_ports(HRESULT)  Toupcam_get_RealTime(HToupCam h, BOOL* bEnable);

toupcam_ports(HRESULT)  Toupcam_Flush(HToupCam h);  /* discard the current internal frame cache */

toupcam_ports(HRESULT)  Toupcam_put_RoiMode(HToupCam h, BOOL bRoiMode, int xOffset, int yOffset);
toupcam_ports(HRESULT)  Toupcam_get_RoiMode(HToupCam h, BOOL* pbRoiMode, int* pxOffset, int* pyOffset);

/*
    get the serial number which is always 32 chars which is zero-terminated such as "TP110826145730ABCD1234FEDC56787"
*/
toupcam_ports(HRESULT)  Toupcam_get_SerialNumber(HToupCam h, char sn[32]);

toupcam_ports(HRESULT)  Toupcam_put_LevelRange(HToupCam h, unsigned short aLow[4], unsigned short aHigh[4]);
toupcam_ports(HRESULT)  Toupcam_get_LevelRange(HToupCam h, unsigned short aLow[4], unsigned short aHigh[4]);

toupcam_ports(HRESULT)  Toupcam_put_ExpoCallback(HToupCam h, PITOUPCAM_EXPOSURE_CALLBACK fnExpoProc, void* pExpoCtx);
toupcam_ports(HRESULT)  Toupcam_put_ChromeCallback(HToupCam h, PITOUPCAM_CHROME_CALLBACK fnChromeProc, void* pChromeCtx);

/*
    The following functions must be called AFTER Toupcam_StartXXXX
*/
toupcam_ports(HRESULT)  Toupcam_LevelRangeAuto(HToupCam h);
toupcam_ports(HRESULT)  Toupcam_GetHistogram(HToupCam h, PITOUPCAM_HISTOGRAM_CALLBACK fnHistogramProc, void* pHistogramCtx);

/*
            ------------------------------------------------------------|
            | Parameter         |   Range       |   Default             |
            |-----------------------------------------------------------|
            | VidgetAmount      |   -100~100    |   0                   |
            | VignetMidPoint    |   0~100       |   50                  |
            -------------------------------------------------------------
*/
toupcam_ports(HRESULT)  Toupcam_put_VignetEnable(HToupCam h, BOOL bEnable);
toupcam_ports(HRESULT)  Toupcam_get_VignetEnable(HToupCam h, BOOL* bEnable);
toupcam_ports(HRESULT)  Toupcam_put_VignetAmountInt(HToupCam h, int nAmount);
toupcam_ports(HRESULT)  Toupcam_get_VignetAmountInt(HToupCam h, int* nAmount);
toupcam_ports(HRESULT)  Toupcam_put_VignetMidPointInt(HToupCam h, int nMidPoint);
toupcam_ports(HRESULT)  Toupcam_get_VignetMidPointInt(HToupCam h, int* nMidPoint);

#ifdef _WIN32
/*
    strRegPath, such as: Software\XxxCompany\yyyApplication.
    If we call this function to enable this feature, the camera parameters will be save in the Registry at HKEY_CURRENT_USER\Software\XxxCompany\yyyApplication\{CameraModelName} when we close the handle,
    and then, the next time, we open the camera, the parameters will be loaded automatically.
*/
toupcam_ports(void)     Toupcam_EnableReg(const wchar_t* strRegPath);

/* Toupcam_Start is obsolete, it's a synonyms for Toupcam_StartPushMode. They are exactly the same. */
toupcam_ports(HRESULT)  Toupcam_Start(HToupCam h, PTOUPCAM_DATA_CALLBACK pDataCallback, void* pCallbackCtx);

/* Toupcam_put_TempTintInit is obsolete, it's a synonyms for Toupcam_AwbOnePush. They are exactly the same. */
toupcam_ports(HRESULT)  Toupcam_put_TempTintInit(HToupCam h, PITOUPCAM_TEMPTINT_CALLBACK fnTTProc, void* pTTCtx);
#endif

#ifdef _WIN32
#pragma pack(pop)
#endif

#ifdef __cplusplus
}
#endif

#endif
