/*
 * AXMIspAssistState.cpp
 */

//#include <iostream>
#include "../../project/refkit/AXMIspConfig.hpp"
#include "../AXMCommon/AXMCommonParam.hpp"
#include "../AXMCommon/AXMCommonStruct.hpp"
#include "../AXMCommon/AXMCommonBridgeParam.hpp"
#include "../AXMPixcessor/AXMPixcessor.hpp"
#include "AXMIspAssist.hpp"
#include "AXMIspOb.hpp"
#include "AXMIspCh.hpp"
#include "AXMIspAssistDef.hpp"
#include "../AXMIsp/AXMIsp.hpp"

// 3rdリリースから、「モデルイベント」と「デバイスイベント」の
// 登録が可能となる。
//
// 状態テーブルは、状態ごとに定義し、イベントIDとメンバ関数の紐付けを行う。
// ※状態テーブルの最後は、必ず{0,NULL}で終了する必要がある。

// STATE_RUNNING状態の状態テーブル定義
//      {イベントID, メンバ関数ポインタ}
//      ...
//     {0,NULL}
const AXMIspAssist::StateTable AXMIspAssist::state_running[] = {
    { AXMIspAssist::EVENT_SET_OB_PARAM,                        // OBパラメータ設定処理
      (AXMIspAssist::StateFuncPtr) &AXMIspAssist::matrix0100 },
    { AXMIspAssist::EVENT_PROC_OB_START,                       // OB処理開始
      (AXMIspAssist::StateFuncPtr) &AXMIspAssist::matrix0101 },
    { AXMIspAssist::EVENT_PROC_CALC_DARK_LEVEL,                // 黒レベル計算
      (AXMIspAssist::StateFuncPtr) &AXMIspAssist::matrix0102 },
    { AXMIspAssist::EVENT_PROC_SET_DARK_LEVEL,                 // 黒レベル設定完了
      (AXMIspAssist::StateFuncPtr) &AXMIspAssist::matrix0103 },
    { AXMIspAssist::EVENT_PROC_PARAM_SETTINGS,                 // 低輝度クロマサプレスゲインパラメータ設定処理
      (AXMIspAssist::StateFuncPtr) &AXMIspAssist::matrix0200 },
    { AXMIspAssist::EVENT_PROC_LOW_LUMINANCE_GAIN,             // 低輝度クロマサプレスゲイン設定処理
      (AXMIspAssist::StateFuncPtr) &AXMIspAssist::matrix0201 },
    {0, NULL}
};

USHORT AXMIspAssist::checkOBParam() {

	USHORT updStatus = 0;
	bool isChange = false;

	if ((p_spec->changeStatus[AXH_Index_SPEC_CHK_OB] & SPEC_CHG_OB) == SPEC_CHG_OB) {
		BYTE   mode             = p_spec->OB.mode;
		short  samplingWidth    = p_spec->OB.samplingWidth  - 1;
		short  samplingHeight   = p_spec->OB.samplingHeight - 1;
		USHORT darkLevelFloorR  = p_spec->OB.darkLevelFloorR;
		USHORT darkLevelFloorGr = p_spec->OB.darkLevelFloorGr;
		USHORT darkLevelFloorB  = p_spec->OB.darkLevelFloorB;
		USHORT darkLevelFloorGb = p_spec->OB.darkLevelFloorGb;

		if (m_obSettings.obMode != mode) {
			m_obSettings.obMode = static_cast<OBMode>(mode);
			updStatus |= PTN_OB_UPD_MODE;
		}

		m_obSettings.samplingRange.hStart = 0;

		if (m_obSettings.samplingRange.hEnd != samplingWidth) {
			m_obSettings.samplingRange.SetHorizon(0, samplingWidth);
			isChange = true;
		}

		m_obSettings.samplingRange.vStart = 0;

		if (m_obSettings.samplingRange.vEnd != samplingHeight) {
			m_obSettings.samplingRange.SetVertical(0, samplingHeight);
			isChange = true;
		}

		if (isChange) {
			updStatus |= PTN_OB_UPD_RANGE;
		}

		isChange = false;

		if (m_obSettings.obDarkLevelFloor[0] != darkLevelFloorR) {
			m_obSettings.obDarkLevelFloor[0] = darkLevelFloorR;
			isChange = true;
		}
		if (m_obSettings.obDarkLevelFloor[1] != darkLevelFloorGr) {
			m_obSettings.obDarkLevelFloor[1] = darkLevelFloorGr;
			isChange = true;
		}
		if (m_obSettings.obDarkLevelFloor[2] != darkLevelFloorB) {
			m_obSettings.obDarkLevelFloor[2] = darkLevelFloorB;
			isChange = true;
		}
		if (m_obSettings.obDarkLevelFloor[3] != darkLevelFloorGb) {
			m_obSettings.obDarkLevelFloor[3] = darkLevelFloorGb;
			isChange = true;
		}

		if (isChange) {
			updStatus |= PTN_OB_UPD_FLOOR;
		}

		p_spec->changeStatus[AXH_Index_SPEC_CHK_OB] &= ~SPEC_CHG_OB;
	}

	if ((p_spec->changeStatus[AXH_Index_SPEC_CHK_OB] & SPEC_CHG_OB_FIX) == SPEC_CHG_OB_FIX) {
		OBArrayPattern arrayPtn = (OBArrayPattern)p_spec->OB.sensorArrayPtn;

		if (OBArrayPattern_2_2 <= arrayPtn && arrayPtn <= OBArrayPattern_8_2) {
			if (m_obSettings.arrayPattern != arrayPtn) {
				m_obSettings.arrayPattern = arrayPtn;
				updStatus |= PTN_OB_UPD_ARRAY_PTN;
			}
		}

		isChange = false;
		for (int i = 0; i < OB_PTN_PIXEL_CNT; i++) {
			BYTE arrayPtnIndex = p_spec->OB.arrayPtnIndex[i];
			if (arrayPtnIndex != m_obSettings.arrayPtnIdx[i] && arrayPtnIndex < OB_DRK_VALUE_CNT) {
				m_obSettings.arrayPtnIdx[i] = arrayPtnIndex;
				isChange = true;
			}
		}
		if (isChange) {
			updStatus |= PTN_OB_UPD_ARRAY_PTN_IDX;
		}

		isChange = false;
		for (int i = 0; i < OB_DRK_VALUE_CNT; i++) {
			if (p_spec->OB.indexValue[i] != (UINT)m_obSettings.indexValue[i]) {
				isChange = true;
			}
			m_obSettings.indexValue[i] = (UINT)p_spec->OB.indexValue[i];
		}
		if (isChange) {
			updStatus |= PTN_OB_UPD_ARRAY_IDX_VAL;
		}

		p_spec->changeStatus[AXH_Index_SPEC_CHK_OB] &= ~SPEC_CHG_OB_FIX;
	}

	return updStatus;
}

void AXMIspAssist::setOBSamplingRange() {
#ifndef DISABLE_OB_PROC
	ST_MSG msg;
	msg.data = &m_obSettings.samplingRange;
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.param[0] = 0;
	checkDataCPPTEST.param[1] = 0;
	checkDataCPPTEST.param[2] = 0;
	checkDataCPPTEST.param[3] = 0;
#endif

#ifndef PARASOFT_CPPTEST
	if (0 > send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_OB_AREA_SET), &msg, sizeof(ST_MSG))) {
		;
	}
#else
	checkDataCPPTEST.param[0] = m_obSettings.samplingRange.hStart;
	checkDataCPPTEST.param[1] = m_obSettings.samplingRange.hEnd;
	checkDataCPPTEST.param[2] = m_obSettings.samplingRange.vStart;
	checkDataCPPTEST.param[3] = m_obSettings.samplingRange.vEnd;
#endif  //  PARASOFT_CPPTEST
#endif  //  DISABLE_OB_PROC
}

void AXMIspAssist::setOBArrayPattern() {
#ifndef DISABLE_OB_PROC
	ST_MSG msg;
	msg.data = &m_obSettings.arrayPattern;
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.param[0] = 0;
#endif

#ifndef PARASOFT_CPPTEST
	if (0 > send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_OB_SENSOR_ARRAY_PTN_SET), &msg, sizeof(ST_MSG))) {
		;
	}
#else
	checkDataCPPTEST.param[0] = *((unsigned char*)msg.data);
#endif  //  PARASOFT_CPPTEST
#endif  //  DISABLE_OB_PROC
}

void AXMIspAssist::setOBArrayPatternIndex() {
#ifndef DISABLE_OB_PROC
	ST_MSG msg;
	msg.data = &m_obSettings.arrayPtnIdx[0];
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.param[0] = 0;
	checkDataCPPTEST.param[1] = 0;
	checkDataCPPTEST.param[2] = 0;
#endif

#ifndef PARASOFT_CPPTEST
	if (0 > send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_OB_ARRAY_PTN_INDEX_SET), &msg, sizeof(ST_MSG))) {
		;
	}
#else
	unsigned char* testcheckData = (unsigned char*)msg.data;
	checkDataCPPTEST.param[0] = testcheckData[0];
	checkDataCPPTEST.param[1] = testcheckData[1];
	checkDataCPPTEST.param[2] = testcheckData[15];
#endif  //  PARASOFT_CPPTEST
#endif  //  DISABLE_OB_PROC
}

void AXMIspAssist::setOBIndexValue() {
#ifndef DISABLE_OB_PROC
	ST_MSG msg;
	msg.data = &m_obSettings.indexValue[0];
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.param[0] = 0;
	checkDataCPPTEST.param[1] = 0;
	checkDataCPPTEST.param[2] = 0;
	checkDataCPPTEST.param[3] = 0;
	checkDataCPPTEST.param[4] = 0;
	checkDataCPPTEST.param[5] = 0;
	checkDataCPPTEST.param[6] = 0;
	checkDataCPPTEST.param[7] = 0;
#endif

#ifndef PARASOFT_CPPTEST
	if (0 > send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_OB_FIX_DARKLEVEL_SET), &msg, sizeof(ST_MSG))) {
		;
	}
#else
	unsigned int* testcheckData = (unsigned int*)msg.data;
	checkDataCPPTEST.param[0] = testcheckData[0];
	checkDataCPPTEST.param[1] = testcheckData[1];
	checkDataCPPTEST.param[2] = testcheckData[2];
	checkDataCPPTEST.param[3] = testcheckData[3];
	checkDataCPPTEST.param[4] = testcheckData[4];
	checkDataCPPTEST.param[5] = testcheckData[5];
	checkDataCPPTEST.param[6] = testcheckData[6];
	checkDataCPPTEST.param[7] = testcheckData[7];
#endif  //  PARASOFT_CPPTEST
#endif  //  DISABLE_OB_PROC
}

ax::actorFuncStatus AXMIspAssist::matrix0100(const void *pParam, int size) {
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.data[0] = 0;
	checkDataCPPTEST.data[1] = 0;
	checkDataCPPTEST.data[2] = 0;
	checkDataCPPTEST.data[3] = 0;
	checkDataCPPTEST.data[4] = 0;
	checkDataCPPTEST.data[5] = 0;
	checkDataCPPTEST.data[6] = 0;
#endif
	USHORT updStatus = checkOBParam();
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.data[0] = updStatus;
#endif
#ifdef PARASOFT_CPPTEST
	if ((updStatus & PTN_OB_UPD_MODE) == PTN_OB_UPD_MODE) {
		checkDataCPPTEST.data[1] = 1;
	}
#endif

	if ((updStatus & PTN_OB_UPD_RANGE) == PTN_OB_UPD_RANGE) {
#ifdef PARASOFT_CPPTEST
		checkDataCPPTEST.data[2] = 1;
#endif
		setOBSamplingRange();
	}

#ifdef PARASOFT_CPPTEST
	if ((updStatus & PTN_OB_UPD_FLOOR) == PTN_OB_UPD_FLOOR) {
		checkDataCPPTEST.data[3] = 1;
	}
#endif

	if ((updStatus & PTN_OB_UPD_ARRAY_PTN) == PTN_OB_UPD_ARRAY_PTN) {
#ifdef PARASOFT_CPPTEST
		checkDataCPPTEST.data[4] = 1;
#endif
		setOBArrayPattern();
	}
	if ((updStatus & PTN_OB_UPD_ARRAY_PTN_IDX) == PTN_OB_UPD_ARRAY_PTN_IDX) {
#ifdef PARASOFT_CPPTEST
		checkDataCPPTEST.data[5] = 1;
#endif
		setOBArrayPatternIndex();
	}
#ifdef PARASOFT_CPPTEST
	if ((updStatus & PTN_OB_UPD_ARRAY_IDX_VAL) == PTN_OB_UPD_ARRAY_IDX_VAL) {
		checkDataCPPTEST.data[6] = 1;
	}
#endif

	state = STATE_RUNNING;
#ifndef PARASOFT_CPPTEST
	setNextState(state);
#endif  //  PARASOFT_CPPTEST
	return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMIspAssist::matrix0101(const void *pParam, int size) {
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.data[0] = 0;
	checkDataCPPTEST.data[1] = 0;
#endif

	// 必要な処理をここに記述
	if (0 < size) {
		if (m_obSettings.obMode == OBFeedback) {
			// フィードバックモード
			ST_MSG msg;
#ifdef DISABLE_OB_PROC
			msg.data = NULL;
#else
			msg.data = &m_obSettings.obAccumlator[0];
#endif //  DISABLE_OB_PROC

// CPPTESTでは除外
#ifndef PARASOFT_CPPTEST
			if (0 > send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_OB_ACCUM_GET), &msg, sizeof(ST_MSG))) {
				;
			}
#endif // PARASOFT_CPPTEST
#ifdef PARASOFT_CPPTEST
			checkDataCPPTEST.data[0] = 1;
#endif
		}
		else {
			// 固定値モード(固定値送信)
			setOBIndexValue();
#ifdef PARASOFT_CPPTEST
			checkDataCPPTEST.data[1] = 1;
#endif
		}
	}
	return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMIspAssist::matrix0102(const void *pParam, int size) {
	// 必要な処理をここに記述
	if(0 < size)
	{
		ST_MSG msg;
#ifdef DISABLE_OB_PROC
		msg.data = NULL;
#else
//		char str[200];
//		snprintf(str, sizeof(str), "OB matrix0102() : Feedback mode : OB 黒レベル計算積算値 %d, %d, %d, %d", m_obSettings.obAccumlator[0], m_obSettings.obAccumlator[1], m_obSettings.obAccumlator[2], m_obSettings.obAccumlator[3]);
		
		// 黒レベル計算
		m_obCalc.Exec();

		msg.data = &m_obSettings.obDarkLevel[0];
#endif //  DISABLE_OB_PROC
#ifndef PARASOFT_CPPTEST // CPPTESTでは除外
		if (0 > send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_OB_DARKLEVEL_SET), &msg, sizeof(ST_MSG))) {
			;
		}
#endif //  PARASOFT_CPPTEST
	}
	return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMIspAssist::matrix0103(const void *pParam, int size) {
		// OB処理なしのため不要
//#ifndef PARASOFT_CPPTEST  //  CPPTESTでは除外
//	if (0 > send(nameIsp, AXFEVENT_MODEL(AXMIsp::EVENT_OB_END), 0, 0)) {
//		;
//	}
//#endif //  PARASOFT_CPPTEST
	return ax::AXFACTOR_SUCCESS;
}

ax::actorFuncStatus AXMIspAssist::matrix0200(const void *pParam, int size) {
#ifdef PARASOFT_CPPTEST
	BYTE paramChange = 0;
#endif

	bool isChange = checkLowChromaParam();

	if (isChange) {
		chLowLuminanceGainSet(m_preSensorGain);
#ifdef PARASOFT_CPPTEST
		paramChange = 1;
#endif
	}
#ifdef PARASOFT_CPPTEST
	checkDataCPPTEST.data[1] = paramChange;
#endif

	return ax::AXFACTOR_SUCCESS;
}

bool AXMIspAssist::checkLowChromaParam() {
	bool isChange = false;
	BYTE lowStartGain = p_spec->CHROMA.lowStartGain;
	BYTE lowInc       = p_spec->CHROMA.lowInc;
	// 低輝度クロマサプレス設定
	if (lowStartGain != m_chSettings.lowStartGain) {
		m_chSettings.lowStartGain = lowStartGain;
		isChange = true;
	}
	if (lowInc != m_chSettings.lowInc) {
		m_chSettings.lowInc = lowInc;
		isChange = true;
	}

	p_spec->changeStatus[AXH_Index_SPEC_CHK_CHROMA] &= ~SPEC_CHG_LOW_CHRO;

	return isChange;
}

ax::actorFuncStatus AXMIspAssist::matrix0201(const void *pParam, int size) {
	ST_MSG *p_msg = (ST_MSG *)pParam;

	// AEからのセンサーゲインデータを取得
	BYTE sensorGain = 0;
	if (0 < size) {
		sensorGain = *((BYTE*)p_msg->data);
	}

	chLowLuminanceGainSet(sensorGain);

	m_preSensorGain = sensorGain;

	return ax::AXFACTOR_SUCCESS;
}

void AXMIspAssist::chDefaultLowLuminanceGainSet() {
	BYTE datasize = 0;
	BYTE data = 0;

#ifndef DISABLE_CHROMA_PROC
	// 最大ゲインを設定
	data = CH_MAX_OUTPUT_GAIN;
	datasize = sizeof(data);
#endif  // DISABLE_CHROMA_PROC

#ifndef PARASOFT_CPPTEST
	if (send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_CHROMA_LOW_LUMINANCE_GAIN_SET), &data, datasize) < 0) {
		;
	}
#else
	checkDataCPPTEST.size = datasize;
	checkDataCPPTEST.data[0] = data;
#endif
}

void AXMIspAssist::chLowLuminanceGainSet(BYTE sensorGain) {
	BYTE datasize = 0;
	BYTE data = 0;

#ifndef DISABLE_CHROMA_PROC
	m_chCalc.CalcLowLuminanceChromaSuppress(
		  sensorGain
		, m_chSettings.lowStartGain
		, m_chSettings.lowInc
		, &data
	);
	datasize = sizeof(data);
#endif  // DISABLE_CHROMA_PROC

#ifndef PARASOFT_CPPTEST
	if (send(namePixessor, AXFEVENT_MODEL(AXMPixcessor::ISP_EVENT_CHROMA_LOW_LUMINANCE_GAIN_SET), &data, datasize) < 0) {
		;
	}
#else
	checkDataCPPTEST.param[0] = m_chSettings.lowStartGain;
	checkDataCPPTEST.param[1] = m_chSettings.lowInc;
	checkDataCPPTEST.param[2] = sensorGain;
	checkDataCPPTEST.size = datasize;
	checkDataCPPTEST.data[0] = data;
#endif
}
