#ifndef PMDCAMCUBESOURCEPLUGIN_H__
#define PMDCAMCUBESOURCEPLUGIN_H__

#include "ritkSourcePlugin.h"
#include "ritkThreadedJob.h"

#include "PMDCamCubeRImageSource.h"
#include "PMDCamCubeSourcePluginWidget.h"
#include "PMDCamCubeRImageIO.h"

#include <QMessageBox>
#include <QTimer>

// Forward declaration
class ConnectToCamJob;


/**	@class		PMDCamCubeSourcePlugin
 *	@author		Jakob Wasza / Sebastian Bauer
 *	@brief		player that gets its input from a PDM CamCube
 *
 *	@details
 */
class PMDCamCubeSourcePlugin : public ritk::SourcePlugin
{
	Q_OBJECT

public:
	/// Constructor
	PMDCamCubeSourcePlugin();
	/// Destructor
	virtual ~PMDCamCubeSourcePlugin();

	/// Get the plugins GUI @sa PluginBase::GetPluginGUI
	QWidget *GetPluginGUI();

	/** @name	Camera states */
	//@{
	enum CamInterfaceStateType
	{
		DisconnectedState,
		ConnectingState, 
		ConnectedState, 
		PlayLiveState,
	};
	/// Set the state
	void SetState(CamInterfaceStateType Type);
	/// Get the state
	CamInterfaceStateType GetState();
	/// Update the state
	void UpdateState();
	//@}

signals:
	/// Is emitted if a GUI updated is desired. Should be connected to the widget 
	void UpdateGUI();

public slots:
	/// Connect the player to the camera
	void Connect();
	/// Disconnect the player from the camera
	void Disconnect();
	/// Integration time for the camera
	void SetIntegrationTime(int value);
	/// Average source data
	void AverageSourceData(bool b);
	/// Number of frames to average source data
	void SetNumberOfFramesToAverageSourceData(int num);
	/// Play
	void PlayLive();
	/// Pause
	void PauseLive();
	/// Step
	void StepForwardLive();
	/// Stop
	void StopLive();
	/// Should be connected to the acquisition pipelines NewFrame() signal so we can tell the player widget to update its members
	void NewFrame();

protected:
	/// Must be provided. Returns a camera reader
	SourcePointer GetSource();

protected slots:
	/**	@brief	Request a single frame
	 *
	 *	@details
	 *	Request a single frame. This method will eventually execute the pipeline.
	 *	As this method is in a slot, it can be connected to a timer which allows
	 *	live playing. This method is thread safe.
	 */
	void RequestFrame();

	/**	@brief	Is called during connection to camera
	 *	@param	Result	The result of the connection attemp (true or false)
	 *	@param	Message	An optional message
	 */
	void ConnectionResult(bool Result, QString Message);

protected:
	/// The current state
	CamInterfaceStateType m_State;
	/// Mutex used to lock access to the state
	QMutex m_StateMutex;
	/// Timer for live playing
	QTimer *m_Timer;
	/// The file name for recording
	QString m_FileName;
	/** @name	The actual reader that is connected to the camera */
	//@{
	typedef PMDCamCubeRImageSourceF2 SourceType;
	typedef SourceType::Pointer SourcePointer;
	SourcePointer m_CameraSource;
	//@}
	/// The IO object
	PMDCamCubeRImageIOF2::Pointer m_PMDCamCubeRImageIO;
	/// The controlling widget
	PMDCamCubeSourcePluginWidget *m_PlayerWidget;
	/// Message box used during connecting
	QMessageBox *m_ConnectMessageBox;


	/// Due to Qt limitations
	friend class ConnectToCamJob;
};


/** @class	ConnectToCamJob
 *	@author	Jakob Wasza
 *	@brief	Class that is used to connect to camera
 *
 *	@details
 *	Simple class that connects to a camera. Connecting
 *	to the camera might hold the calling thread and has
 *	therefore to be done in a seperate thread. Due to
 *	Qt limitations this class cannot be nested into 
 *	the camera player.
 */
 class ConnectToCamJob : public ritk::ThreadedJob
{
	Q_OBJECT

public:
	/// Constructor
	ConnectToCamJob(PMDCamCubeSourcePlugin::SourcePointer Source);
	/// Destructor
	~ConnectToCamJob();

	/// Work is done here
	void Execute();

signals:
	/// Signal that is emitted when the process finished
	void Finished(bool Success, QString message=tr(""));

protected:
	/// The camera reader
	PMDCamCubeSourcePlugin::SourcePointer m_Source;

private:
	/// Purposely not implemented
	ConnectToCamJob();
};



#endif // PMDCAMCUBESOURCEPLUGIN_H__
