#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32)
#include <conio.h>
#else
#include <curses.h>
#endif
#include "omegonprocam.h"

HOmegonprocam g_hcam = NULL;
void* g_pImageData = NULL;
unsigned g_total = 0, g_totalstill = 0;
bool g_bBitdepth = false, g_bSave = false;

static void SaveRaw(const char* filePrefix, unsigned num, unsigned width, unsigned height, const void* pData, unsigned length)
{
    char filename[1024];
    sprintf(filename, "%s_%ux%u_%u.raw", filePrefix, width, height, num);
    FILE* fp = fopen(filename, "wb");
    if (fp)
    {
        fwrite(pData, 1, length, fp);
        fclose(fp);
    }
    printf("saveraw: %s\n", filename);
}

static void __stdcall EventCallback(unsigned nEvent, void* pCallbackCtx)
{
    if (OMEGONPROCAM_EVENT_IMAGE == nEvent)
    {
        OmegonprocamFrameInfoV3 info = { 0 };
        const HRESULT hr = Omegonprocam_PullImageV3(g_hcam, g_pImageData, 0, 0, 0, &info);
        if (FAILED(hr))
            printf("failed to pull image, hr = 0x%08x\n", hr);
        else
        {
            printf("pull image ok, total = %u, resolution = %u x %u\n", ++g_total, info.width, info.height);
            if (g_bSave)
            {
                g_bSave = false;
                SaveRaw("demoraw", g_total, info.width, info.height, g_pImageData, info.width * info.height * (g_bBitdepth ? 2 : 1));
            }
        }
    }
    else if (OMEGONPROCAM_EVENT_STILLIMAGE == nEvent)
    {
        OmegonprocamFrameInfoV3 info = { 0 };
        const HRESULT hr = Omegonprocam_PullImageV3(g_hcam, g_pImageData, 1, 0, 0, &info);
        if (FAILED(hr))
            printf("failed to pull still image, hr = 0x%08x\n", hr);
        else
        {
            printf("pull still image ok, total = %u, resolution = %u x %u\n", ++g_totalstill, info.width, info.height);
            SaveRaw("demorawstill", g_totalstill, info.width, info.height, g_pImageData, info.width * info.height * (g_bBitdepth ? 2 : 1));
        }
    }
    else
    {
        printf("event callback: 0x%04x\n", nEvent);
    }
}

int main(int, char**)
{
    OmegonprocamDeviceV2 tdev[OMEGONPROCAM_MAX] = { 0 };
    const unsigned ncam = Omegonprocam_EnumV2(tdev);
    if (0 == ncam)
    {
        printf("no camera found\n");
        return -1;
    }
    
    g_hcam = Omegonprocam_Open(tdev[0].id);
    if (NULL == g_hcam)
    {
        printf("failed to open camera\n");
        return -1;
    }
    
    HRESULT hr = Omegonprocam_put_Option(g_hcam, OMEGONPROCAM_OPTION_RAW, 1); /* use raw image data */
    printf("put option raw: hr = 0x%08x\n", hr);

    if (tdev[0].model->preview > 1)
        Omegonprocam_put_eSize(g_hcam, 1);

    if (tdev[0].model->flag & (OMEGONPROCAM_FLAG_RAW10 | OMEGONPROCAM_FLAG_RAW12 | OMEGONPROCAM_FLAG_RAW14 | OMEGONPROCAM_FLAG_RAW16))  /* bitdepth supported */
    {
        Omegonprocam_put_Option(g_hcam, OMEGONPROCAM_OPTION_BITDEPTH, 1); /* enable bitdepth */
        g_bBitdepth = true;
    }

    int nMaxWidth = 0, nMaxHeight = 0;
    hr = Omegonprocam_get_Resolution(g_hcam, 0, &nMaxWidth, &nMaxHeight);
    if (FAILED(hr))
        printf("failed to get size, hr = 0x%08x\n", hr);
    else
    {
        g_pImageData = malloc(nMaxWidth * nMaxHeight * (g_bBitdepth ? 2 : 1));
        if (NULL == g_pImageData)
            printf("failed to malloc\n");
        else
        {
            hr = Omegonprocam_StartPullModeWithCallback(g_hcam, EventCallback, NULL);
            if (FAILED(hr))
                printf("failed to start camera, hr = 0x%08x\n", hr);
            else
            {
                bool bloop = true;
                while (bloop)
                {
                    printf("press s to save raw, any other key to exit\n");
                    switch (getch())
                    {
                    case 'x':
                    case 'X':
                        bloop = false;
                        break;
                    case 's':
                    case 'S':
                        g_bSave = true;
                        break;
                    default:
                        if (tdev[0].model->still)             /* snap supported */
                            Omegonprocam_Snap(g_hcam, 0);
                        else
                            bloop = false;
                        break;
                    }
                }
            }
        }
    }
    
    /* cleanup */
    Omegonprocam_Close(g_hcam);
    if (g_pImageData)
        free(g_pImageData);
    return 0;
}
