/**********************************************************************
 * INCLUDES
 */
#include "ikk-opt-tunnel.h"
#include "ikk-debug.h"
#include "../../../../zigbee/zcl/zcl_include.h"

// FCC0-0000
#pragma pack(1)
typedef struct tag_private_clsFCC0_attr0000_frame_st {
	unsigned char length;	// frame length - not include itself!!!
	unsigned int  device_id;// device id
	unsigned char channel;	// channel
	unsigned char opcode;	// pocode
	unsigned char arg[OPTTUNNEL_OPTDATA_MAXLEN - 7]; // opcode arg
}
__attribute__((packed)) OptTunnelOptDataFrameSt;



uint8_t g_tmp_buffer[OPTTUNNEL_CHUNK_MAXLEN+1] = { 0 }, g_tmp_length = 0;

// private protocol optdata message incoming process callback
pFUNC_OPTDATA_MESSAGE_CALLBACK g_pOptDataIncomingMessageCallback = NULL;


extern _CODE_ZCL_ zclReadCmd_t *zcl_parseInReadCmd(zclIncoming_t *pCmd);
extern _CODE_ZCL_ status_t zcl_readRsp(u8 srcEp, epInfo_t *pDstEpInfo, u16 clusterId, u16 manuCode, u8 disableDefaultRsp, u8 direction, u8 seqNo, zclReadRspCmd_t *readRspCmd);
//_CODE_ZCL_ static status_t zcl_Private_cmdHandler(zclIncoming_t *pInMsg);
//
//
//
//
//_CODE_ZCL_ status_t zcl_private_fcc0_register(u8 endpoint, u16 manuCode, u8 attrNum, const zclAttrInfo_t attrTbl[], cluster_forAppCb_t cb)
//{
//    return zcl_registerCluster(endpoint, ZCL_CLUSTER_PRIVATE_FCC0, manuCode, attrNum, attrTbl, zcl_Private_cmdHandler, cb);
//}
//
//_CODE_ZCL_ static status_t zcl_private_clientCmdHandler(zclIncoming_t *pInMsg)
//{
//	u8 status = ZCL_STA_SUCCESS;
//	apsdeDataInd_t *pApsdeInd = (apsdeDataInd_t*)pInMsg->msg;
//	iKonkeAfSelfPrint("#############zcl_private_clientCmdHandler ,command id =%x!!!!!!!\r\n",pInMsg->hdr.cmd);
////	switch(pInMsg->hdr.cmd)
////	{
////		case ZCL_CMD_BASIC_RESET_FAC_DEFAULT:
////			if(pInMsg->clusterAppCb){
////				zclIncomingAddrInfo_t addrInfo;
////				addrInfo.dirCluster = pInMsg->hdr.frmCtrl.bf.dir;
////				addrInfo.profileId = pApsdeInd->indInfo.profile_id;
////				addrInfo.srcAddr = pApsdeInd->indInfo.src_short_addr;
////				addrInfo.dstAddr = pApsdeInd->indInfo.dst_addr;
////				addrInfo.srcEp = pApsdeInd->indInfo.src_ep;
////				addrInfo.dstEp = pApsdeInd->indInfo.dst_ep;
////
////				status = pInMsg->clusterAppCb(&addrInfo, ZCL_CMD_BASIC_RESET_FAC_DEFAULT, NULL);
////			}else{
////				status = ZCL_STA_FAILURE;
////			}
////			break;
////		default:
////			status = ZCL_STA_UNSUP_CLUSTER_COMMAND;
////			break;
////	}
//
//	return status;
//}
//
//_CODE_ZCL_ static status_t zcl_Private_cmdHandler(zclIncoming_t *pInMsg)
//{
//	if(pInMsg->hdr.frmCtrl.bf.dir == ZCL_FRAME_CLIENT_SERVER_DIR){
//		return zcl_private_clientCmdHandler(pInMsg);
//	}else{
//		return ZCL_STA_UNSUP_CLUSTER_COMMAND;
//	}
//}
//
///*********************************************************************
// * @fn      private_fcc0Cb
// *
// * @brief   Handler for ZCL FCC0 command. This function will set attribute first.
// *
// * @param	pAddrInfo
// * @param   cmdId - onoff cluster command id
// * @param	cmdPayload
// *
// * @return  status_t
// */
//status_t private_fcc0Cb(zclIncomingAddrInfo_t *pAddrInfo, u8 cmdId, void *cmdPayload)
//{
//	zcl_privateAttr_t *pFcc0_data = zcl_privateAttrGet();
//	iKonkeAfSelfPrint("#############private_fcc0Cb ,command id =%x!!!!!!!\r\n",cmdId);
//	if(pAddrInfo->dstEp == SAMPLE_LIGHT_ENDPOINT){
//		switch(cmdId){
//			case ZCL_CMD_ONOFF_ON:
//			case ZCL_CMD_ONOFF_OFF:
//			case ZCL_CMD_ONOFF_TOGGLE:
//				//sampleLight_onoff(cmdId);
//				break;
//			default:
//				break;
//		}
//	}
//
//	return ZCL_STA_SUCCESS;
//}

status_t kOptTunnelMessageReadResponse(zclIncoming_t *pInHdlrMsg,uint8_t *pData)
{
	u8 status = ZCL_STA_SUCCESS;
	u16 clusterId = pInHdlrMsg->msg->indInfo.cluster_id;
	u8 endpoint = pInHdlrMsg->msg->indInfo.dst_ep;


	/* Parse In Read Command */
	zclReadCmd_t *pReadCmd = zcl_parseInReadCmd(pInHdlrMsg);
	if(pReadCmd == NULL){
		return ZCL_STA_INSUFFICIENT_SPACE;
	}else{
		pInHdlrMsg->attrCmd = (void *)pReadCmd;
	}

	if(!pInHdlrMsg->msg->indInfo.security_status){
		return ZCL_STA_FAILURE;
	}

	/* Build Read Response Command */
	u16 len = sizeof(zclReadRspCmd_t) + (pReadCmd->numAttr * sizeof(zclReadRspStatus_t));
	zclReadRspCmd_t *pReadRspCmd = (zclReadRspCmd_t *)ev_buf_allocate(len);
	if(!pReadRspCmd){
		return ZCL_STA_INSUFFICIENT_SPACE;
	}
	pReadRspCmd->numAttr = pReadCmd->numAttr;


	pReadRspCmd->attrList[0].dataType = ZCL_DATA_TYPE_CHAR_STR;
	pReadRspCmd->attrList[0].data = pData;
	pReadRspCmd->attrList[0].attrID = pReadCmd->attrID[0];
	pReadRspCmd->attrList[0].status = ZCL_STA_SUCCESS;

	epInfo_t dstEp;
	TL_SETSTRUCTCONTENT(dstEp, 0);

	dstEp.dstEp = pInHdlrMsg->msg->indInfo.src_ep;
	dstEp.profileId = pInHdlrMsg->msg->indInfo.profile_id;
	dstEp.dstAddrMode = APS_SHORT_DSTADDR_WITHEP;
	dstEp.dstAddr.shortAddr = pInHdlrMsg->msg->indInfo.src_short_addr;
	dstEp.txOptions |= APS_TX_OPT_ACK_TX;
	if(pInHdlrMsg->msg->indInfo.security_status & SECURITY_IN_APSLAYER){
		dstEp.txOptions |= APS_TX_OPT_SECURITY_ENABLED;
	}

	status = zcl_readRsp(endpoint, &dstEp, clusterId, pInHdlrMsg->hdr.manufCode, false, !pInHdlrMsg->hdr.frmCtrl.bf.dir, pInHdlrMsg->hdr.seqNum, pReadRspCmd);
	return status;
}
status_t kOptTunnelMessageWriteResponse(zclIncoming_t *pCmd,uint8_t *pData)
{
	u8 status = ZCL_STA_SUCCESS;
	u16 clusterId = pCmd->msg->indInfo.cluster_id;
	u8 endpoint = pCmd->msg->indInfo.dst_ep;
	uint8_t tmp_buffer[64] ={0};
	uint8_t i =0;
	uint8_t payload_len = pData[0];


	// 8 0 51 86 10 0 0 0 0
	if(pCmd->hdr.cmd == ZCL_CMD_WRITE){
		tmp_buffer[i++] = 0x00;
		tmp_buffer[i++] = ZCL_STA_SUCCESS;				//0
		tmp_buffer[i++] = 00;							//1
		tmp_buffer[i++] = 00;							//2
		tmp_buffer[i++] = ZCL_DATA_TYPE_CHAR_STR;		//3 type
		tmp_buffer[i++] = payload_len+1;				//4 len
		tmp_buffer[i++] = payload_len;					//5 len
		if(payload_len +7 < 64)
		{
			memcpy(&tmp_buffer[i],&pData[1],payload_len);
		}
		tmp_buffer[0] = payload_len + 6;
		epInfo_t dstEp;
		TL_SETSTRUCTCONTENT(dstEp, 0);

		dstEp.dstEp = pCmd->msg->indInfo.src_ep;
		dstEp.profileId = pCmd->msg->indInfo.profile_id;
		dstEp.dstAddrMode = APS_SHORT_DSTADDR_WITHEP;
		dstEp.dstAddr.shortAddr = pCmd->msg->indInfo.src_short_addr;
		dstEp.txOptions |= APS_TX_OPT_ACK_TX;
		if(pCmd->msg->indInfo.security_status & SECURITY_IN_APSLAYER){
			dstEp.txOptions |= APS_TX_OPT_SECURITY_ENABLED;
		}
		status = zcl_sendCmd(endpoint, &dstEp, clusterId, ZCL_CMD_WRITE_RSP, FALSE, !pCmd->hdr.frmCtrl.bf.dir, false, pCmd->hdr.manufCode, pCmd->hdr.seqNum, tmp_buffer[0], &tmp_buffer[1]);
	}
	return status;
}
/*	DESP: private protocol command process.
 * 	Auth: dingmz_frc.20190704.
 * */
status_t kOptTunnelMessageIncoming(OptMethodEm method,zclIncoming_t *pCmd)
{
	u8 status = ZCL_STA_SUCCESS;
	// 0 0 42 7 6 0 51 86 10 0 0      oring data  zcl global write 0xfcc0 0x0000 0x42 {06 00 51 86 10 00 00}
	//out 6 0 51 86 10 0 0 0
	iKonkeAfSelfPrint("\r\n-------------------------\r\n");

	// device id
	uint8_t tmp_buffer[6];
	tmp_buffer[0] = 5;
	tmp_buffer[1] = 0X00;
	tmp_buffer[2] = 0X06;
	tmp_buffer[3] = 0X86;
	tmp_buffer[4] = 0x01;
	switch(method) {
		case (EOM_WRITE):
		{
			uint8_t length = (uint8_t)pCmd->dataLen - 4;
			if( pCmd->pData ) {
				memcpy(g_tmp_buffer, pCmd->pData+4, length);
				g_tmp_length = length;
			}
			iKonkeAfSelfPrint("#######kOptTunnelMessageIncoming length(0x%d)\r\n", length);
			iKonkeAfSelfPrintBuffer(g_tmp_buffer,length);

			//copy device id
			memcpy(&g_tmp_buffer[1],&tmp_buffer[1],4);
//			switch(attribute_id)
//			{
//				case (ECA_OPTDATA):
//				{
					if( length >= 7 ) {
						iKonkeAfSelfPrint("\r\n########################OPTDATA WRITE,g_tmp_length = %d\r\n",g_tmp_length);
						if( g_pOptDataIncomingMessageCallback ) {
							g_tmp_length  = g_tmp_length - 6;
							if(KET_NO_RESPONSE == g_pOptDataIncomingMessageCallback(g_tmp_buffer[5], g_tmp_buffer[6], g_tmp_buffer + 7, &g_tmp_length)){
								return KET_NO_RESPONSE;
							}
							g_tmp_length += 7;
							g_tmp_buffer[0] = g_tmp_length - 1;
							iKonkeAfSelfPrint("#######kOptTunnelMessageIncoming11111 length(0x%2x)\r\n", g_tmp_buffer[0]);
							iKonkeAfSelfPrintBuffer(g_tmp_buffer,g_tmp_buffer[0]+1);
							kOptTunnelMessageWriteResponse(pCmd, g_tmp_buffer);
						}
					}else {
						return KET_ERR_INVALID_PARAM;
					}
//
//					break;
//				}
//			}
			break;
		}
		case (EOM_READ ):
		{
//			switch(attribute_id){
//				// OptData read command is same to write opcode 0x00, read the device snap.
//				case (ECA_OPTDATA):
//				{
					iKonkeAfSelfPrint("\r\n########################OPTDATA READ\r\n");
					if( g_pOptDataIncomingMessageCallback ) {
						memcpy(&g_tmp_buffer[2],&tmp_buffer[1],4);
						g_tmp_buffer[6] = 0x00;
						g_tmp_buffer[7] = 0x00;
						g_tmp_buffer[8] = 0x00;
						g_tmp_buffer[9] = 0x00;
						g_tmp_length = 0;
						g_pOptDataIncomingMessageCallback(0, 0, g_tmp_buffer + 8, &g_tmp_length);
						g_tmp_length += 7;
						g_tmp_buffer[0] = g_tmp_length;				//length
						g_tmp_buffer[1] = g_tmp_length - 1;			//string length
						kOptTunnelMessageReadResponse(pCmd, g_tmp_buffer);
					}
//					break;
//				}
//			}
			break;
		}
		default: break;
	}

	return status;
}

/*	DESP: Private protocol message(command) reporting interface
 * 	Auth: dingmz_frc.20191113.
 * */
extern status_t General_Report(uint8_t src_ep,uint8_t des_ep,uint16_t cluster,uint16_t Attribute,uint8_t Data_Type,uint8_t *value);
static status_t kOptTunnelOODReport(uint16_t attribute_id,uint8_t channel, uint8_t opcode, uint8_t *arg, uint8_t length )
{
	uint8_t temp_buffer[64] = {0};
	if(length < 64)
		memmove(temp_buffer+1, arg, length);
	temp_buffer[0] = length;
	memmove(g_tmp_buffer,temp_buffer,length+1);

	return General_Report(channel,1,PRIV_CLUSTER_FCC0,attribute_id,ZCL_DATA_TYPE_CHAR_STR,g_tmp_buffer);
}
/*	DESP: Private protocol common report interface.
 * 	Auth: dingmz_frc.20191113.
 * */
kk_err_t kOptTunnelCommonReport(uint16_t attribute_id )
{
	if( attribute_id == OPTTUNNEL_UNKNOW ) {
		return KET_ERR_NON_EXIST;
	}

	kk_err_t err = KET_OK;

	switch(attribute_id) {
		case (ECA_OPTDATA):
		{
			iKonkeAfSelfPrint("#######kOptTunnelCommonReport OPTDATA\r\n");
			g_tmp_buffer[1] = 0x00;
			g_tmp_buffer[2] = 0x06;
			g_tmp_buffer[3] = 0x86;
			g_tmp_buffer[4] = 0x01;
			g_tmp_buffer[5] = 0x00;//channel
			g_tmp_buffer[6] = 0x00;//opcode
			if( g_pOptDataIncomingMessageCallback ) {
				g_tmp_length = 0;
				g_tmp_buffer[7] = 0x00;//add by maozj 20200511
				g_pOptDataIncomingMessageCallback(0, 0, g_tmp_buffer + 7, &g_tmp_length);
				g_tmp_length += 7;
				g_tmp_buffer[0] = g_tmp_length - 1;
			}else {
				err = KET_ERR_INVALID_POINTER;
			}
			break;
		}
		default:
		{
			err = KET_ERR_OPRATE_ILLEGAL;
			break;
		}
	}
	if( err == KET_OK  && g_tmp_length > 1) {
		if(kOptTunnelOODReport(attribute_id,g_tmp_buffer[5],g_tmp_buffer[6],g_tmp_buffer,g_tmp_buffer[0]+1)== ZCL_STA_SUCCESS)
			err = KET_OK;
		else
			err = KET_FAILED;
	}

	return err;
}


kk_err_t kOptTunnelModuleInit(pFUNC_OPTDATA_MESSAGE_CALLBACK pOptdataIncomingCallback )
{
	g_pOptDataIncomingMessageCallback = pOptdataIncomingCallback;

	return KET_OK;
}
