#include <string.h>
#include <stdlib.h>
#include "klist.h"
#include "kk_log.h"
#include "kk_tsl_common.h"
#include "kk_dm_mng.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;

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);
    }
}
uint64_t s_start_time = 0;

void *kk_heartbeat_yield(void *args)
{
    kk_heartbeat_ctx_t *ctx = _kk_heartbeat_get_ctx();
	time_t current_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();

		_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(current_time);
		sleep(1);
    }
    return NULL;
}

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_UptimeMs();

	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);

}

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;
}

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;
}

