/********************************************************************************/
/* 
* File name: autodetect.cpp 
* Location:  ...\Matrox Imaging\MILxxx\Examples\BoardSpecific\OrionHD\C++\AutoDetect
 *             
*
* Synopsis:  This program shows how to detect Matrox Orion HD
*            input sources using the M_MINIMAL flag with MdigAlloc.
*
*            When a digitizer is allocated with M_MINIMAL it can only be
*            used for input source detection, it cannot be used for grabbing.
*
*/

#include <mil.h>
#include <windows.h>

const MIL_INT gNumberOfDigitizers = 4;
const MIL_TEXT_PTR gDCFName = MIL_TEXT("autodetect.dcf");
const MIL_INT gDevNumber [4] = {M_DEV0, M_DEV1, M_DEV2, M_DEV3};
const MIL_DOUBLE gCameraPresentWaitTime = 5.0;

MIL_INT MFTYPE DigHookCameraPresent(MIL_INT hookType, MIL_ID eventId, void *userData);
void PrintDigitizerInfo(MIL_ID MilDigitizer);

typedef struct 
   {
   MIL_ID MilSystem;
   MIL_ID MilDigitizer;
   MIL_INT DevNumber;
   MIL_ID MilDisplay;
   MIL_ID MilImageDisp;

   bool   IsCameraPresent;
   bool   IsGrabbing;
   MIL_DOUBLE CheckforCameraPresentWaitTime;

   } DIG_INFO, *PDIG_INFO ;


int MosMain(void)
   { 
   MIL_ID MilApplication,                   /* Application identifier.  */
          MilSystem;                        /* System identifier.       */
   DIG_INFO DigInfo[gNumberOfDigitizers];
   MIL_TEXT_CHAR  DCFFormat[255];
   MIL_INT i;
   MIL_INT NumberOfGrabsInProgress = 0;

   memset(DigInfo, 0, sizeof(DigInfo));

   system("cls");
   MosPrintf(MIL_TEXT("Matrox OrionHD autodetect example.\n"));
   MosPrintf(MIL_TEXT("----------------------------------\n\n"));

   // First step: allocate Mil OrionHD system.
   MappAlloc(M_DEFAULT, &MilApplication);
   MsysAlloc(M_SYSTEM_ORION_HD, M_DEFAULT, M_DEFAULT, &MilSystem);

   // Second step: allocate displays and minimum digitizers.
   MosPrintf(MIL_TEXT("Allocating system and digitizers... "));
   for(i = 0; i < gNumberOfDigitizers; i++)
      {
      PDIG_INFO pDigInfo = &DigInfo[i];
      pDigInfo->MilSystem = MilSystem;
      pDigInfo->DevNumber = gDevNumber[i];
      pDigInfo->IsGrabbing = false;
      pDigInfo->IsCameraPresent = false;

      MdispAlloc(MilSystem, M_DEFAULT, MIL_TEXT("M_DEFAULT"), M_DEFAULT, &pDigInfo->MilDisplay);
      MdigAlloc(MilSystem, DigInfo[i].DevNumber, gDCFName, M_MINIMAL, &pDigInfo->MilDigitizer);
      MdigHookFunction(DigInfo[i].MilDigitizer, M_CAMERA_PRESENT, DigHookCameraPresent, pDigInfo);

      if(MdigInquire(pDigInfo->MilDigitizer, M_CAMERA_PRESENT, M_NULL) == M_TRUE)
         pDigInfo->IsCameraPresent = true;
      MosPrintf(MIL_TEXT("."));
      }
   MosPrintf(MIL_TEXT(" done\n\n"));
   MosPrintf(MIL_TEXT("-------------------------------------------------------------\n"));
   MappControl(M_ERROR, M_PRINT_DISABLE);

   // Third step: loop all the digitizers and print their information.
   while(1)
      {
      Sleep(500);

      MIL_INT KeyPressed = 0;
      if(MosKbhit())
         KeyPressed = MosGetch();

      if(KeyPressed == 'q')
         break;

      COORD Coord;
      Coord.X = 0;
      Coord.Y = 6;
      SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), Coord);

      // Print the input source of each digitizer.
      for(i = 0; i < gNumberOfDigitizers; i++)
         {
         PDIG_INFO pDigInfo = &DigInfo[i];

         MosPrintf(MIL_TEXT("\nDigitizer %d: \n"),i);
         MosPrintf(MIL_TEXT("------------  \n"));

         if(pDigInfo->IsCameraPresent)
            {
            MosPrintf(MIL_TEXT("Input source is present. %s  \n"), pDigInfo->IsGrabbing?MIL_TEXT("Live grab in progress.   "):
                                                                                        MIL_TEXT("                         "));
            PrintDigitizerInfo(pDigInfo->MilDigitizer);
            }
         else
            {
            MosPrintf(MIL_TEXT("Input source not present.                                                      \n"));
            MosPrintf(MIL_TEXT("                                                                               \n"));
            MosPrintf(MIL_TEXT("                                                                               \n"));
            MosPrintf(MIL_TEXT("                                                                               \n"));
            }

         // The camera present hook was called, check the camera present status after a few seconds
         // to be sure it is stable. Prevents fast plug-unplug issues.
         if(pDigInfo->CheckforCameraPresentWaitTime)
            {
            MIL_DOUBLE TimeRead;
            MappTimer(M_TIMER_READ + M_GLOBAL, &TimeRead);
            if(TimeRead - pDigInfo->CheckforCameraPresentWaitTime > gCameraPresentWaitTime)
               {
               pDigInfo->CheckforCameraPresentWaitTime = 0;
               if(MdigInquire(pDigInfo->MilDigitizer, M_CAMERA_PRESENT, M_NULL))
                  pDigInfo->IsCameraPresent = true;
               else
                  pDigInfo->IsCameraPresent = false;
               }
            }

         // Stop the live grab if the camera is disconnected.
         bool StopGrabbing = (pDigInfo->IsGrabbing) && (!pDigInfo->IsCameraPresent);

         // The user pressed the digitizer number.
         if((KeyPressed == i + '0') || StopGrabbing)
            {
            if(pDigInfo->IsGrabbing || StopGrabbing)
               {
               // A grab is in progress, stop it.
               MdigHalt(pDigInfo->MilDigitizer);
               MbufFree(DigInfo[i].MilImageDisp);
               MdigFree(pDigInfo->MilDigitizer);

               // Allocated the digitizer with the M_MINIMAL flag. This digitizer cannot be used for grabbing.
               MdigAlloc(pDigInfo->MilSystem, pDigInfo->DevNumber, gDCFName, M_MINIMAL, &pDigInfo->MilDigitizer);
               MdigHookFunction(pDigInfo->MilDigitizer, M_CAMERA_PRESENT, DigHookCameraPresent, pDigInfo);
               pDigInfo->IsGrabbing = false;
               NumberOfGrabsInProgress--;
               }
            else if(pDigInfo->IsCameraPresent)
               {
               MIL_INT SizeX, SizeY;
               MdigInquire(pDigInfo->MilDigitizer, M_FORMAT_DETECTED, DCFFormat);
               MdigFree(pDigInfo->MilDigitizer);

               MdigAlloc(pDigInfo->MilSystem, pDigInfo->DevNumber, DCFFormat, M_DEFAULT, &pDigInfo->MilDigitizer);
               if(pDigInfo->MilDigitizer)
                  {
                  MdigHookFunction(pDigInfo->MilDigitizer, M_CAMERA_PRESENT, DigHookCameraPresent, pDigInfo);

                  MIL_TEXT_CHAR WindowTitle[MAX_PATH];
                  MosSprintf(WindowTitle, MAX_PATH, MIL_TEXT("Dev: %d DCF: %s"), pDigInfo->DevNumber, DCFFormat);
                  MdispControl(pDigInfo->MilDisplay, M_TITLE, M_PTR_TO_DOUBLE(WindowTitle));

                  MdigInquire(pDigInfo->MilDigitizer, M_SIZE_X, &SizeX);
                  MdigInquire(pDigInfo->MilDigitizer, M_SIZE_Y, &SizeY);
                  MbufAllocColor(pDigInfo->MilSystem, 3, SizeX, SizeY, 8, M_IMAGE + M_GRAB + M_DISP, &pDigInfo->MilImageDisp);
                  MdispSelect(pDigInfo->MilDisplay, pDigInfo->MilImageDisp);
                  MdigGrabContinuous(pDigInfo->MilDigitizer, pDigInfo->MilImageDisp);
                  pDigInfo->IsGrabbing = true;
                  NumberOfGrabsInProgress++;
                  }
               else
                  {
                  MdigAlloc(pDigInfo->MilSystem, pDigInfo->DevNumber, gDCFName, M_MINIMAL, &pDigInfo->MilDigitizer);
                  MdigHookFunction(pDigInfo->MilDigitizer, M_CAMERA_PRESENT, DigHookCameraPresent, pDigInfo);
                  pDigInfo->IsGrabbing = false;
                  }
               }
            }
         }

      MosPrintf(MIL_TEXT("\n---------------------------------------------------------------\n\n"));
      MosPrintf(MIL_TEXT("Press the digitizer number (0-3) to start or stop a live grab.   \n"));
      MosPrintf(MIL_TEXT("Press 'q' to quit.                                               \n"));
      MosPrintf(MIL_TEXT("                                                                 \n"));
      }

   // Last step: free all allocations and exit.
   for(i = 0; i < gNumberOfDigitizers; i++)
      {
      if(DigInfo[i].MilImageDisp)
         MbufFree(DigInfo[i].MilImageDisp);

      if(DigInfo[i].MilDisplay)
         MdispFree(DigInfo[i].MilDisplay);

      if(DigInfo[i].MilDigitizer)
         MdigFree(DigInfo[i].MilDigitizer);
      }

   MsysFree(MilSystem);
   MappFree(MilApplication);

   return 0;
   }


// The camera present hook.
// When called inquire and store the current time. 
// Then MdigInquire of camera present will be done in the main loop after a few seconds.
MIL_INT MFTYPE DigHookCameraPresent(MIL_INT hookType, MIL_ID eventId, void *userData)
   {
   PDIG_INFO pDigInfo = (PDIG_INFO)userData;

   pDigInfo->IsCameraPresent = false;
   MappTimer(M_TIMER_READ + M_GLOBAL, &pDigInfo->CheckforCameraPresentWaitTime);

   return 0;
   }


// Prints to the console the details of the detected input.
void PrintDigitizerInfo(MIL_ID MilDigitizer)
   {
   MIL_TEXT_CHAR  DCFFormat[255];
   MIL_INT        ColorMode;
   MIL_INT        InputMode;
   MIL_INT        ScanMode;
   MIL_INT        SizeX, SizeY, SizeBand;
   MIL_DOUBLE     FrameRate;
   MIL_INT        DigitizerNumber;

   MdigInquire(MilDigitizer, M_NUMBER, &DigitizerNumber);
   MdigInquire(MilDigitizer, M_SIZE_X, &SizeX);
   MdigInquire(MilDigitizer, M_SIZE_Y, &SizeY);
   MdigInquire(MilDigitizer, M_SIZE_BAND, &SizeBand);
   MdigInquire(MilDigitizer, M_INPUT_MODE, &InputMode);
   MdigInquire(MilDigitizer, M_COLOR_MODE, &ColorMode);
   MdigInquire(MilDigitizer, M_SCAN_MODE, &ScanMode);
   MdigInquire(MilDigitizer, M_SELECTED_FRAME_RATE, &FrameRate);
   MdigInquire(MilDigitizer, M_FORMAT_DETECTED, DCFFormat);

   MosPrintf(MIL_TEXT("                                                                              \r"));
   MosPrintf(MIL_TEXT("\t%d x %d, %d band(s). "), SizeX, SizeY, SizeBand);

   switch(ColorMode)
      {
      case M_DVI: MosPrintf(MIL_TEXT("DVI "));break;
      case M_SDI: MosPrintf(MIL_TEXT("SDI "));break;
      case M_COMPOSITE: MosPrintf(MIL_TEXT("Composite "));break;
      case M_RGB: MosPrintf(MIL_TEXT("RGB "));break;
      case M_EXTERNAL_CHROMINANCE: MosPrintf(MIL_TEXT("Y\\C "));break;
      case M_MONOCHROME: MosPrintf(MIL_TEXT("Monochrome "));break;
      default: MosPrintf(MIL_TEXT(" "));
      }
   switch(InputMode)
      {
      case M_ANALOG: MosPrintf(MIL_TEXT("analog "));break;
      case M_DIGITAL: MosPrintf(MIL_TEXT("digital "));break;
      default: MosPrintf(MIL_TEXT(" "));
      }
   switch(ScanMode)
      {
      case M_PROGRESSIVE: MosPrintf(MIL_TEXT("progressive "));break;
      case M_INTERLACE: MosPrintf(MIL_TEXT("interlaced "));break;
      default: MosPrintf(MIL_TEXT(" "));
      }

   MosPrintf(MIL_TEXT("@ %0.2f fps.\n"), FrameRate);
   MosPrintf(MIL_TEXT("                                                                              \r"));
   MosPrintf(MIL_TEXT("\tDCF: %s.\n\n"), DCFFormat);
   }