/**
    05Robot - Computer Vision Module

    @author P.Kaczmarek,J.Tomczynski,T.Mankowski
    @version 1.0 2017
*/
#ifndef CAMERAOBJECT_H
#define CAMERAOBJECT_H 

#include <QSemaphore>
#include <QObject>
#include <QString>
#include <QVariant>
#include "Serialization.hpp"
#include "Camera.h"
#include "ProcessorObject.h"

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>
#include <fstream>
#include <cxmlio.h>
/** \addtogroup ComputerVisionModule
 *  @{
 */
class ProcessorObject;

/**
 @brief Wrapper object containing single camera, managing its processing and control pipelines, and properties
 */
class  CameraObject : public cXmlIO
{
	Q_OBJECT
public:
    /**
     * @brief Display data type enum
     */
    enum DisplayData {
        DisplayRawImage, /**< Raw image */
        DisplayThreshold, /**< Thresholded image */
        DisplayPoints, /**< Points */
        DisplayNoImage, /**< No display */
    };
    
    /**
     @brief Camera calibration file path
     */
    ADD_PROPERTY(calibrationPath, QString)
	Q_PROPERTY(QString CalibrationFileName READ calibrationFileName WRITE setCalibrationFileName DESIGNABLE true USER true)
    
    /**
     @brief Display data type
     */
    ADD_PROPERTY(displayData, DisplayData)
	Q_ENUMS(DisplayData)

public:
    /**
     @brief Gets calibration file path
     */
	QString calibrationFileName() const {return m_calibrationFileName;}
    /**
     @brief Reads calibration file
     */
    void readCallibrationFile();
    /**
     @brief Sets calibration file path
     */
    void setCalibrationFileName(const QString& calibrationFileName) {m_calibrationFileName = calibrationFileName;readCallibrationFile();}
    
    virtual void writeXml(QXmlStreamWriter& xml);
    virtual void readXml(QXmlStreamReader& xml);
    //cImagePocessing *markersGenerator;
private:
	QString	m_calibrationFileName;
	int n_img;
	
	int matType;
	bool first_grab;
	cv::Mat frame;
	cv::Mat thresh;
	vector<vector<cv::Point> > contours;
	vector<cv::Point2f> points;
	ofstream output_file;
	
	bool doRemap;
	cv::Mat map1,map2;

public:
    /**
     @brief Camera matrix
     */
	cv::Mat cameraMatrix;
    /**
     @brief Distortion coefficients
     */
	cv::Mat distCoeffs;
    /**
     @brief Camera name
     */
	QString cameraName;

public:
	QSemaphore * syncSem;
    CameraObject(Camera *c, int camType, int camId, QSemaphore *ss);
    ~CameraObject()
    {
		qDebug("deleting co");
		if(isRunning)
			cam->stop();
		cam->disconnect();
        //delete markersGenerator;
//			QFile ser(cameraName+".set");
//		ser.open(QIODevice::WriteOnly);
//		if(ser.isOpen())
//		{
//			QDataStream out(&ser);
//			out<<*this;
//			out<<*cam;
//			ser.close();
//		}
		delete cam;
	}

public:
    /**
     @brief Pointer to corresponding Camera
     */
	Camera* cam;
    /**
     @brief Corresponding camera type
     */
	int cameraType;
    /**
     @brief Corresponding camera ID
     */
	int cameraID;
    /**
     @brief Camera running flag
     */
	bool isRunning;

public slots:
    /**
     @brief Starts camera pipeline, sets isRunning to true
     */
	void cStart();
    /**
     @brief Sends software trigger to camera
     */
	void cSync();
    /**
     @brief Copies image from internal buffer to requested buffers
     */
	void cGrab();
    /**
     @brief Stops camera pipeline, sets isRunning to true
     */
	void cStop();
	
	void requestImage(void*, void*); // (cv::Mat *, QSemaphore *)
	void requestPoints2(void*, void*); // (vector<cv::Point> *, QSemaphore * camSem)

signals:
    /**
     @brief Emitted at finish of each frame capture
     
     @param image Pointer to image data
     @param width Image width
     @param height Image height
     */
	void frameOut(cv::Mat* image, int width, int height);
    /**
     @brief Data logger
     
     @param info text to log
     */
	void writeInfo(QString info);

};
/** @}*/
#endif
