/************************************************************
*版权所有 （C）2020，公司（或个人）名称
*
*文件名称： kk_dm_heartbeat.c
*内容摘要： 设备心跳处理
*其他说明： 
*当前版本：  
*************************************************************/
 
/*************************************************************
头文件引用 
*************************************************************/


#include <string.h>
#include <stdlib.h>
#include "klist.h"
#include "kk_log.h"
#include "kk_tsl_common.h"
#include "kk_dm_mng.h"
#include "kk_hal.h"

/*************************************************************
全局变量定义 
*************************************************************/

typedef struct {
	void *mutex;
	void *hearbeat_thread;
	int hearbeat_thread_running;	
	struct list_head gw_status_list;	
} kk_heartbeat_ctx_t;

typedef struct {
	int isOnline;
	time_t starttime;
	char deviceCode[DEVICE_CODE_MAXLEN];
	struct list_head linked_list;
} kk_gw_status_ctx_t;
time_t s_start_time = 0;
static kk_heartbeat_ctx_t s_kk_heartbeat_ctx = {0};

/*************************************************************
函数实现 
*************************************************************/

static kk_heartbeat_ctx_t *_kk_heartbeat_get_ctx(void)
{
	return &s_kk_heartbeat_ctx;
}
static void _kk_heartbeat_lock(void)
{
	kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();
	if (ctx->mutex) {
		HAL_MutexLock(ctx->mutex);
	}
}

static void _kk_heartbeat_unlock(void)
{
	kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();
	if (ctx->mutex) {
		HAL_MutexUnlock(ctx->mutex);
	}
}

/************************************************************
*功能描述： 心跳处理主任务
*输入参数： args：传入参数，暂未使用
*输出参数： 无
*返 回 值：  
*其他说明：
*************************************************************/
void *kk_heartbeat_yield(void *args)
{
	kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();
	time_t current_time = 0;
	time_t sys_time = 0;	
	int res = 0;
	dm_mgr_dev_node_t *node = NULL;	
	kk_gw_status_ctx_t *gw = NULL;	
	while (ctx->hearbeat_thread_running) {
		current_time = HAL_GetTime();
		sys_time = HAL_Uptimes();

		_kk_heartbeat_lock();
		if (!list_empty(&ctx->gw_status_list)) {

			list_for_each_entry(gw, &ctx->gw_status_list, linked_list, kk_gw_status_ctx_t){
				if(gw->isOnline == KK_DEV_ONLINE){
					list_del(&gw->linked_list);
					//kk_subDev_send_property_get(gw->deviceCode);
					free(gw);
				}
				else{
					res = dm_mgr_get_device_by_devicecode(gw->deviceCode,&node);
					if (res != SUCCESS_RETURN) {
						ERROR_PRINT("ERROR [%s][%d] res:%d\n",__FUNCTION__,__LINE__,res);
					}
					if(node->hb_timeout == 0){
						node->hb_timeout = DEFAULT_HEARTBEAT_TIMEOUT;
					}
					/*开机如果一直没有收到网关reply,等待到超时到后发送超时到云端*/
					if((current_time - gw->starttime) >= node->hb_timeout){
						//printf("&&&&&&&&&&&&&&&&&&&&&&[%s][%d]\n",__FUNCTION__,__LINE__);
						INFO_PRINT("GW is off line now!!! deviceCode:%s\n",node->deviceCode);
						dm_mgr_set_dev_onoffline(node,KK_DEV_OFFLINE);
						list_del(&gw->linked_list);
						free(gw);
					}
					else{
						/*先下发网关属性获取，判断网关是否在线*/
						kk_msg_execute_property_get(node);
					}
				}
			}
		}
		_kk_heartbeat_unlock();
		dm_mgr_check_heartbeat_timeout(sys_time);
		sleep(1);
	}
	return NULL;
}
/************************************************************
*功能描述： 心跳模块初始化
*输入参数： 无
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_heartbeat_init(void)
{
	int res = 0;
	kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();
	/* Create Mutex */
	ctx->mutex = HAL_MutexCreate();
	if (ctx->mutex == NULL) {
		return FAIL_RETURN;
	}
	/* Init Device Id*/
	INIT_LIST_HEAD(&ctx->gw_status_list);
	ctx->hearbeat_thread_running = 1;
	s_start_time = HAL_Uptimes();

	res = pthread_create(&ctx->hearbeat_thread, NULL, kk_heartbeat_yield, NULL);
	if (res < 0) {
		ERROR_PRINT("HAL_ThreadCreate ota Failed\n");
		//IOT_Linkkit_Close(mid_ctx->master_devid);
		return FAIL_RETURN;
	}
	return SUCCESS_RETURN;

	/* Init Device List */
	// INIT_LIST_HEAD(&ctx->dev_list);
}
/************************************************************
*功能描述： 上电把需要查询状态的网关加入队列，load设备的时候调用此函数
*输入参数： deviceCode：网关deviceCode
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_dm_gw_status_check_push(const char *deviceCode)
{
	kk_gw_status_ctx_t *gw = NULL;
	kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();

	if(deviceCode == NULL){
		ERROR_PRINT("kk_dm_gw_status_check_push Failed\n");
		return INVALID_PARAMETER;
	}
	gw = malloc(sizeof(kk_gw_status_ctx_t));
	if (gw == NULL) {
		ERROR_PRINT("kk_dm_gw_status_check_push malloc Failed\n");
		return MEMORY_NOT_ENOUGH;
	}
	memset(gw, 0, sizeof(kk_gw_status_ctx_t));	
	_kk_heartbeat_lock();
	memcpy(gw->deviceCode,deviceCode,strlen(deviceCode));	
	gw->isOnline = KK_DEV_UNKNOW;
	gw->starttime = HAL_GetTime();
	INIT_LIST_HEAD(&gw->linked_list);
	list_add_tail(&gw->linked_list, &ctx->gw_status_list);	
	_kk_heartbeat_unlock();
	return SUCCESS_RETURN;
}

/************************************************************
*功能描述： 收到网关反馈后更新网关在线标记，收到网关消息后调用此函数
*输入参数： deviceCode：网关deviceCode
*输出参数： 无
*返 回 值：  0：成功；其他：失败
*其他说明：
*************************************************************/
int kk_dm_gw_status_update_online(const char *deviceCode)
{
	kk_gw_status_ctx_t *gw = NULL;
	kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();
	
	_kk_heartbeat_lock();
	list_for_each_entry(gw,&ctx->gw_status_list,linked_list,kk_gw_status_ctx_t){
		if(0 == strcmp(gw->deviceCode,deviceCode))
		{
			INFO_PRINT("kk_dm_gw_status_update_online find!!!\n");
			gw->isOnline = KK_DEV_ONLINE;
			_kk_heartbeat_unlock();
			return SUCCESS_RETURN;
		}
	}

	_kk_heartbeat_unlock();
	return FAIL_RETURN;
}

