/**
    05Robot - Computer Vision Module

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

#include "Camera.h"
#include <iostream>
#include <fstream>

#ifdef __APPLE__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#pragma clang diagnostic ignored "-Woverloaded-virtual"
#include <PylonIncludes.h>
#include <gige/BaslerGigECamera.h>
#include <gige/BaslerGigEInstantCamera.h>
#pragma clang diagnostic pop
#else
#include <pylon/PylonIncludes.h>
#include <pylon/gige/BaslerGigECamera.h>
#include <pylon/gige/BaslerGigEInstantCamera.h>
#endif

using namespace Pylon;

typedef Pylon::CBaslerGigEInstantCamera Camera_t;
using namespace Basler_GigECameraParams;
using namespace Basler_GigEStreamParams;

using namespace std;

// Buffers for grabbing
const uint32_t c_nBuffers = 2;
/** \addtogroup ComputerVisionModule
 *  @{
 */
/**
 @brief Basler Gigabit Ethernet camera interface class
 */
class Camera_Basler_GigE: public Camera
{
	Q_OBJECT
    /**
     @brief Picture width in pixels
     */
	Q_PROPERTY(int Width READ width WRITE setWidth DESIGNABLE true USER true)
	Q_CLASSINFO("Width", "minimum=0;maximum=10000;singleStep=1;");
    /**
     @brief Picture height in pixels
     */
	Q_PROPERTY(int Height READ height WRITE setHeight DESIGNABLE true USER true)
	Q_CLASSINFO("Height", "minimum=0;maximum=10000;singleStep=1;");
    /**
     @brief Picture horizontal offset in pixels
     */
	Q_PROPERTY(int OffsetX READ offsetX WRITE setOffsetX DESIGNABLE true USER true)
	Q_CLASSINFO("OffsetX", "minimum=-1;maximum=10000;singleStep=1;");
    /**
     @brief Picture vertical offset in pixels
     */
	Q_PROPERTY(int OffsetY READ offsetY WRITE setOffsetY DESIGNABLE true USER true)
	Q_CLASSINFO("OffsetY", "minimum=-1;maximum=10000;singleStep=1;");
    /**
     @brief Raw exposure time
     */
	Q_PROPERTY(int ExposureTimeRaw READ exposureTimeRaw WRITE setExposureTimeRaw DESIGNABLE true USER true)
	Q_CLASSINFO("ExposureTimeRaw", "minimum=0;maximum=500000;singleStep=1;");
    /**
     @brief Red color balance ratio
     */
    Q_PROPERTY(int BalanceRatioRaw_red READ balanceRatioRaw_red WRITE setBalanceRatioRaw_red DESIGNABLE true USER true)
    Q_CLASSINFO("BalanceRatioRaw_red", "minimum=0;maximum=500000;singleStep=1;");
    /**
     @brief Green color balance ratio
     */
    Q_PROPERTY(int BalanceRatioRaw_green READ balanceRatioRaw_green WRITE setBalanceRatioRaw_green DESIGNABLE true USER true)
    Q_CLASSINFO("BalanceRatioRaw_green", "minimum=0;maximum=500000;singleStep=1;");
    /**
     @brief Blue color balance ratio
     */
    Q_PROPERTY(int BalanceRatioRaw_blue READ balanceRatioRaw_blue WRITE setBalanceRatioRaw_blue DESIGNABLE true USER true)
    Q_CLASSINFO("BalanceRatioRaw_blue", "minimum=0;maximum=500000;singleStep=1;");

public:
    /**
     @brief Initializes default parameters
     */
	Camera_Basler_GigE()
	{
		m_width=10000;
		m_height=10000;
		m_offsetx=-1;
		m_offsety=-1;
		m_exposuretimeraw=3599;
        m_balanceratioraw_red=108;
        m_balanceratioraw_green=64;
        m_balanceratioraw_blue=89;
		resultBufferYUV=NULL;
		Camera();
    }
    /**
     @brief Gets picture width in pixels
     */
	int width() const {return m_width;}
    /**
     @brief Sets picture width in pixels
     */
	void setWidth(const int& width) {m_width = width;}
    /**
     @brief Gets picture height in pixels
     */
	int height() const {return m_height;}
    /**
     @brief Sets picture height in pixels
     */
	void setHeight(const int& height) {m_height = height;}
    /**
     @brief Gets picture horizontal offset in pixels
     */
	int offsetX() const {return m_offsetx;}
    /**
     @brief Sets picture horizontal offset in pixels
     */
	void setOffsetX(const int& offsetx) {m_offsetx = offsetx;}
    /**
     @brief Gets picture vertical offset in pixels
     */
	int offsetY() const {return m_offsety;}
    /**
     @brief Sets picture vertical offset in pixels
     */
	void setOffsetY(const int& offsety) {m_offsety = offsety;}
    
    /**
     @brief Gets raw exposure time
     */
	int exposureTimeRaw() const {return m_exposuretimeraw;}
    /**
     @brief Sets raw exposure time
     */
	void setExposureTimeRaw(const int& exposuretimeraw) {
        m_exposuretimeraw = exposuretimeraw;
        if (pCamera != NULL) {
            pCamera->ExposureTimeRaw.SetValue(m_exposuretimeraw);
        }
    }
    /**
     @brief Gets red color balance ratio
     */
    int balanceRatioRaw_red() const {return m_balanceratioraw_red;}
    /**
     @brief Sets red color balance ratio
     */
    void setBalanceRatioRaw_red(const int& balanceratioraw_red) {
        m_balanceratioraw_red = balanceratioraw_red;
        if (pCamera != NULL) {
            pCamera->BalanceRatioSelector.SetValue(BalanceRatioSelector_Red);
            pCamera->BalanceRatioRaw.SetValue(m_balanceratioraw_red);
        }
    }
    /**
     @brief Gets green color balance ratio
     */
    int balanceRatioRaw_green() const {return m_balanceratioraw_green;}
    /**
     @brief Sets green color balance ratio
     */
    void setBalanceRatioRaw_green(const int& balanceratioraw_green) {
        m_balanceratioraw_green = balanceratioraw_green;
        if (pCamera != NULL) {
            pCamera->BalanceRatioSelector.SetValue(BalanceRatioSelector_Green);
            pCamera->BalanceRatioRaw.SetValue(m_balanceratioraw_green);
        }
    }
    /**
     @brief Gets green color balance ratio
     */
    int balanceRatioRaw_blue() const {return m_balanceratioraw_blue;}
    /**
     @brief Sets green color balance ratio
     */
    void setBalanceRatioRaw_blue(const int& balanceratioraw_blue) {
        m_balanceratioraw_blue = balanceratioraw_blue;
        if (pCamera != NULL) {
            pCamera->BalanceRatioSelector.SetValue(BalanceRatioSelector_Blue);
            pCamera->BalanceRatioRaw.SetValue(m_balanceratioraw_blue);
        }
    }
    
private:
	int	m_width;
	int	m_height;
	int	m_offsetx;
	int	m_offsety;
	int	m_exposuretimeraw;
    int m_balanceratioraw_red;
    int m_balanceratioraw_green;
    int m_balanceratioraw_blue;

	unsigned char* resultBufferYUV;

private: // statics
    static Pylon::PylonAutoInitTerm autoInitTerm;
	static CTlFactory& TlFactory;
	static ITransportLayer *pTl;
	static int started;

private:
		CDeviceInfo deviceInfo;
        Camera_t* pCamera = NULL;

public:
    /**
     @brief Pylon camera list
     */
    static DeviceInfoList_t devices;
    /**
     @brief Refreshes connected devices
     */
	static void refreshDevices()
	{
		pTl->EnumerateDevices(devices);
	}

	
public:
    /**
     @brief Connects to camera with given ID
     
     @param camera_id ID of camera to connect to
     
     @return Returns 0 on success
     */
	int connect(int camera_id);
    /**
     @brief Starts acquisition
     
     @return Returns 0 on success
     */
	int start();
    /**
     @brief Sends software trigger to camera
     
     @return Returns 0 on success
     */
	int sync();
    /**
     @brief Copies current internal buffer to resultBuffer or given output Mat
     
     @param output optional Mat to copy image to
     
     @return Returns 0 on success
     */
	int grab(cv::Mat* output = NULL);
    /**
     @brief Stops acquisition
     
     @return Returns 0 on success
     */
	int stop();
    /**
     @brief Disconnects from camera
     
     @return Returns 0 on success
     */
	int disconnect();
};
/** @}*/
#endif
