/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMILVideoSource.h

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
/**
 * @class   vtkMILVideoSource
 * @brief   Matrox Imaging Library frame grabbers
 *
 * vtkMILVideoSource provides an interface to Matrox Meteor, MeteorII
 * and Corona video digitizers through the Matrox Imaging Library
 * interface.  In order to use this class, you must link VTK with mil.lib,
 * MIL version 5.0 or higher is required.
 * @warning
 * With some capture cards, if this class is leaked and ReleaseSystemResources
 * is not called, you may have to reboot before you can capture again.
 * vtkVideoSource used to keep a global list and delete the video sources
 * if your program leaked, due to exit crashes that was removed.
 * @sa
 * vtkWin32VideoSource vtkVideoSource
*/

#ifndef vtkMILVideoSource_h
#define vtkMILVideoSource_h

#include "vtkIOVideoModule.h" // For export macro
#include "vtkVideoSource.h"

// digitizer hardware
#define VTK_MIL_DEFAULT        0
#define VTK_MIL_METEOR         "M_SYSTEM_METEOR"
#define VTK_MIL_METEOR_II      "M_SYSTEM_METEOR_II"
#define VTK_MIL_METEOR_II_DIG  "M_SYSTEM_METEOR_II_DIG"
#define VTK_MIL_METEOR_II_CL   "M_SYSTEM_METEOR_II_CL"
#define VTK_MIL_METEOR_II_1394 "M_SYSTEM_METEOR_II_1394"
#define VTK_MIL_CORONA         "M_SYSTEM_CORONA"
#define VTK_MIL_CORONA_II      "M_SYSTEM_CORONA_II"
#define VTK_MIL_PULSAR         "M_SYSTEM_PULSAR"
#define VTK_MIL_GENESIS        "M_SYSTEM_GENESIS"
#define VTK_MIL_GENESIS_PLUS   "M_SYSTEM_GENESIS_PLUS"
#define VTK_MIL_ORION          "M_SYSTEM_ORION"
#define VTK_MIL_CRONOS         "M_SYSTEM_CRONOS"
#define VTK_MIL_ODYSSEY        "M_SYSTEM_ODYSSEY"

// video inputs:
#define VTK_MIL_MONO          0
#define VTK_MIL_COMPOSITE     1
#define VTK_MIL_YC            2
#define VTK_MIL_RGB           3
#define VTK_MIL_DIGITAL       4

// video formats:
#define VTK_MIL_RS170         0
#define VTK_MIL_NTSC          1
#define VTK_MIL_CCIR          2
#define VTK_MIL_PAL           3
#define VTK_MIL_SECAM         4
#define VTK_MIL_NONSTANDARD   5

class VTKIOVIDEO_EXPORT vtkMILVideoSource : public vtkVideoSource
{
public:
  static vtkMILVideoSource *New();
  vtkTypeMacro(vtkMILVideoSource,vtkVideoSource);
  void PrintSelf(ostream& os, vtkIndent indent);

  /**
   * Standard VCR functionality: Record incoming video.
   */
  void Record() override;

  /**
   * Standard VCR functionality: Play recorded video.
   */
  void Play() override;

  /**
   * Standard VCR functionality: Stop recording or playing.
   */
  void Stop() override;

  /**
   * Grab a single video frame.
   */
  void Grab() override;

  /**
   * Request a particular frame size (set the third value to 1).
   */
  void SetFrameSize(int x, int y, int z) override;

  /**
   * Request a particular output format (default: VTK_RGB).
   */
  void SetOutputFormat(int format) override;

  //@{
  /**
   * Set/Get the video channel
   */
  virtual void SetVideoChannel(int channel);
  vtkGetMacro(VideoChannel, int);
  //@}

  //@{
  /**
   * Set/Get the video format
   */
  virtual void SetVideoFormat(int format);
  void SetVideoFormatToNTSC() { this->SetVideoFormat(VTK_MIL_NTSC); };
  void SetVideoFormatToPAL() { this->SetVideoFormat(VTK_MIL_PAL); };
  void SetVideoFormatToSECAM() { this->SetVideoFormat(VTK_MIL_SECAM); };
  void SetVideoFormatToRS170() { this->SetVideoFormat(VTK_MIL_RS170); };
  void SetVideoFormatToCCIR() { this->SetVideoFormat(VTK_MIL_CCIR); };
  void SetVideoFormatToNonStandard() {
    this->SetVideoFormat(VTK_MIL_NONSTANDARD); };
  vtkGetMacro(VideoFormat,int);
  //@}

  //@{
  /**
   * Set/Get the video input
   */
  virtual void SetVideoInput(int input);
  void SetVideoInputToMono() { this->SetVideoInput(VTK_MIL_MONO); };
  void SetVideoInputToComposite() {this->SetVideoInput(VTK_MIL_COMPOSITE);};
  void SetVideoInputToYC() { this->SetVideoInput(VTK_MIL_YC); };
  void SetVideoInputToRGB() { this->SetVideoInput(VTK_MIL_RGB); };
  void SetVideoInputToDigital() { this->SetVideoInput(VTK_MIL_DIGITAL); };
  vtkGetMacro(VideoInput,int);
  //@}

  //@{
  /**
   * Set/Get the video levels for composite/SVideo: the valid ranges are:
   * Contrast [0.0,2.0]
   * Brightness [0.0,255.0]
   * Hue [-0.5,0.5]
   * Saturation [0.0,2.0]
   */
  virtual void SetContrastLevel(float contrast);
  vtkGetMacro(ContrastLevel,float);
  virtual void SetBrightnessLevel(float brightness);
  vtkGetMacro(BrightnessLevel,float);
  virtual void SetHueLevel(float hue);
  vtkGetMacro(HueLevel,float);
  virtual void SetSaturationLevel(float saturation);
  vtkGetMacro(SaturationLevel,float);
  //@}

  //@{
  /**
   * Set/Get the video levels for monochrome/RGB: valid values are
   * between 0.0 and 255.0.
   */
  virtual void SetBlackLevel(float value);
  virtual float GetBlackLevel() {
    return this->BlackLevel; };
  virtual void SetWhiteLevel(float value);
  virtual float GetWhiteLevel() {
    return this->WhiteLevel; };
  //@}

  //@{
  /**
   * Set the system which you want use.  If you don't specify a system,
   * then your primary digitizer will be autodetected.
   */
  vtkSetStringMacro(MILSystemType);
  vtkGetStringMacro(MILSystemType);
  void SetMILSystemTypeToMeteor() { this->SetMILSystemType(VTK_MIL_METEOR); };
  void SetMILSystemTypeToMeteorII() { this->SetMILSystemType(VTK_MIL_METEOR_II); };
  void SetMILSystemTypeToMeteorIIDig() { this->SetMILSystemType(VTK_MIL_METEOR_II_DIG); };
  void SetMILSystemTypeToMeteorIICL() { this->SetMILSystemType(VTK_MIL_METEOR_II_CL); };
  void SetMILSystemTypeToMeteorII1394() { this->SetMILSystemType(VTK_MIL_METEOR_II_1394); };
  void SetMILSystemTypeToCorona() { this->SetMILSystemType(VTK_MIL_CORONA); };
  void SetMILSystemTypeToCoronaII() { this->SetMILSystemType(VTK_MIL_CORONA_II); };
  void SetMILSystemTypeToPulsar() { this->SetMILSystemType(VTK_MIL_PULSAR); };
  void SetMILSystemTypeToGenesis() { this->SetMILSystemType(VTK_MIL_GENESIS); };
  void SetMILSystemTypeToGenesisPlus() { this->SetMILSystemType(VTK_MIL_GENESIS_PLUS); };
  void SetMILSystemTypeToOrion() { this->SetMILSystemType(VTK_MIL_ORION); };
  void SetMILSystemTypeToCronos() { this->SetMILSystemType(VTK_MIL_CRONOS); };
  void SetMILSystemTypeToOdyssey() { this->SetMILSystemType(VTK_MIL_ODYSSEY); };
  //@}
  //@{
  /**
   * Set the system number if you have multiple systems of the same type
   */
  vtkSetMacro(MILSystemNumber,int);
  vtkGetMacro(MILSystemNumber,int);
  //@}

  //@{
  /**
   * Set the DCF filename for non-standard video formats
   */
  vtkSetStringMacro(MILDigitizerDCF);
  vtkGetStringMacro(MILDigitizerDCF);
  //@}

  //@{
  /**
   * Set the digitizer number for systems with multiple digitizers
   */
  vtkSetMacro(MILDigitizerNumber,int);
  vtkGetMacro(MILDigitizerNumber,int);
  //@}

  //@{
  /**
   * Set whether to display MIL error messages (default on)
   */
  virtual void SetMILErrorMessages(int yesno);
  vtkBooleanMacro(MILErrorMessages,int);
  vtkGetMacro(MILErrorMessages,int);
  //@}

  //@{
  /**
   * Allows fine-grained control
   */
  vtkSetMacro(MILAppID,long);
  vtkGetMacro(MILAppID,long);
  vtkSetMacro(MILSysID,long);
  vtkGetMacro(MILSysID,long);
  vtkGetMacro(MILDigID,long);
  vtkGetMacro(MILBufID,long);
  //@}

  /**
   * Initialize the driver (this is called automatically when the
   * first grab is done).
   */
  void Initialize() override;

  /**
   * Free the driver (this is called automatically inside the
   * destructor).
   */
  void ReleaseSystemResources() override;

  //@{
  /**
   * For internal use only
   */
  void *OldHookFunction;
  void *OldUserDataPtr;
  int FrameCounter;
  int ForceGrab;
  void InternalGrab() override;
  //@}

protected:
  vtkMILVideoSource();
  ~vtkMILVideoSource();

  virtual void AllocateMILDigitizer();
  virtual void AllocateMILBuffer();

  virtual char *MILInterpreterForSystem(const char *system);
  char *MILInterpreterDLL;

  int VideoChannel;
  int VideoInput;
  int VideoInputForColor;
  int VideoFormat;

  float ContrastLevel;
  float BrightnessLevel;
  float HueLevel;
  float SaturationLevel;

  float BlackLevel;
  float WhiteLevel;

  int FrameMaxSize[2];

  long MILAppID;
  long MILSysID;
  long MILDigID;
  long MILBufID;
  // long MILDispBufID;
  // long MILDispID;

  char *MILSystemType;
  int MILSystemNumber;

  int MILDigitizerNumber;
  char *MILDigitizerDCF;

  int MILErrorMessages;

  int MILAppInternallyAllocated;
  int MILSysInternallyAllocated;

  int FatalMILError;

  /**
   * Method for updating the virtual clock that accurately times the
   * arrival of each frame, more accurately than is possible with
   * the system clock alone because the virtual clock averages out the
   * jitter.
   */
  double CreateTimeStampForFrame(unsigned long frame);

  double LastTimeStamp;
  unsigned long LastFrameCount;
  double EstimatedFramePeriod;
  double NextFramePeriod;

private:
  vtkMILVideoSource(const vtkMILVideoSource&) = delete;
  void operator=(const vtkMILVideoSource&) = delete;
};

#endif
