
#ifndef _VIDEODEV_H_
#define _VIDEODEV_H_

#include <stdint.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <string.h>

#include <string>
#include <list>

#include "simpleskycam.h"
#include "json.h"
#include "gui.h"
#include "config.h"
#include "convert.h"
#include "video.h"
#include "videoframe.h"


enum {
	VDEV_STATUS_UNKNOWN,
	VDEV_STATUS_OK,
	VDEV_STATUS_AGAIN,
	VDEV_STATUS_ERROR
};

//
// jpeg error handling
//
struct jpg_error_mgr {
  struct jpeg_error_mgr pub;	/* "public" fields */

  jmp_buf setjmp_buffer;	/* for return to caller */
};
typedef struct jpg_error_mgr *jpg_error_ptr;


// callback status
enum {
	VDEV_CBSTATUS_NOTHING = 1,
	VDEV_CBSTATUS_NEWFRAME,
	VDEV_CBSTATUS_ERROR
};


struct {
	unsigned int id;
	int min;
	int max;
	int value;
	std::string name;
} typedef VideoDevCtrl;


struct {
	unsigned int size;
	unsigned char* data;
} typedef VideoInBuffer;


/*
 * data which we send to the main thread
 */
struct {
	int running;
	VideoFrame vf;
	VideoFrameRaw vfr;
} typedef VideoDevThreadData;

#ifndef CLEAR
#define CLEAR(x) memset (&(x), 0, sizeof (x))
#endif

/*
 * the run Start(..) needs to be called from a created thread process. It will not return until
 * another thread called the Stop() function or an error occured.
 *
 * New Devices will need to rewrite the following virtual functions:
 * Grab(), Open(), Close(), SetDevCtrl(), GetDevGtrl(), GetDeviceList(), GetCtrlList()
 */
class VideoDev {
private:
	std::string conf_device;			// device or filename to connect to
	std::string conf_devicename;		// human friendly name of the device
	std::string conf_format;			// video or image format (should every device have)
	std::string conf_parameter; 		// can hold additional parameters
	uint32_t pixelformat;				// pixelformat
	int conf_height;
	int conf_width;

	int running;						// 0 ... not running
										// 1 ... initialized (init, first frame)
										// 2 ... running
	ConvertData cdata;

	GMutex mutex;
	gboolean (*callback)(gpointer data);

	VideoDevThreadData threaddata;

	std::list<VideoDevCtrl> vidctrls;

	/* grabs a single frame, writes the RGB24 converted frame to the VideoFrame pointer */
	virtual int Grab(VideoFrameRaw *vf) { return VDEV_STATUS_AGAIN; };

	/* opens the device, will need to fill the controls as well */
	virtual int Open()  { return VDEV_STATUS_OK; };

	/* close the device */
	virtual int Close()  { return VDEV_STATUS_OK; };

	/* close the device */
	virtual int CaptureStart() { return VDEV_STATUS_OK; };

	/* close the device */
	virtual int CaptureStop() { return VDEV_STATUS_OK; };

	/* set the control */
	virtual int SetDevCtrl(unsigned int id, int value)  { return VDEV_STATUS_OK; };

	/* read a value from the control */
	virtual int GetDevCtrl(unsigned int id, int *value) { return VDEV_STATUS_OK; };

	friend class VideoDev_Dumpfile;
	friend class VideoDev_Simulation;
	friend class VideoDev_V4L2;
#ifdef USE_SVBONY
	friend class VideoDev_SVBCam;
#endif
#ifdef USE_VFW
	friend class VideoDev_VFW;
#endif
public:
	VideoDev();
	virtual ~VideoDev();

	static int get_bytesperpixel (uint32_t pixfmt);

	void SetConfig(std::string dev, int w, int h, std::string format, std::string parameter, gboolean (*callback_func)(gpointer data));
	void ThreadProcess();
	void Stop();
	int IsRunning() { return running; };
	void LockMutex() { g_mutex_lock(&mutex); };
	void UnLockMutex() { g_mutex_unlock(&mutex); };

	void GetVideoInfo(int *w, int *h, std::string *format);
	std::string GetDevice() { return conf_device; };

	int GetCtrlMinMaxValue(std::string name, int *min, int *max, int *value);
	int SetCtrlValue(std::string name, int value);

	/* fills the list with all found device */
	virtual int GetDeviceList(std::list<std::string> *list) { return VDEV_STATUS_OK; };
	virtual int GetDeviceFormats(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };
	virtual int GetDeviceResolutions(string device, std::list<string> *formats) { return VDEV_STATUS_OK; };

	int GetCtrlList(std::list<std::string> *list);

	/* returns a list with all control and thier parameters */
	list<VideoDevCtrl> GetCtrlsMinMaxValue();
};


#include "videodev-dumpfile.h"
#include "videodev-simulation.h"

#ifdef USE_V4L2
#include "videodev-v4l2.h"
#endif
#ifdef USE_SVBONY
#include "videodev-svbcam.h"
#endif
#ifdef USE_VFW
#include "videodev-vfw.h"
#endif

#endif
