////////////////////////////////////////////////////////////////////////////////
///
/// \file       SampleCode01.c
///
///
/// \brief
///     This file contains the test code for the HRx SDK.
///
/// \b description
///     The code here opens the library, finds a single camera, sets the 
///     capture mode to JPEG. IT then triggers an image, waits for that image
////    to complete being sent, and then saves the captured image in a file.
///
/// \b  Copyright 2004 Imaginant
///
///  Change History
///     - 2004.10.??    File created
///     - 2004.10.??    Mutated to use McK's backend.  Does not meet SDK standards anymore (whoops)
///     - 2004.10.22    Header added.
///
////////////////////////////////////////////////////////////////////////////////

#include <stdio.h>

#include "HR_Types.h"
#include "HR_Errors.h"
#include "HR_Lib.h"
#include "HR_Loader.h"
int debugMode = 1;

/// Decleration for exit function at end of this file
void exitWithMessage(HR_StatusType status);

// This is global here but should be a member variable of a class
HR_FunctionPtrs HRFuncs;


int main(int argc, char* argv[])
{

    HR_StatusType       status = HR_OK;         ///< this status is checked before continuing
    HR_StatusType       ignoredStatus = HR_OK;  ///< this status is not checked (programmers use only)

    HR_LibHandle    libHnd = 0;                 ///< handle for a library object
    HR_CamHandle    camHnd = 0;                 ///< handle for a camera object
    HR_ImgHandle    imgHnd = 0;                 ///< handle for an image object

    HR_BufferStructType  imgBufferStruct;


    HR_Int32Type       cameraCount = 0;    

    HR_Int32Type       libInitOptionBits = 0;
    HR_Int32Type       imagesInCamera = 0; 
    HR_Int32Type       percentDone = 0;
    HR_Int32Type       cameraStatus = 0;   
    HR_Int32Type       numImagesToGet= 0;   
    HR_Int32Type       count = 0;


    HR_ImgDataFormatEnumType fileTypeJPEG = HR_FILE_JPEG; /// 


    HR_Int32Type JpegSizeOutput = 0;
    HR_Int32Type NumValuesFound = 0;


    ///
    /// 0) Say Hello & load lib
    /// 
    if(debugMode == TRUE)
        printf("Sample Code 01 : Starting\n");
    
    status = HR_LoaderLoadLib("HR_Lib.dll", &HRFuncs);
    if ( HR_OK != status )
    {
        printf("ERROR: HR_LoaderLoadLib FAILED. Status=%d\n", status);
        return(1);
    }


    ///
    /// 1)  Initialize the Library ( the DLL ), no option bits are set
    ///
     
    if(debugMode == TRUE)
        printf("Sample Code 01 : calling HR_OpenLibrary \n");

    status = HRFuncs.OpenLibrary( libInitOptionBits , &libHnd );

    if(status != HR_OK)
        exitWithMessage(status);

  

    ///
    /// 2)  List available cameras
    ///
    if(debugMode == TRUE)
        printf("Sample Code 01 : calling HR_GetCameraList \n");
        

    do{
        status = HRFuncs.GetCameraList (libHnd, 1 , &cameraCount, &camHnd);
    }
    while(cameraCount != 1);

    //:TOFIX: do we really want this? Should the library
    // return an error message of 0 cameras are found? Should
    // we allow/suggest the end developer use our error codes?
    if(cameraCount < 1) 
        status = HR_ERR_CAM_INHANDLE_NOT_VALID;


    if(status != HR_OK)
        exitWithMessage(status);


    ///    
    /// 3) Connect to the camera
    /// 
    if(cameraCount > 0 )
    {
        if(debugMode == TRUE)
            printf("Sample Code 01 : calling HR_OpenCamera \n");
        
        status = HRFuncs.OpenCamera(camHnd); ///< HR_OpenCamera returns immedately, 
                                        /// and the cam structure continues to connect
                                        /// as a seprate thread in the background
    }

    if(status != HR_OK)
        exitWithMessage(status);

    ///
    /// 4) Wait for the cameras to connect (this may take a moment)
    ///
    if(debugMode == TRUE)
        printf("Sample Code 01 : Waiting for the Camera to connect \n"); 
       
    do{
        status = HRFuncs.GetParam(camHnd, HR_PID_CAM_STATE,1,&count, &cameraStatus);
//        Sleep(500);
    } 
    while ( (cameraStatus != HR_CAM_STATE_IDLE) && (status == HR_OK) );

    if(status != HR_OK)
        exitWithMessage(status);


    ///
    /// 5) Set the camera to JPEG mode (camera defaults to JPEG mode on boot, this is just to test sending a parameter
    ///
    if(debugMode == TRUE)
        printf("Sample Code 01 : setting capture FileType\n");

    status = HRFuncs.SetParam(   camHnd,             ///< Handle to the object we are settting parameters on
                            HR_PID_CAM_CAPTURE_FILE_TYPE,///< Parameter we are setting 
                            HR_TYPE_ENUM,       ///< data type we are setting the parameter with
                            1,                  ///< number of items in the parameter
                            &fileTypeJPEG );    ///< pointer to the parameter data 

    if(status != HR_OK)
        exitWithMessage(status);


    //
    // 6) Send a single trigger to the camera
    //
    if(debugMode == TRUE)
        printf("Sample Code 01 : calling HR_TriggerCamera\n");

    status = HRFuncs.TriggerCamera ( camHnd );

    if(status != HR_OK)
        exitWithMessage(status);
 

    //
    // 7) Wait for the camera to take a picture
    //
    imagesInCamera = 0;

    if(debugMode == TRUE)
        printf("Sample Code 01 : Polling for a finished image\n");

    while (  ( status == HR_OK ) && (imagesInCamera == 0) )
    {
        HR_Int32Type eventsCodes = HR_POLL_CAM_TRANSFER_EVENTS;
        HR_Int32Type events = 0;
  
        // This is an oversimplified example. In a loop like this your code should
        // do two things that are not shown here:
        //  1. use "sleep" or similar OS call so this loop does not take 100% of the CPU
        //  2. watch for other events from the user
 
        status = HRFuncs.Poll (camHnd,eventsCodes,&events);

        //This is an OK error, because the image might not be generated yet
        if(status == HR_ERR_HANDLEMGR_IMAGE_GET_FIRST_IMG_FAIL)
        {
            status = HR_OK;
        }
        if( (events & HR_EVENT_CAM_TRANSFER_NEW_COMPLETE_IMAGE_AVAILABLE) == HR_EVENT_CAM_TRANSFER_NEW_COMPLETE_IMAGE_AVAILABLE)
            imagesInCamera = 1;
        Sleep(500);
    }

    if(status != HR_OK)
        exitWithMessage(status);


  if(debugMode == TRUE)
        printf("Sample Code 01 : First Image Found\n");
   

    ///
    /// 8) Get the handle to the first image we can get
    ///
    if(debugMode == TRUE)
        printf("Sample Code 01 : Get the first Image Handle\n");

    numImagesToGet = 1; // we want just the first image


    status = HRFuncs.GetImageList(camHnd,1,&numImagesToGet,&imgHnd);

   
    if(status != HR_OK)
        exitWithMessage(status);


    //
    // 9) Open the image
    //
    if(debugMode == TRUE)
        printf("Sample Code 01 : Open the Image Handle\n");

    status = HRFuncs.OpenImage(imgHnd);

   if(status != HR_OK)
        exitWithMessage(status);



    //
    // 10) Get the image buffer strucutre
    //
    if(debugMode == TRUE)
        printf("Sample Code 01 : Get the Image Buffer structure\n");
   
    numImagesToGet = 1; // we are reusing this variable to get the image buffer structure

    memset(&imgBufferStruct, 0, sizeof(HR_BufferStructType));

    status = HRFuncs.GetParam(imgHnd, HR_PID_IMG_IMAGE_BUFFER_STRUCT,1, &numImagesToGet, &imgBufferStruct );

   if(status != HR_OK)
        exitWithMessage(status);


    ///
    /// 11) Write the Image buffer to a file
    ///
   if(debugMode == TRUE)
        printf("Sample Code 01 : Writing the Image to a file\n");

   status  = HRFuncs.GetParam(imgHnd,HR_PID_IMG_BYTES_COLLECTED,1,&NumValuesFound,&JpegSizeOutput);

   if(status != HR_OK)
        exitWithMessage(status);
       

    if (imgBufferStruct.dataPtr != NULL )
    {
        FILE* fp = fopen( "HR1100.jpg", "wb" );
        if ( NULL != fp )
        {
            fwrite((void*)imgBufferStruct.dataPtr, 1, JpegSizeOutput, fp );
            fclose(fp);
        }
    }

   if(debugMode == TRUE)
        printf("Sample Code 01 : Image Saved, closing handles\n");

    //
    // 12)  Close and delete the image
    //
    if ( imgHnd != 0)
    {
        ignoredStatus = HRFuncs.CloseImage(imgHnd);
        ignoredStatus = HRFuncs.DeleteImage(imgHnd);
        imgHnd = 0;
        // the local copy of the buffer image is now useless as well
        imgBufferStruct.dataPtr = NULL;
    }


    //
    // 13) Close the camera
    //
    if ( camHnd != 0)
    {
        ignoredStatus = HRFuncs.CloseCamera(camHnd);
    }
    

    // this handle is now useless, make sure no one reuses it
    camHnd = 0;

    //
    // 15 )Close the Library
    //
    if ( 0 != libHnd )
    {
        ignoredStatus = HRFuncs.CloseLibrary(libHnd);
        libHnd = 0;
    }

    //
    // 16) Exit 
    //
    exitWithMessage(status);

    return 0;
}



void exitWithMessage(HR_StatusType status)
{
    int response;

    /// Print an error message
    if(debugMode == TRUE && status != HR_OK )
        printf("Sample code encountered an error %i\n", status);
    
    /// more info on the failure
    switch(status)
    {   
        case HR_OK:
            printf("SampleCode01 : program finished with no errors\n");
        break;
        case HR_ERR_CAM_INHANDLE_NOT_VALID :
            printf("\nSample Code 01 : No cameras found on network.\n");
        break;
        default:
            printf("SampleCode01 : program exited with unchecked error\n");
        break;
    }
    printf("Press <enter> to close this window\n");
    response = getchar();

    exit(status);
}