/********************************************************************************************************
 * @file	zcl_onOffCb.c
 *
 * @brief	This is the source file for zcl_onOffCb
 *
 * @author	Zigbee Group
 * @date	2019
 *
 * @par     Copyright (c) 2019, Telink Semiconductor (Shanghai) Co., Ltd. ("TELINK")
 *          All rights reserved.
 *
 *          Redistribution and use in source and binary forms, with or without
 *          modification, are permitted provided that the following conditions are met:
 *
 *              1. Redistributions of source code must retain the above copyright
 *              notice, this list of conditions and the following disclaimer.
 *
 *              2. Unless for usage inside a TELINK integrated circuit, redistributions
 *              in binary form must reproduce the above copyright notice, this list of
 *              conditions and the following disclaimer in the documentation and/or other
 *              materials provided with the distribution.
 *
 *              3. Neither the name of TELINK, nor the names of its contributors may be
 *              used to endorse or promote products derived from this software without
 *              specific prior written permission.
 *
 *              4. This software, with or without modification, must only be used with a
 *              TELINK integrated circuit. All other usages are subject to written permission
 *              from TELINK and different commercial license may apply.
 *
 *              5. Licensee shall be solely responsible for any claim to the extent arising out of or
 *              relating to such deletion(s), modification(s) or alteration(s).
 *
 *          THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 *          ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 *          WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *          DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
 *          DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 *          (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *          LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 *          ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 *          (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *          SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *******************************************************************************************************/
#if (__PROJECT_3LIGHT_PANEL_DEMO__)

/**********************************************************************
 * INCLUDES
 */
#include "tl_common.h"
#include "zb_api.h"
#include "zcl_include.h"
#include PROJECT_H
#include "zcl.h"
#include "ikk-debug.h"
#include "ikk-sequence.h"
#include "ikk-cluster.h"
/**********************************************************************
 * LOCAL CONSTANTS
 */
#define ZCL_ONOFF_TIMER_INTERVAL		100    //the timer interval to change the offWaitTime/onTime attribute of the ONOFF cluster

/**********************************************************************
 * LOCAL VARIABLES
 */
static ev_timer_event_t *onWithTimedOffTimerEvt = NULL;

/**********************************************************************
 * FUNCTIONS
 */

/*********************************************************************
 * @fn      sampleLight_onOffInit
 *
 * @brief
 *
 * @param   None
 *
 * @return  None
 */
void sampleLight_onOffInit(void)
{
//	zcl_onOffAttr_t *pOnOff = zcl_onoffAttrGet();
//
//	sampleLight_onoff(pOnOff->onOff);
}
/*********************************************************************
 * @fn      sampleLight_updateOnOff
 *
 * @brief
 *
 * @param   None
 *
 * @return  None
 */
void sampleLight_updateOnOff(void)
{
//	zcl_onOffAttr_t *pOnOff = zcl_onoffAttrGet();
//
//	hwLight_onOffUpdate(pOnOff->onOff);
}

/*********************************************************************
 * @fn      sampleLight_onoff
 *
 * @brief
 *
 * @param   ZCL_CMD_ONOFF_ON / ZCL_ONOFF_STATUS_OFF
 *
 * @return  None
 */
void sampleLight_onoff(u8 cmd)
{
//	zcl_onOffAttr_t *pOnOff = zcl_onoffAttrGet();
//
//	if(cmd == ZCL_CMD_ONOFF_ON){
//		pOnOff->globalSceneControl = TRUE;
//
//		pOnOff->onOff = ZCL_ONOFF_STATUS_ON;
//		if(pOnOff->onTime == 0){
//			pOnOff->offWaitTime = 0;
//		}
//	}else if(cmd == ZCL_CMD_ONOFF_OFF){
//		pOnOff->onOff = ZCL_ONOFF_STATUS_OFF;
//		pOnOff->onTime = 0;
//	}else{
//		if(pOnOff->onOff == ZCL_ONOFF_STATUS_OFF){
//			pOnOff->globalSceneControl = TRUE;
//
//			pOnOff->onOff = ZCL_ONOFF_STATUS_ON;
//			if(pOnOff->onTime == 0){
//				pOnOff->offWaitTime = 0;
//			}
//		}else{
//			pOnOff->onOff = ZCL_ONOFF_STATUS_OFF;
//			pOnOff->onTime = 0;
//		}
//	}

	//light_fresh();

#ifdef ZCL_SCENE
//	zcl_sceneAttr_t *pScene = zcl_sceneAttrGet();
//	pScene->sceneValid = 0;
#endif
}

/*********************************************************************
 * @fn      sampleLight_OnWithTimedOffTimerCb
 *
 * @brief   timer event to process the ON_WITH_TIMED_OFF command
 *
 * @param   arg
 *
 * @return  0: timer continue on; -1: timer will be canceled
 */
static s32 sampleLight_OnWithTimedOffTimerCb(void *arg)
{
//	zcl_onOffAttr_t *pOnOff = zcl_onoffAttrGet();
//
//	if((pOnOff->onOff == ZCL_ONOFF_STATUS_ON) && pOnOff->onTime){
//		pOnOff->onTime--;
//		if(pOnOff->onTime <= 0){
//			pOnOff->offWaitTime = 0;
//			sampleLight_onoff(ZCL_CMD_ONOFF_OFF);
//		}
//	}
//
//	if((pOnOff->onOff == ZCL_ONOFF_STATUS_OFF) && pOnOff->offWaitTime){
//		pOnOff->offWaitTime--;
//		if(pOnOff->offWaitTime <= 0){
//			onWithTimedOffTimerEvt = NULL;
//			return -1;
//		}
//	}
//
//	if(pOnOff->onTime || pOnOff->offWaitTime){
//		return 0;
//	}else{
//		onWithTimedOffTimerEvt = NULL;
//		return -1;
//	}
}

/*********************************************************************
 * @fn      sampleLight_OnWithTimedOffTimerStop
 *
 * @brief   force to stop the OnWithTimedOff timer
 *
 * @param
 *
 * @return
 */
static void sampleLight_OnWithTimedOffTimerStop(void)
{
	if(onWithTimedOffTimerEvt){
		TL_ZB_TIMER_CANCEL(&onWithTimedOffTimerEvt);
	}
}

/*********************************************************************
 * @fn      sampleLight_onoff_onWithTimedOffProcess
 *
 * @brief
 *
 * @param   cmd
 *
 * @return  None
 */
static void sampleLight_onoff_onWithTimedOffProcess(uint8_t ep,zcl_onoff_onWithTimeOffCmd_t *cmd)
{
	zcl_onOffAttr_t *pOnOff = zcl_onoffAttrGet(ep);

	if(cmd->onOffCtrl.bits.acceptOnlyWhenOn && (pOnOff->onOff == ZCL_ONOFF_STATUS_OFF)){
		return;
	}

	if(pOnOff->offWaitTime && (pOnOff->onOff == ZCL_ONOFF_STATUS_OFF)){
		pOnOff->offWaitTime = min2(pOnOff->offWaitTime, cmd->offWaitTime);
	}else{
		pOnOff->onTime = max2(pOnOff->onTime, cmd->onTime);
		pOnOff->offWaitTime = cmd->offWaitTime;
		sampleLight_onoff(ZCL_CMD_ONOFF_ON);
	}

	if((pOnOff->onTime < 0xFFFF) && (pOnOff->offWaitTime < 0xFFFF)){
		if(pOnOff->onTime || pOnOff->offWaitTime){
			sampleLight_OnWithTimedOffTimerStop();
			onWithTimedOffTimerEvt = TL_ZB_TIMER_SCHEDULE(sampleLight_OnWithTimedOffTimerCb, NULL, ZCL_ONOFF_TIMER_INTERVAL);
		}
	}
}

/*********************************************************************
 * @fn      sampleLight_onoff_offWithEffectProcess
 *
 * @brief
 *
 * @param   cmd
 *
 * @return  None
 */
static void sampleLight_onoff_offWithEffectProcess(uint8_t ep,zcl_onoff_offWithEffectCmd_t *cmd)
{
	//TODO: FIXED ME

	sampleLight_onoff(ZCL_CMD_ONOFF_OFF);
}

/*********************************************************************
 * @fn      sampleLight_onoff_onWithRecallGlobalSceneProcess
 *
 * @brief
 *
 * @param   cmd
 *
 * @return  None
 */
static void sampleLight_onoff_onWithRecallGlobalSceneProcess(void)
{

}

typedef struct{
	u16 clusterId[5];
	u16 attrID[5];
}ClusterAttrID;
ClusterAttrID clusterattrid;

static ev_timer_event_t *kSrcEp1Multieport = NULL;
static ev_timer_event_t *kSrcEp2Multieport = NULL;
static ev_timer_event_t *kSrcEp3Multieport = NULL;
static ev_timer_event_t *kSrcEp4Multieport = NULL;
static s32 kSrcEp1MultieportEventHandler(void *arg)
{
	Tl_printf("######kSrcEp1MultieportEventHandler\r\n");
	kZclClusterSetPermitReportInfo(1,ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true,NULL,RESET_ENDPOINT);
	kOptTunnelReportingStatus(1, clusterattrid.clusterId[1], clusterattrid.attrID[1]);
	return -1;
}
static s32 kSrcEp2MultieportEventHandler(void *arg)
{
	Tl_printf("######kSrcEp2MultieportEventHandler\r\n");
	kZclClusterSetPermitReportInfo(2,ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true,NULL,RESET_ENDPOINT);
	kOptTunnelReportingStatus(2, clusterattrid.clusterId[2], clusterattrid.attrID[2]);
	return -1;
}
static s32 kSrcEp3MultieportEventHandler(void *arg)
{
	Tl_printf("######kSrcEp3MultieportEventHandler\r\n");
	kZclClusterSetPermitReportInfo(3,ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true,NULL,RESET_ENDPOINT);
	kOptTunnelReportingStatus(3, clusterattrid.clusterId[3], clusterattrid.attrID[3]);
	return -1;
}

static s32 kSrcEp4MultieportEventHandler(void *arg)
{
	Tl_printf("######kSrcEp4MultieportEventHandler\r\n");
	kZclClusterSetPermitReportInfo(4,ZCL_CLUSTER_GEN_ON_OFF, true, false, true, true,NULL,RESET_ENDPOINT);
	kOptTunnelReportingStatus(4, clusterattrid.clusterId[4], clusterattrid.attrID[4]);
	return -1;
}

extern void ON_OFF_Cmd_Handler(uint8_t endpoint,bool onoff);
void zclReportCmdHandler(uint8_t ep,uint16_t cluster,zclReportCmd_t *reportInfo,zclIncoming_t *pInHdlrMsg)
{
	iKonkeAfSelfPrint("######sampleLight_zclReportCmd,attr = %d,data type=%d,data = %d\r\n",reportInfo->attrList[0].attrID,reportInfo->attrList[0].dataType,reportInfo->attrList[0].attrData[0]);
	switch(cluster)
	{
		//当report的是子设备时进行过滤
		case ZCL_CLUSTER_GEN_ON_OFF:
		{
			uint16_t sender = pInHdlrMsg->msg->indInfo.src_short_addr;
			for(uint8_t i = 0;i<(reportInfo->numAttr);i++){
				uint8_t dataType =  reportInfo->attrList[i].dataType;
				if(reportInfo->attrList[i].attrID == ZCL_ATTRID_ONOFF && dataType == ZCL_DATA_TYPE_BOOLEAN){
					bool on_off_ctr = reportInfo->attrList[0].attrData[i];
					if (sender != 0x0000){//sender是芯科SDK里的参数
						uint8_t index = 0;
						uint8_t storedSequence = kSequenceFindByNodeidAndEp(sender, pInHdlrMsg->msg->indInfo.dst_ep, &index);
						iKonkeAfSelfPrint("######zclReportCmdHandler111111,sender = %d,directed endpoint = %d,seqNum = %d,storedSequence = %d\r\n", \
													sender,pInHdlrMsg->msg->indInfo.dst_ep,pInHdlrMsg->hdr.seqNum,storedSequence);
						//过滤seq,以免早的seq改变后来的seq状态
						if (pInHdlrMsg->hdr.seqNum <= storedSequence && storedSequence - pInHdlrMsg->hdr.seqNum <= 60) {
							//直接不执行当前操作
							iKonkeAfSelfPrint("######zclReportCmdHandler222222\r\n");
							return;
						}else {
							iKonkeAfSelfPrint("######zclReportCmdHandler333333\r\n");
							kSequenceAdd(sender, pInHdlrMsg->msg->indInfo.dst_ep, pInHdlrMsg->hdr.seqNum);
						}
					}
					ZclOnOffControlInfoSt ZclOnOffControlInfo;
					iKonkeAfSelfPrint("Multi-ContorlWrite Attribute ep(%d) value(%d)\r\n", pInHdlrMsg->msg->indInfo.dst_ep, on_off_ctr);
					switch (on_off_ctr)
					{
						case 0x00:
						case 0x01:
						{
							iKonkeAfSelfPrint("!!!!!!!!!!!!!OnOffValue111111 = %d!!!!!!!!!\r\n",on_off_ctr);
							ON_OFF_Cmd_Handler(ep,on_off_ctr);
							addrExt_t senderEui64 = {0};
							for(uint8_t i = 0;i<8;i++){
								senderEui64[i] = pInHdlrMsg->msg->indInfo.src_ext_addr[i];
							}
							memcpy(ZclOnOffControlInfo.maskEui64Addr, senderEui64, 8);
							ZclOnOffControlInfo.dest_endpoint = pInHdlrMsg->msg->indInfo.src_ep;
							//采用单播上报的方式，实现多控时的单向控制
							kZclClusterSetPermitReportInfo(ep, ZCL_CLUSTER_GEN_ON_OFF, true, false, false, false, ZclOnOffControlInfo.maskEui64Addr, ZclOnOffControlInfo.dest_endpoint);
							clusterattrid.clusterId[ep] = ZCL_CLUSTER_GEN_ON_OFF;
							clusterattrid.attrID[ep] = ZCL_ATTRID_ONOFF;
							if (ep == 1){
								kSrcEp1Multieport = TL_ZB_TIMER_SCHEDULE(kSrcEp1MultieportEventHandler, NULL, 50);
							}else if (ep == 2){
								kSrcEp2Multieport = TL_ZB_TIMER_SCHEDULE(kSrcEp2MultieportEventHandler, NULL, 50);
							}else if (ep == 3){
								kSrcEp3Multieport = TL_ZB_TIMER_SCHEDULE(kSrcEp3MultieportEventHandler, NULL, 50);
							}else if (ep == 4){
								kSrcEp4Multieport = TL_ZB_TIMER_SCHEDULE(kSrcEp4MultieportEventHandler, NULL, 50);
							}
						}
							break;
						case 0x02:
							break;
						default:
							break;
					}
				}
			}
			break;
		}
		default:
			break;
	}
}

status_t sampleLight_onOffCb(zclIncomingAddrInfo_t *pAddrInfo, u8 cmdId, void *cmdPayload)
{
	uint8_t ep  = pAddrInfo->dstEp;
	zcl_onOffAttr_t *pOnOff = zcl_onoffAttrGet(ep);
	bool on_off_ctr;
	switch(cmdId){
		case ZCL_CMD_ONOFF_ON:
		{
			pOnOff->globalSceneControl = TRUE;
			pOnOff->onOff = ZCL_ONOFF_STATUS_ON;
			on_off_ctr = true;
			if(pOnOff->onTime == 0){
				pOnOff->offWaitTime = 0;
			}
			ON_OFF_Cmd_Handler(ep,on_off_ctr);
			break;
		}
		case ZCL_CMD_ONOFF_OFF:
		{
			pOnOff->onOff = ZCL_ONOFF_STATUS_OFF;
			pOnOff->onTime = 0;
			on_off_ctr = false;
			ON_OFF_Cmd_Handler(ep,on_off_ctr);
			break;
		}
		case ZCL_CMD_ONOFF_TOGGLE:
		{
			if(pOnOff->onOff == ZCL_ONOFF_STATUS_OFF){
				pOnOff->globalSceneControl = TRUE;

				pOnOff->onOff = ZCL_ONOFF_STATUS_ON;
				on_off_ctr = true;
				if(pOnOff->onTime == 0){
					pOnOff->offWaitTime = 0;
				}
			}else{
				pOnOff->onOff = ZCL_ONOFF_STATUS_OFF;
				pOnOff->onTime = 0;
				on_off_ctr = false;
			}

			ON_OFF_Cmd_Handler(ep,on_off_ctr);
			break;
		}
		case ZCL_CMD_OFF_WITH_EFFECT:
			if(pOnOff->globalSceneControl == TRUE){
				/* TODO: store its settings in its global scene */

				pOnOff->globalSceneControl = FALSE;
			}
			sampleLight_onoff_offWithEffectProcess(ep,(zcl_onoff_offWithEffectCmd_t *)cmdPayload);
			break;
		case ZCL_CMD_ON_WITH_RECALL_GLOBAL_SCENE:
			if(pOnOff->globalSceneControl == FALSE){
				sampleLight_onoff_onWithRecallGlobalSceneProcess();
				pOnOff->globalSceneControl = TRUE;
			}
			break;
		case ZCL_CMD_ON_WITH_TIMED_OFF:
			sampleLight_onoff_onWithTimedOffProcess(ep,(zcl_onoff_onWithTimeOffCmd_t *)cmdPayload);
			break;
		default:
			break;
	}
	return ZCL_STA_SUCCESS;
}

#endif  /* __PROJECT_TL_DIMMABLE_LIGHT__ */
