#include "ccamdriver_basler.h"
#include "pylon/PylonIncludes.h"
#include "ccam_basler.h"
#define  ALARM_CAMERA_COMMUNICATION 50240
typedef Camera_t::GrabResultPtr_t GrabResultPtr_t;
using namespace Pylon;
CCamDriver_Basler::CCamDriver_Basler(const QString& name, int32_t id)
    : CCamDriver(name, id)
{

}
CCamDriver_Basler::~CCamDriver_Basler()
{
    //PylonTerminate();
}
int32_t CCamDriver_Basler::grab_image(int32_t camid, CMImage* pImageDest)
{
	CCam_Basler* pCam=(CCam_Basler*)FindChannel(camid);
	Q_ASSERT(pCam);

	CPreciseTime timeStart;
    QMutexLocker locker2(&pCam->m_CHMutex);
	timeStart.StartTime();
    try
    {
        GrabResultPtr_t pGrabResult;
        if (!pCam->m_camera.IsGrabbing())
            pCam->m_camera.StartGrabbing(Pylon::GrabStrategy_LatestImageOnly);
        
        //抓取图像
        if (false == pCam->m_camera.RetrieveResult(1500, pGrabResult))
        {
            MQT_THROW_CODESTR(ALARM_CAMERA_COMMUNICATION, (m_sName + QObject::trUtf8("%1 Grab Immage Error,CamID:%2").arg(pCam->m_sName).arg(camid)));
        }

        int width = pCam->m_camera.Width.GetValue();
        int height = pCam->m_camera.Height.GetValue();
        if (width != (long)pCam->m_Variants.get_VData(Var_Cam_Width_ID)->toInt() ||
            height != (long)pCam->m_Variants.get_VData(Var_Cam_Height_ID)->toInt())
        {
            if (pCam->m_pRawImageData) delete[] pCam->m_pRawImageData;
            pCam->m_pRawImageData = new uint8_t[height * width];
            pCam->m_Variants.get_VData(Var_Cam_Width_ID)->setValue(int(width));
            pCam->m_Variants.get_VData(Var_Cam_Height_ID)->setValue(int(height));
        }
        memcpy(pCam->m_pRawImageData, (uint8_t*)(pGrabResult->GetBuffer()), width * height);
        locker2.unlock();
    }
    catch (const GenericException& ex)
    {
        //尝试重连
        if (false == pCam->Reconnect())
        {
            MQT_THROW_CODESTR(ALARM_CAMERA_COMMUNICATION, (m_sName + QObject::trUtf8("%1 Reconnect Cam Error CamID:%2").arg(pCam->m_sName).arg(camid)));
        }

        //采图失败直接
        MQT_THROW_CODESTR(ALARM_CAMERA_COMMUNICATION, (m_sName + QObject::trUtf8("%1 Grab Immage Error,CamID:%2").arg(pCam->m_sName).arg(camid)));

    }
    catch (const QString& sEx)
    {
        MqDebug() << sEx;
    }
	
    QMutexLocker locker1(&pCam->m_imageContainer.mutex);
	return CCamDriver::grab_image(camid,pImageDest);
}

int32_t CCamDriver_Basler::init_driver()
{
    PylonInitialize();

	CCamDriver::init_driver();
	CHANNELMAP::iterator ii=mchannels.begin();
	for(;ii!=mchannels.end();ii++)
	{
		CCam* pcam=(CCam*)(*ii);

		//if(pcam->m_iID != CAM6X)continue;
		set_auto_property(pcam->m_iID, Var_Cam_Exposure_ID,		false);
		set_auto_property(pcam->m_iID, Var_Cam_Gain_ID,			false);
	}

    return RTN_SUCCESS1;
}

int32_t CCamDriver_Basler::exit_driver()
{
    CCamDriver::exit_driver();

    PylonTerminate();

    return RTN_SUCCESS1;
}

int32_t CCamDriver_Basler::get_cam_property_range(int32_t camid, int32_t propertyid)
{
	//if(camid != CAM6X)return RTN_FAILED1;
    if (propertyid != Var_Cam_Gain_ID && propertyid != Var_Cam_Exposure_ID) {
        return RTN_FAILED1;
    }

    CCam_Basler* pCam = (CCam_Basler*)FindChannel(camid);
    if (propertyid == Var_Cam_Gain_ID) {
        QStringList& lrange = pCam->m_Variants.get_IndexList(propertyid);
        lrange.clear();
        lrange << QString::number(pCam->m_camera.Gain.GetMin()) << QString::number(pCam->m_camera.Gain.GetMax());
        return RTN_SUCCESS1;
    }

    if (propertyid == Var_Cam_Exposure_ID) {
        QStringList& lrange = pCam->m_Variants.get_IndexList(propertyid);
        lrange.clear();
        lrange << QString::number(pCam->m_camera.ExposureTime.GetMin()) << QString::number(pCam->m_camera.ExposureTime.GetMax());
        return RTN_SUCCESS1;
    }
    
    return RTN_FAILED1;
}

int32_t CCamDriver_Basler::set_cam_property(int32_t camid, int32_t propertyid, int32_t data, bool_t bsetdefault)
{
	//if(camid != CAM6X)return RTN_FAILED1;
	
	try{
		CCam_Basler* pCam = (CCam_Basler*)FindChannel(camid);
		if (propertyid == Var_Cam_Gain_ID) {

			pCam->m_camera.Gain.SetValue(data);
			//return RTN_SUCCESS1;
		}

		if (propertyid == Var_Cam_Exposure_ID) {
			pCam->m_camera.ExposureTime.SetValue(data);
			//return RTN_SUCCESS1;
		}
		}catch(const Pylon::GenericException &ex){
			MQT_THROW_CODESTR(ALARM_CAMERA_COMMUNICATION, QString(ex.GetDescription()));
		}

    return CCamDriver::set_cam_property(camid, propertyid, data, bsetdefault);
}

int32_t CCamDriver_Basler::autoadjust_property(int32_t camid)
{
    set_auto_property(camid, Var_Cam_Exposure_ID, true);
    set_auto_property(camid, Var_Cam_Gain_ID, true);

    int32_t time = m_Variants.get_VData(Var_CamDriver_AutoAdjust_Time_ID)->toInt();

    MSleep(time);

    set_auto_property(camid, Var_Cam_Exposure_ID, false);
    set_auto_property(camid, Var_Cam_Gain_ID, false);


    fresh_cam_property(camid, Var_Cam_Exposure_ID);
    fresh_cam_property(camid, Var_Cam_Gain_ID);

    CCam_Basler* pcam = (CCam_Basler*)FindChannel(camid);
    Q_ASSERT(pcam);
    pcam->m_Variants.get_VData(Var_Cam_Exposure_default_ID)->setValue(pcam->m_Variants.get_VData(Var_Cam_Exposure_ID)->toInt());
    pcam->m_Variants.get_VData(Var_Cam_Gain_default_ID)->setValue(pcam->m_Variants.get_VData(Var_Cam_Gain_ID)->toInt());

    //m_gSystem.m_bNeedFreshUI = true;
    return RTN_SUCCESS1;
}

int32_t CCamDriver_Basler::fresh_cam_property(int32_t camid, int32_t propertyid)
{
    CCam_Basler* pCam = (CCam_Basler*)FindChannel(camid);
    if (propertyid == Var_Cam_Gain_ID) {

        pCam->m_Variants.get_VData(Var_Cam_Exposure_ID)
            ->setValue(static_cast<int>(pCam->m_camera.Gain.GetValue()));
            
        return RTN_SUCCESS1;
    }

    if (propertyid == Var_Cam_Exposure_ID) {
        pCam->m_Variants.get_VData(Var_Cam_Exposure_ID)
            ->setValue(static_cast<int>(pCam->m_camera.ExposureTime.GetValue()));
        return RTN_SUCCESS1;
    }

    return RTN_FAILED1;
}

int32_t CCamDriver_Basler::set_auto_property(int32_t camid, int32_t propertyid, bool bAuto)
{
    CCam_Basler* pCam = (CCam_Basler*)FindChannel(camid);
    if (propertyid == Var_Cam_Gain_ID) {
        if (bAuto) {
            pCam->m_camera.GainAuto.SetValue(GainAuto_Continuous);
        } else {
            pCam->m_camera.GainAuto.SetValue(GainAuto_Off);
        }
        
        return RTN_SUCCESS1;
    }

    if (propertyid == Var_Cam_Exposure_ID) {
        if (bAuto) {
            pCam->m_camera.ExposureAuto.SetValue(ExposureAuto_Continuous);
        } else {
            pCam->m_camera.ExposureAuto.SetValue(ExposureAuto_Off);
        }
        return RTN_SUCCESS1;
    }

    return RTN_FAILED1;
}
