#include "CaptureThreadHIK.h"
#include <QtWidgets/QApplication>
#include "PLCDevice.h"
#include "common.h"
#include <windows.h>
extern bool g_debug_mode;	//相机调试模式，工作模式必须停止状态才能打开
extern SingleCamInfoStruct SingleCamInfo[NumberOfSupportedCameras];
extern PLCDevice * m_PLCDevice;

inline void LossCallBackfunction(unsigned int pData, void* pUser){
	try{
		CaptureThreadHIK* CaptureThreadHIKptr = (CaptureThreadHIK*)pUser;
		SingleCamInfo[CaptureThreadHIKptr->Local_Num].OffLine = true;
		CaptureThreadHIKptr->terminate();
	}
	catch(...){
		std::cout << "LossCallBackfunction error" << std::endl;
	}
}
inline void FallingGpioEventfunction(MV_EVENT_OUT_INFO* pEventInfo, void* pUser){
	try{
		CaptureThreadHIK* CaptureThreadHIKptr = (CaptureThreadHIK*)pUser;
		int unit_count = CaptureThreadHIKptr->p_unit_queue->count();
		if (unit_count > 0)
		{
			cv::Mat long_image;
			for (int i = 0; i < unit_count; i++)
			{
				cv::Mat image;
				CaptureThreadHIKptr->p_unit_queue->take(image);
				if (0 == i)
				{
					long_image = cv::Mat::zeros(image.rows * unit_count, image.cols, image.type());
				}
				cv::Rect r(0, i * image.rows, image.cols, image.rows);
				cv::Mat roi = long_image(r);
				image.copyTo(roi);
			}
			CaptureThreadHIKptr->p_image_queue->put(std::make_pair(unit_count, long_image));
			CaptureThreadHIKptr->p_shooted_queue->put(true);
		}
		CaptureThreadHIKptr->p_unit_queue->clear();
	}
	catch(...){
		std::cout << "FallingGpioEventfunction error" << std::endl;
	}
}
inline void RisingGpioEventfunction(MV_EVENT_OUT_INFO* pEventInfo, void* pUser){
	try{
		CaptureThreadHIK* CaptureThreadHIKptr = (CaptureThreadHIK*)pUser;
#ifdef IMM_FEED_BACK
		if (CaptureThreadHIKptr->p_shooted_queue->count() > 0)
		{
			bool temp;
			CaptureThreadHIKptr->p_shooted_queue->take(temp);
		}

#elif defined ONE_TIME_SHIFT
		if(
			CaptureThreadHIKptr->p_shooted_queue->count() > 0
		#if defined DOUBLE_FEED_BACK
			|| CaptureThreadHIKptr->p_double_queue->count() > 0
		#endif
		)
		{
			if (CaptureThreadHIKptr->p_shooted_queue->count() > 0){
				bool temp;
				CaptureThreadHIKptr->p_shooted_queue->take(temp);
			}
			CaptureThreadHIKptr->m_threadFunc.SendFeedBack(EdgeEvent);
		}
#else
		if(CaptureThreadHIKptr->p_result_wait_queue->count() > 0)
		{
			bool temp;
			CaptureThreadHIKptr->p_result_wait_queue->take(temp);
			CaptureThreadHIKptr->m_threadFunc.SendFeedBack(EdgeEvent);
		}
		if(CaptureThreadHIKptr->p_shooted_queue->count() > 0)
		{
			bool temp;
			CaptureThreadHIKptr->p_shooted_queue->take(temp);
			CaptureThreadHIKptr->p_result_wait_queue->put(true);
		}
#endif
	}
	catch(...){
		std::cout << "RisingGpioEventfunction error" << std::endl;
	}
}

#define CaptureThreadHIK_init(a)\
void __stdcall LossCallBack##a(unsigned int pData, void* pUser){LossCallBackfunction(pData,pUser);}\
void __stdcall FallingGpioEvent##a(MV_EVENT_OUT_INFO* pEventInfo, void* pUser){FallingGpioEventfunction(pEventInfo,pUser);}\
void __stdcall RisingGpioEvent##a(MV_EVENT_OUT_INFO* pEventInfo, void* pUser){RisingGpioEventfunction(pEventInfo,pUser);}
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
CaptureThreadHIK_init(1)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
CaptureThreadHIK_init(2)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
CaptureThreadHIK_init(3)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
CaptureThreadHIK_init(4)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
CaptureThreadHIK_init(5)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
CaptureThreadHIK_init(6)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
CaptureThreadHIK_init(7)
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
CaptureThreadHIK_init(8)
#endif

void(*LossCallBack[NumberOfSupportedCameras])(unsigned int pData, void* pUser) = { 
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
	LossCallBack1
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
	,LossCallBack2
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
	,LossCallBack3
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
	,LossCallBack4
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
	,LossCallBack5
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
	,LossCallBack6
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
	,LossCallBack7
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
	,LossCallBack8
#endif
};
void(*FallingGpioEvent[NumberOfSupportedCameras])(MV_EVENT_OUT_INFO* pEventInfo, void* pUser) = { 
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
	FallingGpioEvent1
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
	,FallingGpioEvent2
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
	,FallingGpioEvent3
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
	,FallingGpioEvent4
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
	,FallingGpioEvent5
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
	,FallingGpioEvent6
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
	,FallingGpioEvent7
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
	,FallingGpioEvent8
#endif
};
void(*RisingGpioEvent[NumberOfSupportedCameras])(MV_EVENT_OUT_INFO* pEventInfo, void* pUser) = { 
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>0)
	RisingGpioEvent1
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>1)
	,RisingGpioEvent2
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>2)
	,RisingGpioEvent3
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>3)
	,RisingGpioEvent4
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>4)
	,RisingGpioEvent5
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>5)
	,RisingGpioEvent6
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>6)
	,RisingGpioEvent7
#endif
#if defined(NumberOfSupportedCameras) && (NumberOfSupportedCameras>7)
	,RisingGpioEvent8
#endif
};
void CaptureThreadHIK::fpsTimeout(void)
{
	uint64_t delta = m_cntGrabbedImages - m_cntLastGrabbedImages;
	m_cntLastGrabbedImages = m_cntGrabbedImages;
	QString data = QString("%1").arg(delta);
	emit updateStatistics(data.left(4), Local_Num);
}

//-----------------------------------------------------------------------------
CaptureThreadHIK::CaptureThreadHIK(void *camhandle, bool boTerminated,int Num) :
	CamHandle( camhandle ), boTerminated_( boTerminated ),Local_Num(Num)
//-----------------------------------------------------------------------------
{
	p_unit_queue = new ASyncQueue<cv::Mat>(Unit_Queue_Size);
	g_pImage_buf = (unsigned char*)malloc(3000 * 3000 * 3);
}
CaptureThreadHIK::~CaptureThreadHIK()
{
	delete p_unit_queue;
	free(g_pImage_buf);
}
//-----------------------------------------------------------------------------
void CaptureThreadHIK::process( void )
//-----------------------------------------------------------------------------
{
	try {
		int nRet = MV_OK, nnRet = MV_OK;
	
		m_threadFunc.CamHandle_ = CamHandle;
		m_threadFunc.p_result_queue_ = p_result_queue;
		m_threadFunc.p_double_queue_ = p_double_queue;

		nRet = MV_CC_RegisterExceptionCallBack(CamHandle, LossCallBack[Local_Num], this);
		if (nRet) { std::cout << "can not register loss callback" << std::endl; nnRet = nRet; }

//#ifdef IMM_FEED_BACK  ///不打开无反馈等( 延后一次两次用ifndef // 不延后用ifdef)
		nRet = MV_CC_SetEnumValueByString(CamHandle, "EventSelector", "Line0FallingEdge");
		if (nRet) { std::cout << "can not set EventSelector" << std::endl; nnRet = nRet; }

		nRet = MV_CC_SetEnumValueByString(CamHandle, "EventNotification", "On");
		if (nRet) { std::cout << "can not set EventNotification" << std::endl; nnRet = nRet; }

		nRet = MV_CC_SetEnumValueByString(CamHandle, "EventSelector", "Line0RisingEdge");
		if (nRet) { std::cout << "can not set EventSelector" << std::endl; nnRet = nRet; }

		nRet = MV_CC_SetEnumValueByString(CamHandle, "EventNotification", "On");
		if (nRet) { std::cout << "can not set EventNotification" << std::endl; nnRet = nRet; }

		nRet = MV_CC_RegisterEventCallBackEx(CamHandle, "Line0FallingEdge", FallingGpioEvent[Local_Num], this);
		if (nRet) { std::cout << "can not register GPIO callback" << std::endl; nnRet = nRet; }

		nRet = MV_CC_RegisterEventCallBackEx(CamHandle, "Line0RisingEdge", RisingGpioEvent[Local_Num], this);
		if (nRet) { std::cout << "can not register GPIO callback" << std::endl; nnRet = nRet; }
//#endif

		m_Timer = new QTimer();
		connect(m_Timer, SIGNAL(timeout()), this, SLOT(fpsTimeout()));
		m_Timer->start(1000);

		unsigned int nDataSize;
		MVCC_INTVALUE_EX stIntValue = { 0 };
		nRet = MV_CC_GetIntValueEx(CamHandle, "PayloadSize", &stIntValue);
		if (nRet) { std::cout << "Get PayloadSize error" << std::endl; }
		nDataSize = stIntValue.nCurValue*3;///
		MV_CC_StartGrabbing(CamHandle);
		Ready = true;
		while(!boTerminated_)
		{
			//nRet = MV_CC_GetOneFrameTimeout(CamHandle, g_pImage_buf, nDataSize, &stFrameInfo, 200);
			nRet = MV_CC_GetImageForBGR(CamHandle, g_pImage_buf, nDataSize, &stFrameInfo, 200);
			if (MV_OK == nRet)
			{
				m_cntGrabbedImages++;

				cv::Mat openCVImage(stFrameInfo.nHeight, stFrameInfo.nWidth, CV_8UC3, g_pImage_buf);
				cv::Mat image_clone = openCVImage.clone();
				if (!g_debug_mode)
				{
#ifdef IMM_PROCESS
					p_image_queue->put(std::make_pair(1,image_clone));
#else
					p_unit_queue->put(image_clone);	//放入临时队列
#endif
				}
				else
				{
					p_debug_queue->put(image_clone);	//放入调试队列
				}
			}
#if defined (IMM_FEED_BACK) || defined (CAP_FEED_BACK)
			m_threadFunc.SendFeedBack(ImageCap);
#endif
			QCoreApplication::processEvents();//Make sure the timer is triggered
		}
		MV_CC_StopGrabbing(CamHandle);
		MV_CC_CloseDevice(CamHandle);
		delete m_Timer;
	}
	catch (cv::Exception& e) {
		const char* err_msg = e.what();
		std::cout << "exception caught: " << err_msg << std::endl;
	}
}
//-----------------------------------------------------------------------------
