#ifndef VIDEO_DEVICE_HPP
#define VIDEO_DEVICE_HPP

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <sys/types.h>
#include <linux/videodev.h>

#include <qarray.h>
#include <qcolor.h>
#include <qimage.h>
#include <qobject.h>
#include <qsocketnotifier.h>
#include <qtimer.h>
#include <qvector.h>

#include "VideoDeviceInput.h"
#include "VideoAudioInput.h"

class CVideoDevice: public QObject
{
friend class CVideoDeviceInput;
friend class CVideoDeviceTuner;
friend class CVideoAudioInput;
   Q_OBJECT
private:
   bool validated;
   QString NodeName, IntfName;
   int CamFD, Opened;
   bool UseSelect, HasFramerate;
   int Capturing;
   int Palette, FrameRate;
   int PalRGB, PalYUV;
   struct video_picture VPic;
   struct video_mbuf VMBuf;
   int Buffers, CurBuffer;

   QVector <CVideoDeviceInput>VideoInputs;
   int CurrentVideoInput;
   QVector <CVideoAudioInput>AudioInputs;
   int CurrentAudioInput;

   QVector<QImage> RGB;
   QVector<QImage> Y, U, V;
   QImage *pNullImage;
   QRgb GrayScale[256];

   int image_w, image_h;
   int max_w, max_h;
   int min_w, min_h;
   uchar *vid_io_buffer;		// The buffer used for I/O; this can be mmap()ed or malloc()ed
   uchar *rgb_vid_buffer;		// The buffer for rgb images; may point to vid_io_buffer
   uchar *yuv_vid_buffer;		// The buffer for yuv images; may point to vid_io_buffer
   QArray<int> vid_io_offsets, rgb_vid_offsets, yuv_vid_offsets;
   int vid_io_buffer_size, vid_io_image_size;

   QSocketNotifier *pImageSocket;
   QTimer *pImageTimer;

   void Init();
   void CleanUp();

   bool TryPalette(int pal, int depth);
   void SetPalette();
   void CalcVidIoSize();
   
   int MCapture(int buf);
   int MSync();

   void CreateImagesRGB();
   void ResetImagesRGB();
   void CreateImagesYUV();
   void ResetImagesYUV();
   
   void StartCapture();
   void StopCapture();

private slots:
   void LoadImage();

public:
   CVideoDevice(const QString &node_name);
   ~CVideoDevice();

   bool IsValid();

   int Open(int buffers = 1);
   void Close();
   int GetDescriptor() const;
   
   void EnableRGB(bool isOn);
   void EnableYUV(bool isOn);

   QString GetNodeName() const;
   QString GetIntfName() const;
   
   QSize GetMinSize() const;
   QSize GetSize();
   QSize GetMaxSize() const;
   bool  SetSize(int width, int height);
   bool  SetSize(const QSize &new_size);
   int   GetFramerate() const;
   bool  SetFramerate(int fps);
   int   GetMBuffers() const;
   int   GetBuffers() const;

   int   GetVideoInputs() const;
   int   GetCurrentVideoInput() const;
   CVideoDeviceInput *GetVideoInput(int number = -1) const;
   bool  SelectVideoInput(int number);
   
   int   GetAudioInputs() const;
   CVideoAudioInput *GetAudioInput(int number = -1) const;
   bool  SelectAudioInput(int number);
   
   int GetBrightness() const;
   bool SetBrightness(int val);
   int GetContrast() const;
   bool SetContrast(int val);
   int GetHue() const;
   bool SetHue(int val);
   int GetColour() const;
   bool SetColour(int val);
   int GetWhiteness() const;
   bool SetWhiteness(int val);
   
   int ReadImage();

   QImage *GetRGB(int offset = 0) const;
   QImage *GetY(int offset = 0) const;
   QImage *GetU(int offset = 0) const;
   QImage *GetV(int offset = 0) const;

signals:   
   /** A new image is available. */
   void Notify();
   /** The device is being closed by the last user; the device is not accessible */
   void Closed();
   /** The size has been changed. */
   void Resized(const QSize &new_size);
   /** The frame rate has been changed. */
   void FramerateChanged(int);
   /** The video input channel has changed. */
   void ChangedVideoInput(int input);
   /** The frequency or norm changed. */
   void ChangedTunerNorm(int tuner, int norm);
   /** An error occured. err_num is one of the errno values. */
   void Error(int err_num);
};

#endif
