/**@file camera.h: Windows capturing device prototypes. */

#ifndef __CAMERA_H__
#define __CAMERA_H__

//#define DIRECT3D_VERSION 0x0900

#include <string>
#include <vector>

#include <comdef.h>

#if _MSC_VER < 1400	// (Visual Studio 2005)
 #include <dshow.h>
 #include <qedit.h>
#else
 #include "../../../fix_c/ddraw.h"
 #include "../../../fix_c/control.h"
 #include "../../../fix_c/qedit.h"
 #include "../../../fix_c/amvideo.h"
 #include <uuids.h>
 #include <strmif.h>
#endif


#include "../../points.h"


// define smart pointer types for DirectShow COM interfaces
_COM_SMARTPTR_TYPEDEF(IGraphBuilder, __uuidof(IGraphBuilder));
_COM_SMARTPTR_TYPEDEF(IFilterGraph, __uuidof(IFilterGraph));
_COM_SMARTPTR_TYPEDEF(IMediaControl, __uuidof(IMediaControl));
_COM_SMARTPTR_TYPEDEF(ICaptureGraphBuilder2, __uuidof(ICaptureGraphBuilder2));
_COM_SMARTPTR_TYPEDEF(IBaseFilter, __uuidof(IBaseFilter));
_COM_SMARTPTR_TYPEDEF(ISampleGrabber, __uuidof(ISampleGrabber));
_COM_SMARTPTR_TYPEDEF(IAMStreamConfig, __uuidof(IAMStreamConfig));


class wxTimer;
class wxFrame;


/** Wrapper around moniker for one camera. */
class CameraInfo
{
friend class CameraInput;

private:  
  IMonikerPtr moniker;
  std::wstring name;

public:  

  CameraInfo(_bstr_t _name, IMonikerPtr _moniker) throw() :
    name(_name, _name.length()),
    moniker(_moniker)
  { };

  const std::wstring& GetName() const throw()
  { return(name); };

};



/** Main class that handles camera device. */
class CameraInput: public CameraDevice, virtual public ISampleGrabberCB
{
private:  
  IMediaControlPtr    graph;		///< containder for camera-grabber stuff
  IAMStreamConfigPtr  camera;		///< Camera related pin from Camera_Base - used for obtaining config; not required.
  ISampleGrabberPtr   grabber;		///< camera grabber that stores data

  ICaptureGraphBuilder2Ptr capbuilder;
  IBaseFilterPtr camera_base;
  IBaseFilterPtr grabber_base;
  IBaseFilterPtr filter_base;

  IMediaSample * volatile m_MediaSample;

  //std::vector<unsigned char> rawbuffer; ///< raw buffer that stores data from camera

  int Width, Height, Planes;		///< internal image properties  
  REFERENCE_TIME FrameDuration, MinFrameDuration, MaxFrameDuration;
  wxString IntName;
  bool GraphIsBuilt;

  bool BuildGraph(void);
  //void UseFilterDV(void);
  void UseFilter(const CLSID & FilterCleId);
  void ProcessMediaType(AM_MEDIA_TYPE *mediatype);

  LONG m_cRef;				///< DCOM reference counter
  DWORD TickCount;  

public:
  wxFrame *pWxObj;

  explicit CameraInput(const CameraInfo& ci);
  virtual ~CameraInput();
  //CameraInput(_bstr_t _name, IMonikerPtr _moniker);
  
  virtual void *PeekImediaSample(int *Size, IMediaSample **tmpMediaSample);
  virtual void ClearImediaSample(void);  

  //virtual void GrabImage(void);
  //virtual const unsigned char *GetBufferData(void);
  virtual const wxChar *GetName(void) const;

    //comment next line do dismantle wx dependency
  virtual void ChangeResolution(void);

    //interface implemantation CameraDriver
  virtual int GetWidth(void) {return Width;}
  virtual int GetHeight(void) {return Height;}
  virtual int GetDepth(void) {return Planes;}
  virtual double GetFrameRate(int What=0);
  virtual void ShowPropertyPage(size_t hOwner=0);

  virtual void SelectVideoMode(int ReqWidth=320, int ReqHeight=240, int ReqDepth=-1, double NewFrameRate=0);
  static EVideoFormats GetVideoformat(const GUID *MediaSubtype);

  virtual bool Start(void);
  virtual void Stop(bool StopGraph=false);
  virtual unsigned GetLastScan(void) const {return TickCount;}  
  virtual void HookFrame(wxFrame *pFrame2Hook) {pWxObj=pFrame2Hook;} 

public:
// Interface IUnknown - procedure prototypes
  ULONG __stdcall AddRef();
  ULONG __stdcall Release();
  HRESULT __stdcall QueryInterface(REFIID riid, void **ppv);

// Interface ISampleGrabberCB - procedure prototypes
  HRESULT __stdcall BufferCB(double SampleTime, BYTE *pBuffer, long BufferLen);
  HRESULT __stdcall SampleCB(double SampleTime, IMediaSample *pSample);
};


extern void FireSampleCB(wxFrame *pWxObj);


typedef union
  {
  VIDEO_STREAM_CONFIG_CAPS v;
  AUDIO_STREAM_CONFIG_CAPS a;
  } TAudVidConfCaps;


#endif // __CAMERA_H__
