#include "ccamdriver_img.h"
#include "ccam_img.h"
//#include "WinDef.h"
#include "base.h"
#ifndef OUTOFRANGE
#define OUTOFRANGE(md,mmin,mmax) ((md)>=(mmax)||(md)<(mmin))
#endif

#define LESSER_THAN(md, mmin) ((md)<(mmin))
#define GREATER_THAN(md, mmax) ((md)>(mmax))

#define MAX_EXPOSE_MS 30
#define MIN_EXPOSE_MS  0.5
#define MAX_GAIN

#define  ALARM_CAMERA_COMMUNICATION 50240
CCamDriver_IMG::CCamDriver_IMG(const QString &name, int32_t id)
    :CCamDriver(name,id)
{

}

CCamDriver_IMG::~CCamDriver_IMG()
{

}

int32_t CCamDriver_IMG::init_driver()
{
    if (!DShowLib::InitLibrary(0))
    {
        MQT_THROW_STR(m_sName+QObject::trUtf8(":driver Init Failed"));
    }
    int irtn=CCamDriver::init_driver();

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

	set_auto_property(pcam->m_iID, Var_Cam_Exposure_ID,		false);
	set_auto_property(pcam->m_iID, Var_Cam_Gain_ID,			false);
	set_auto_property(pcam->m_iID, Var_Cam_Brightness_ID,	false);
	set_auto_property(pcam->m_iID, Var_Cam_Contrast_ID,		false);

	}
    return irtn;
}

int32_t CCamDriver_IMG::exit_driver()
{
    CCamDriver::exit_driver();
    _DSHOWLIB_NAMESPACE::ExitLibrary();
    return RTN_SUCCESS1;
}

int32_t CCamDriver_IMG::grab_image(int32_t camid, CMImage *pImageDest)
{
    CCam_IMG* pcam=(CCam_IMG*)FindChannel(camid);
    Q_ASSERT(pcam);
	
	//LOG(INFO) << "Start Capture" << camid <<endl;
	FrameTypeInfo typeInfo;
	(*pcam->m_pSink)->getOutputFrameType(typeInfo);
	//int formatId = typeInfo.getColorformat();
	uint32_t width= typeInfo.dim.cx;
	uint32_t height=typeInfo.dim.cy;

	//LOG(INFO) << "Get　getOutputFrameType" << camid <<endl;
	CPreciseTime timeStart;
	timeStart.StartTime();
	tFrameQueueBufferPtr pFrame;
	Error e =(*pcam->m_pSink)->snapSingle(pFrame, 1500);
	if(e.isError()){
		//LOG(ERROR)<<e.getString();
		//LOG(ERROR)<<" Capture Err:ID"<<pcam->m_iID << " ERR:"<< e.getString();
		if(false == pcam->m_pGrabber->stopLive()){
			//LOG(ERROR) << "m_pGrabber->stopLive1 Error:" << pcam->m_pGrabber->getLastError().getString() <<endl;
		}
		if(false == pcam->m_pGrabber->startLive( false ))
		{
			//LOG(ERROR) << "m_pGrabber->startLive1 Error:" << pcam->m_pGrabber->getLastError().getString() <<endl;
		}
		e =(*pcam->m_pSink)->snapSingle(pFrame, 1500);
		if(e.isError()){
			//LOG(ERROR)<<" Capture Retry Err:" << e.getString();
			if(false == pcam->m_pGrabber->stopLive()){
				//LOG(ERROR) << "m_pGrabber->stopLive Error:" << pcam->m_pGrabber->getLastError().getString() <<endl;
			}
			if(false == pcam->m_pGrabber->startLive( false ))
			{
				//LOG(ERROR) << "m_pGrabber->startLive Error:" << pcam->m_pGrabber->getLastError().getString() <<endl;
			}
			if(false == pcam->Reconnect()){
				//LOG(ERROR) << "Reconnect capture failed"<<"camera:"<<pcam->m_sName.toStdString().c_str();
				MQT_THROW_CODESTR(ALARM_CAMERA_COMMUNICATION, (m_sName+QObject::trUtf8("%1 Reconnect Cam Error CamID:%2").arg(pcam->m_sName).arg(camid)));
			}
			e =(*pcam->m_pSink)->snapSingle(pFrame, 1500);
			(*pcam->m_pSink)->getOutputFrameType(typeInfo);
			//int formatId = typeInfo.getColorformat();
			width= typeInfo.dim.cx;
			height=typeInfo.dim.cy;
			if(e.isError())
			{
				//LOG(ERROR) << "Reconnect and grab m_pGrabber->startLive Error:" << pcam->m_pGrabber->getLastError().getString() <<endl;
				MQT_THROW_CODESTR(ALARM_CAMERA_COMMUNICATION, (m_sName+QObject::trUtf8("%1 Reconnect Cam Error CamID:%2").arg(pcam->m_sName).arg(camid)));
				return RTN_FAILED1;
			}
		}else{
			//LOG(ERROR)<<"Retry capture image successed";
		}
	}

	//wchar_t buf[MAX_PATH] = {};
	//swprintf_s( buf, L"file%d.bmp", camid);
	//saveToFileBMP(*pFrame, buf, eY800 );
	
	//uint8_t* ptr = pFrame->getPtr();

	//pcam->m_Variants.set_VData(Var_Cam_Width_ID,int(width));
	//pcam->m_Variants.set_VData(Var_Cam_Height_ID,int(height));

	//QMutexLocker locker1(&pcam->m_imageContainer.mutex);
	//if(width!=(uint32_t)pcam->m_Variants.get_VData(Var_Cam_Width_ID)->toInt()||
	//height!=(uint32_t)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.set_VData(Var_Cam_Width_ID,int(width));
	////pcam->m_Variants.set_VData(Var_Cam_Height_ID,int(height));
	////pcam->m_imageContainer.m_Image=CMImage(width,height,(uint8_t*)( pFrame->getPtr()));
	//}
	//int iMirrortype=NO_MIRROR;
	//uint iFilpytpe= pcam->m_Variants.get_VData(Var_Cam_Image_Filp)->toUInt();
	//switch(iFilpytpe)
	//{
	//case 1:iMirrortype=MIRROR_H; break;
	//case 2:iMirrortype=MIRROR_V; break;
	//case 3:iMirrortype=MIRROR_VH; break;
	//default:break;
	//}

	//QImage img((uchar*)pFrame->getPtr(),width,height,
	//	QImage::Format_Grayscale8);

	//bool b = img.save("file2.bmp","BMP");

	//pcam->m_pRawImageData=new uint8_t[height*width];
	//
	//LOG(INFO) << "Start Capture Mutex" << camid <<"time" <<timeStart.GetTime()*1000<<"ms";
	QMutexLocker locker1(&pcam->m_imageContainer.mutex);
	//LOG(INFO) << "End Capture Mutex" << camid <<endl;
  //  memcpy_mirror(pcam->m_pRawImageData,(uint8_t*)(pFrame->getPtr()), 
		//width, height, NO_MIRROR,false);
	memcpy(pcam->m_pRawImageData,(uint8_t*)(pFrame->getPtr()), width*height);
	//LOG(INFO) << "End Capture Cpy Mirror" << camid <<endl;
	//pcam->m_pRawImageData  pcam->m_imageContainer.m_Image.m_pRawImageData 
	//第一次会new后面就共用内存，但是这里分配了两块内存
	

    CCamDriver::grab_image(camid,pImageDest);
	//LOG(INFO) << "Stop Capture"<<timeStart.GetTime();
    return RTN_SUCCESS1;
}

int32_t CCamDriver_IMG::get_cam_property_range(int32_t camid, int32_t propertyid)
{
    CCam_IMG* pcam=(CCam_IMG*)FindChannel(camid);
    Q_ASSERT(pcam);
	
	if(Var_Cam_Exposure_ID == propertyid || propertyid == Var_Cam_Gain_ID)
	{
		tIVCDAbsoluteValuePropertyPtr propItemRange = pcam->m_pGrabber->getVCDPropertyInterface<IVCDAbsoluteValueProperty>(get_property_guid(propertyid), VCDElement_Value);
		if( propItemRange == NULL )
		{
			QStringList& lrange=pcam->m_Variants.get_IndexList(propertyid);
			lrange << "0" << "1";
			return RTN_FAILED1;
		}
		else
		{
			QStringList& lrange=pcam->m_Variants.get_IndexList(propertyid);
			if(propertyid == Var_Cam_Gain_ID){
				lrange.clear();
				//qDebug() << propertyid << "Min :" << propItemRange->getRangeMin() << "Max:" << propItemRange->getRangeMax() << endl;
				lrange<<QString::number((int)propItemRange->getRangeMin())<<QString::number((int)propItemRange->getRangeMax());
				//qDebug() << lrange << endl;
			}else{
				lrange.clear();
				int min = propItemRange->getRangeMin()*1000;
				if(min < MIN_EXPOSE_MS){
					min = MIN_EXPOSE_MS;
				}
				
				int max = propItemRange->getRangeMax()*1000;
				if(max > MAX_EXPOSE_MS){
					max = MAX_EXPOSE_MS;
				}
				min = min*1000;
				max = max*1000;
				lrange<<QString::number(min)<<QString::number(max);
			}
		}
	}
	else
	{
		tIVCDRangePropertyPtr propItemRange = pcam->m_pGrabber->getVCDPropertyInterface<IVCDRangeProperty>(get_property_guid(propertyid), VCDElement_Value);
		if( propItemRange == NULL )
		{
			QStringList& lrange=pcam->m_Variants.get_IndexList(propertyid);
			lrange << "0" << "1";
			return RTN_FAILED1;
		}
		else
		{
			QStringList& lrange=pcam->m_Variants.get_IndexList(propertyid);
			lrange.clear();
			lrange<<QString::number(propItemRange->getRangeMin())<<QString::number(propItemRange->getRangeMax());
		}
	}
	

    return RTN_SUCCESS1;
}

int32_t CCamDriver_IMG::set_cam_property(int32_t camid, int32_t propertyid,
                                         int32_t data, bool_t bsetdefault)
{
	CCam_IMG* pcam=(CCam_IMG*)FindChannel(camid);
	Q_ASSERT(pcam);
	if(propertyid == Var_Cam_Exposure_ID || propertyid==Var_Cam_Gain_ID)
	{
		tIVCDAbsoluteValuePropertyPtr propItemRange = pcam->m_pGrabber->getVCDPropertyInterface<IVCDAbsoluteValueProperty>(get_property_guid(propertyid), VCDElement_Value);
		if( propItemRange == NULL )
		{
			return RTN_FAILED1;
		}
		else
		{
			
			if(propertyid==Var_Cam_Exposure_ID)
			{
				//单位为us
				double newValue = data/1000.0;
				if(LESSER_THAN(newValue, MIN_EXPOSE_MS)){
					newValue = MIN_EXPOSE_MS/1000.0;
				}
				else if(GREATER_THAN(newValue, MAX_EXPOSE_MS)){
					newValue = MAX_EXPOSE_MS/1000.0;
				}else{
					newValue = newValue/1000;
				}
				propItemRange->setValue(newValue);
				return CCamDriver::set_cam_property(camid,propertyid,data,bsetdefault);
			}
			
			double min = propItemRange->getRangeMin();
			double max = propItemRange->getRangeMax();
			if(LESSER_THAN(data, min)){
				propItemRange->setValue(min);
			}
			else if(GREATER_THAN(data, max)){
				propItemRange->setValue(max);
			}else{
				propItemRange->setValue(data);
			}
		}
	}
	else
	{
		tIVCDRangePropertyPtr propItemRange = pcam->m_pGrabber->getVCDPropertyInterface<IVCDRangeProperty>(get_property_guid(propertyid), VCDElement_Value);
		if( propItemRange == NULL )
		{
			return RTN_FAILED1;
		}
		else
		{
			long min = propItemRange->getRangeMin();
			long max = propItemRange->getRangeMax();
			if(LESSER_THAN(data, min)){
				propItemRange->setValue(min);
			}
			else if(GREATER_THAN(data, max)){
				propItemRange->setValue(max);
			}else{
				propItemRange->setValue(data);
			}
		}
	}
    return CCamDriver::set_cam_property(camid,propertyid,data,bsetdefault);
}

int32_t CCamDriver_IMG::fresh_cam_property(int32_t camid, int32_t propertyid)
{
    CCam_IMG* pcam=(CCam_IMG*)FindChannel(camid);
    Q_ASSERT(pcam);
	if(propertyid == Var_Cam_Exposure_ID || propertyid==Var_Cam_Gain_ID)
	{
		tIVCDAbsoluteValuePropertyPtr propItemRange = pcam->m_pGrabber->getVCDPropertyInterface<IVCDAbsoluteValueProperty>(get_property_guid(propertyid), VCDElement_Value);
		if( propItemRange == NULL )
		{
			pcam->m_Variants.get_VData(propertyid)->setValue((int)0);
			return RTN_FAILED1;
		}
		else
		{
			if(propertyid == Var_Cam_Exposure_ID){
				long data = propItemRange->getValue() * 1000;
				if(data<MIN_EXPOSE_MS){
					data = MIN_EXPOSE_MS;
				}
				if(data>MAX_EXPOSE_MS){
					data = MAX_EXPOSE_MS;
				}
				data *= 1000;
				pcam->m_Variants.get_VData(propertyid)->setValue(int(data));
				return RTN_SUCCESS1;
			}

			long data = propItemRange->getValue();
			pcam->m_Variants.get_VData(propertyid)->setValue(int(data));
			return RTN_SUCCESS1;
		}
	}
	else
	{
		tIVCDRangePropertyPtr propItemRange = pcam->m_pGrabber->getVCDPropertyInterface<IVCDRangeProperty>(get_property_guid(propertyid), VCDElement_Value );
		if( propItemRange == NULL )
		{
			pcam->m_Variants.get_VData(propertyid)->setValue((int)0);
			return RTN_FAILED1;
		}
		else
		{
			long data = propItemRange->getValue();
			pcam->m_Variants.get_VData(propertyid)->setValue(int(data));
	
		}
	}

    return RTN_SUCCESS1;
}

int32_t CCamDriver_IMG::autoadjust_property(int32_t camid)
{
	CCam_IMG* pcam=(CCam_IMG*)FindChannel(camid);
	Q_ASSERT(pcam);
    set_auto_property(camid, Var_Cam_Exposure_ID,	true);
	set_auto_property(camid, Var_Cam_Gain_ID,		true);
	set_auto_property(camid, Var_Cam_Brightness_ID,	true);
	set_auto_property(camid, Var_Cam_Contrast_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);
	set_auto_property(camid, Var_Cam_Brightness_ID,	false);
	set_auto_property(camid, Var_Cam_Contrast_ID,	false);

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

    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());
    pcam->m_Variants.get_VData(Var_Cam_Brightness_default_ID)->setValue(pcam->m_Variants.get_VData(Var_Cam_Brightness_ID)->toInt());
    pcam->m_Variants.get_VData(Var_Cam_Contrast_default_ID)->setValue(pcam->m_Variants.get_VData(Var_Cam_Contrast_ID)->toInt());

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

GUID CCamDriver_IMG::get_property_guid(int propertyid)
{
	Q_ASSERT(!OUTOFRANGE(propertyid, Var_Cam_Exposure_ID, Var_Cam_Contrast_ID+1));
	switch(propertyid){
	case Var_Cam_Exposure_ID://曝光
		return VCDID_Exposure;
		break;
	case Var_Cam_Gain_ID://增益
		return VCDID_Gain;
		break;
	case Var_Cam_Brightness_ID:
		return VCDID_Brightness;
		break;
	case Var_Cam_Contrast_ID:	//对比度
		return VCDID_Contrast;
		break;
	default:
		return VCDID_Exposure;
		break;
	}
}

int32_t CCamDriver_IMG::set_auto_property(int32_t camid,int32_t propertyid, bool bAuto)
{
	CCam_IMG* pcam=(CCam_IMG*)FindChannel(camid);
	Q_ASSERT(pcam);
	tIVCDSwitchPropertyPtr propItemAuto = pcam->m_pGrabber->getVCDPropertyInterface<IVCDSwitchProperty>(get_property_guid(propertyid), VCDElement_Auto);
	if( propItemAuto == NULL )
	{
		return RTN_FAILED1;
	}
	else
	{
		propItemAuto->setSwitch(bAuto);
	}

	return RTN_SUCCESS1;
}

