#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>

#include "ip_camera.h"

#define RTSP_PORT 554

char heartbeat[64];
ip_camera_var_t gvar = {0};
gw_port_e ports[] = {TCP_CLIENT};

/**
*
* @author: cnscn@163.com
* @reference: lovesnow1314@http://community.csdn.net/Expert/TopicView3.asp?id=5198221 
*
* 用新子串newstr替换源字符串src中的前len个字符内所包含的oldstr子串
*
* @param char* dest 目标串，也就是替换后的新串
* @param const char* src 源字符串，被替换的字符串
* @param const char* oldstr 旧的子串，将被替换的子串
* @param const char* newstr 新的子串
* @param int len 将要被替换的前len个字符
*
* @return char* dest 返回新串的地址
*
*/
static char *strreplace(char *dest, char *src, const char *oldstr, const char *newstr, size_t len)
{
	//如果串相等，则直接返回
	if(strcmp(oldstr, newstr)==0)
		return src; 

	//子串位置指针
	char *needle;
	 

	//临时内存区
	char *tmp; 

	//把源串地址赋给指针dest，即让dest和src都指向src的内存区域
	dest = src; 

	//如果找到子串, 并且子串位置在前len个子串范围内, 则进行替换, 否则直接返回
	while((needle = strstr(dest, oldstr)) && (needle -dest <= len))
	{
		//分配新的空间: +1 是为了添加串尾的'\0'结束符
		tmp=(char*)malloc(strlen(dest)+(strlen(newstr)-strlen(oldstr))+1); 

		//把src内的前needle-dest个内存空间的数据，拷贝到arr
		strncpy(tmp, dest, needle-dest); 

		//标识串结束
		tmp[needle-dest]='\0'; 

		//连接arr和newstr, 即把newstr附在arr尾部, 从而组成新串(或说字符数组)arr
		strcat(tmp, newstr); 

		//把src中 从oldstr子串位置后的部分和arr连接在一起，组成新串arr
		strcat(tmp, needle+strlen(oldstr)); 

		//把用malloc分配的内存，复制给指针retv
		dest = strdup(tmp); 

		//释放malloc分配的内存空间
		free(tmp);
	} 

	return dest;
}

int init_python_env()
{
	if(gvar.python == 1)
	{
		//关闭python调用
    	Py_Finalize();
		gvar.python = 0;
		dy_syslog(LOG_DEBUG, "python Py_Finalize...");
	}
	if (gvar.python == 0)
    {
    	dy_syslog(LOG_DEBUG, "python Py_Initialize...");
        //初始化，载入python的扩展模块
        Py_Initialize();
        //判断初始化是否成功
        if (!Py_IsInitialized())
        {
            dy_syslog(LOG_WARNING, "Python init failed!\n");
        }
        //导入当前路径
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('./')");
        PyRun_SimpleString("sys.path.append('/app/script/')");
		PyRun_SimpleString("sys.path.append('/app/default_script/')");

        gvar.python = 1;
    }
}

static int get_rt_data_from_json_str(pp_real_time_data_t *real_data, char *json_str)
{
    int ret = 0;

    cJSON *root = cJSON_Parse(json_str);
    if (root)
    {
        char *payload = NULL;
        char *buf = NULL;

        buf = (char *)malloc(MAXBUF);
        if (buf == NULL)
        {
            dy_syslog(LOG_ERR, "malloc failed");
            ret = -1;
            goto out;
        }

        GET_JSON_VALUE_STRING(root, "port", buf);
        real_data->port = port_char2enum(buf);
        GET_JSON_VALUE_INT(root, "instruction_code", real_data->instruction_code);
        GET_JSON_VALUE_INT(root, "mi", real_data->mi);
        GET_JSON_VALUE_INT(root, "ts", real_data->ts);
        GET_JSON_VALUE_INT(root, "len", real_data->len);
        GET_JSON_VALUE_INT(root, "sub_term_addr_len", real_data->sub_term_addr_len);
        GET_JSON_VALUE_INT(root, "start_addr", real_data->start_addr);
        GET_JSON_VALUE_STRING(root, "sub_template_id", real_data->sub_template_id);
        GET_JSON_VALUE_STRING(root, "src_identifier", real_data->src_identifier);
        GET_JSON_VALUE_STRING(root, "sn", real_data->sn);
        GET_JSON_VALUE_STRING(root, "dtu_sn", real_data->dtu_sn);

        GET_JSON_VALUE_STRING(root, "data_b64", buf);
		dy_syslog(LOG_DEBUG, "buf:%s, real_data->len:%d", buf, real_data->len);
        real_data->data = calloc(real_data->len+1, 1);
        if (real_data->data == NULL)
        {
            dy_syslog(LOG_ERR, "malloc fail len:%d", real_data->len);
            free(buf);
            goto out;
        }
        memcpy(real_data->data, buf, real_data->len);
		dy_syslog(LOG_DEBUG, "real_data->data:%s, real_data->len:%d", real_data->data, real_data->len);
		free(buf);
    }
    else
    {
        dy_syslog(LOG_ERR, "json parse error");
        ret = -1;
    }

out:
    cJSON_Delete(root);

    return ret;
}

static int get_port_mapping(char *mapping, char *ip_addr, int port)
{
    int ret = -1;
    char buff[255] = {0};
    char *string = NULL;
    snprintf(buff, sizeof(buff), "grep -A 5 -B 5 \"src_dport '%d'\" /etc/config/firewall | grep \"dest_ip '%s'\"", port, ip_addr);
    ret = system_reply(buff, &string);
	//dy_syslog(LOG_DEBUG, "ret %d string %p", ret, string);
    if (ret == 0)
    {
        if (!string)return 0;
		dy_syslog(LOG_DEBUG, "string:%s %d", string, strlen(string));
		strcpy(mapping, string);
        free(string);
		return 1;
    }
    return -1;
}

static int get_wan_port_ip(char *wan_ip_addr)
{
    int ret = -1;
    char buff[255] = {0};
    char *string = NULL;
    snprintf(buff, sizeof(buff), "ubus call network.interface.wan status | grep \"address\" | grep -oE '[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}'; ");
    ret = system_reply(buff, &string);
    if (ret == 0)
    {
        if (!string)return 0;
		//strcpy(wan_ip_addr, string);
		//dy_syslog(LOG_DEBUG, "---string %s", string);
		if(strlen(string))
		{
			unsigned char ip_buf[4] = {0};
			int cnt = sscanf(string, "%d.%d.%d.%d", &ip_buf[0], &ip_buf[1], &ip_buf[2], &ip_buf[3]);
			snprintf(wan_ip_addr, 32, "%d.%d.%d.%d", ip_buf[0], ip_buf[1], ip_buf[2], ip_buf[3]);
			dy_syslog(LOG_DEBUG, "--cnt %d wan_ip_addr:%s len:%d", cnt,wan_ip_addr,strlen(wan_ip_addr));
		}
        free(string);
		return 1;
    }
    return -1;
}

static int generate_port_mapping(char *ip_addr, int port, int out_port)
{
    int ret = -1;
    char buff[512] = {0};
    char *string = NULL;
    snprintf(buff, sizeof(buff), "uci add firewall redirect;uci set firewall.@redirect[-1].src=wan;uci set firewall.@redirect[-1].src_dport=%d;uci set firewall.@redirect[-1].dest_ip=%s;uci set firewall.@redirect[-1].dest=lan;uci set firewall.@redirect[-1].dest_port=%d;uci set firewall.@redirect[-1].proto=tcp;uci commit firewall;/etc/init.d/firewall restart;", out_port, ip_addr, port);
    ret = system_reply(buff, &string);
    if (ret == 0)
    {
        if (!string)return 0;        
        free(string);
		return 1;
    }
    return -1;
}

static void generate_rtsp_url(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, char *result_data)
{
	char wan_ip_addr[32] = {0};
	int out_ip = 554;
	
	//生成URL
	//strcpy(result_data, "rtsp://192.168.0.110:554/cam/realmonitor?channel=1&subtype=0&unicast=true");
	//rtsp://admin:a12345678@10.3.1.202:554/cam/realmonitor?channel=1&subtype=0&unicast=true
	get_wan_port_ip(wan_ip_addr);
	dy_syslog(LOG_DEBUG, "wan_ip_addr:%s len:%d", wan_ip_addr,strlen(wan_ip_addr));
	if(strlen(wan_ip_addr))
	{
		char head[128] = {0};
		char *ip, *port, *extend;
		ip = strstr(result_data, ip_camera_cfg->camera_cfg.ip_addr);
		if(!ip)
		{
			dy_syslog(LOG_WARNING, "ip is %p", ip);
			return;
		}
		
		port = strstr(ip, ":");
		if(!port)
		{
			dy_syslog(LOG_WARNING, "port is %p", port);
			return;
		}
		
		extend = strstr(port, "/");
		if(!extend)
		{
			dy_syslog(LOG_WARNING, "extend is %p", extend);
			return;
		}

		if(ip_camera_cfg->camera_cfg.rtsp_url == NULL)
		{
			ip_camera_cfg->camera_cfg.rtsp_url = calloc(512, 1);
			ip_camera_cfg->camera_cfg.rtsp_url_local = calloc(512, 1);
		}

		strncpy(head, result_data, ip-result_data);
		snprintf(ip_camera_cfg->camera_cfg.rtsp_url, 512, "%s%s:%s@%s:%d%s",head,ip_camera_cfg->camera_cfg.user,ip_camera_cfg->camera_cfg.password,wan_ip_addr,out_ip,extend);
		snprintf(ip_camera_cfg->camera_cfg.rtsp_url_local, 512, "%s%s:%s@%s:%d%s",head,ip_camera_cfg->camera_cfg.user,ip_camera_cfg->camera_cfg.password,ip_camera_cfg->camera_cfg.ip_addr,out_ip,extend);
		dy_syslog(LOG_DEBUG, "url:%s", ip_camera_cfg->camera_cfg.rtsp_url);
		dy_syslog(LOG_DEBUG, "rtsp_url_local:%s", ip_camera_cfg->camera_cfg.rtsp_url_local);
		strcpy(result_data, ip_camera_cfg->camera_cfg.rtsp_url);
	}							
}

static void generate_common_repay_package(encode_info_t *encode_info, char *result_data, int *len, char *data)
{
    cJSON *jtag = cJSON_CreateObject();
	cJSON_AddStringToObject(jtag, "result", data);
	char *json_str = cJSON_PrintUnformatted(jtag);

	encode_info->stream_direction = 1;
	strcpy(result_data, json_str);
	*len = strlen(result_data);

	free(json_str);
	cJSON_Delete(jtag);
}

static void ipc_get_stream_url(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, char *result_data)
{
	char mapping[256] = {0};

	if(ip_camera_cfg->camera_cfg.rtsp_url)
		strcpy(result_data, ip_camera_cfg->camera_cfg.rtsp_url);
	else
	{
		//已映射，要把端口取出来
		get_port_mapping(mapping, ip_camera_cfg->camera_cfg.ip_addr, RTSP_PORT);
		if(strlen(mapping) == 0)
		{
			int out_ip = 554;
			//添加端口映射
			generate_port_mapping(ip_camera_cfg->camera_cfg.ip_addr, RTSP_PORT, out_ip);
								
		}
		generate_rtsp_url(var, ip_camera_cfg, result_data);
	}
}

static int add_node_config(ip_camera_var_t * var, camera_config_t *camera_cfg, char *file, cJSON *jroot, cJSON *jnodes,int update)
{
    cJSON* root=NULL;
    cJSON* nodes = NULL;

	if(jroot && jnodes)
	{
		root = jroot;
		nodes = jnodes;
	}
	else
	{
		root=cJSON_CreateObject();
	    if(root == NULL)           return -1;
	    nodes = cJSON_CreateArray();
	    cJSON_AddItemToObject(root,"ip_camera_cfg",nodes);
	}

	cJSON *item = cJSON_CreateObject();
    cJSON_AddItemToArray(nodes,item);
	cJSON_AddStringToObject(item, "sn", camera_cfg->sn);
	cJSON_AddStringToObject(item, "ip_addr", camera_cfg->ip_addr);
	cJSON_AddNumberToObject(item, "port", camera_cfg->port);
	cJSON_AddStringToObject(item, "user", camera_cfg->user);
	cJSON_AddStringToObject(item, "password", camera_cfg->password);	

	char *str = (cJSON_Print(root));
    cJSON_Delete(root);

	write_file_data(file, str, strlen(str));
	free(str);
	if(update == 0)
	{
		ip_camera_config_t *ip_camera_cfg = calloc(1, sizeof(ip_camera_config_t));
		memcpy(&ip_camera_cfg->camera_cfg, camera_cfg, sizeof(camera_config_t));
		
		dy_syslog(LOG_INFO,"==sn:%s ip_addr:%s port:%d user:%s password:%s==",ip_camera_cfg->camera_cfg.sn,ip_camera_cfg->camera_cfg.ip_addr,ip_camera_cfg->camera_cfg.port,ip_camera_cfg->camera_cfg.user,ip_camera_cfg->camera_cfg.password);
		list_add_tail(&ip_camera_cfg->list, &var->config_list);
	}
	
    return 0;

}

static int ipc_add_node_config(ip_camera_var_t *var, char *file, camera_config_t *camera_cfg)
{
	char buff[128] = {0};
	int ret 	   = 0;
	int i		   = 0;

	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        goto __add_config;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
       goto __add_config;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "ip_camera_cfg");
    if (!nodes)
    {
        goto __add_config;
    }

	add_node_config(var, camera_cfg, file, root, nodes, 0);
	return ret;

__add_config:
	add_node_config(var, camera_cfg, file, NULL, NULL, 0);	
    return ret;
}

static int ipc_update_node_config(ip_camera_var_t *var, char *file, camera_config_t *camera_cfg, int delete)
{
	char buff[128] = {0};
	int ret 	   = 0;
	int i		   = 0;

	dy_syslog(LOG_DEBUG, "delete object sn:%s", camera_cfg->sn);
	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        goto __add_config;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
       goto __add_config;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "ip_camera_cfg");
    if (!nodes)
    {
        goto __add_config;
    }

    int node_cnt = cJSON_GetArraySize(nodes);

    for (i = 0; i < node_cnt ; i++)
    {
        cJSON *node = cJSON_GetArrayItem(nodes, i);
        if (node)
        {
        	char sn[32] = {0};
        	GET_JSON_VALUE_STRING(node, "sn", sn);
			if(strcmp(sn, camera_cfg->sn) == 0)
			{
				dy_syslog(LOG_DEBUG, "delete object sn:%s", sn);
				cJSON_DeleteItemFromArray(nodes, i);
				dy_syslog(LOG_DEBUG, "root:%s", cJSON_PrintUnformatted(root));
				break;
			}
        }
    }

	if(delete)
	{
		char *str = (cJSON_Print(root));
	    cJSON_Delete(root);

		write_file_data(file, str, strlen(str));
		free(str);
		return ret;
	}

	add_node_config(var, camera_cfg, file, root, nodes, 1);
	return ret;

__add_config:
	add_node_config(var, camera_cfg, file, NULL, NULL, 0);
    return ret;
}

static int ipc_load_node_config(ip_camera_var_t *var, char *file)
{
	char buff[128] = {0};
	int ret 	   = -1;
	int i		   = 0;

	char *json_str = NULL;
    json_str = read_file_data(file);
    if (!json_str)
    {
        return -1;
    }

    cJSON *root = cJSON_Parse(json_str);
    if (!root)
    {
        return -1;
    }

    cJSON *nodes = cJSON_GetObjectItem(root, "ip_camera_cfg");
    if (!nodes)
    {
        ret = -1;
        goto __cleanup;
    }

    int size = cJSON_GetArraySize(nodes);

    for (i = 0; i < size ; i++)
    {
        cJSON *node = cJSON_GetArrayItem(nodes, i);
        if (!node)
        {
            ret = i + 1;
            goto __cleanup;
        }

		ip_camera_config_t *ip_camera_cfg = calloc(1, sizeof(ip_camera_config_t));
		GET_JSON_VALUE_STRING(node, "sn", ip_camera_cfg->camera_cfg.sn);
		GET_JSON_VALUE_STRING(node, "ip_addr", ip_camera_cfg->camera_cfg.ip_addr);
		GET_JSON_VALUE_INT(node, "port", ip_camera_cfg->camera_cfg.port);
		GET_JSON_VALUE_STRING(node, "user", ip_camera_cfg->camera_cfg.user);
		GET_JSON_VALUE_STRING(node, "password", ip_camera_cfg->camera_cfg.password);

		
		dy_syslog(LOG_INFO,"==%d %d sn:%s ip_addr:%s port:%d user:%s password:%s==",size,i,ip_camera_cfg->camera_cfg.sn,ip_camera_cfg->camera_cfg.ip_addr,ip_camera_cfg->camera_cfg.port,ip_camera_cfg->camera_cfg.user,ip_camera_cfg->camera_cfg.password);
		list_add_tail(&ip_camera_cfg->list, &var->config_list);
    }
    ret = 0;

__cleanup:
    cJSON_Delete(root);
    return ret;
}

static int unload_script_python_module(ip_camera_config_t *ip_camera_cfg, char *file_name)
{
	//清理python对象
    if (ip_camera_cfg->python->pName)
    {
        Py_DECREF(ip_camera_cfg->python->pName);
		ip_camera_cfg->python->pName = NULL;
    }
    if (ip_camera_cfg->python->pModule)
    {
        Py_DECREF(ip_camera_cfg->python->pModule);
		ip_camera_cfg->python->pModule = NULL;
    }
	if (ip_camera_cfg->python->pDict)
    {
        Py_DECREF(ip_camera_cfg->python->pDict);
		ip_camera_cfg->python->pDict = NULL;
    }
	if (ip_camera_cfg->python->pFunc)
    {
        Py_DECREF(ip_camera_cfg->python->pFunc);
		ip_camera_cfg->python->pFunc = NULL;
    }
	
	dy_syslog(LOG_INFO, "--------python unloadfile file_name %s--------", file_name);

    return 0;
}

static int load_script_python_module(ip_camera_config_t *ip_camera_cfg, char *file_name)
{
	static int err_cnt = 0;
	
	if(ip_camera_cfg->python == NULL)
		ip_camera_cfg->python = calloc(sizeof(camera_handle_t), 1);

	unload_script_python_module(ip_camera_cfg, file_name);
	init_python_env();
	
	//unload_script_python_module(ip_camera_cfg, file_name);	
	ip_camera_cfg->python->pName = PyString_FromString(file_name);
	dy_syslog(LOG_INFO, "python PyString_FromString file_name %s pName %p", file_name, ip_camera_cfg->python->pName);
	ip_camera_cfg->python->pModule = PyImport_Import(ip_camera_cfg->python->pName);
	dy_syslog(LOG_INFO, "python PyImport_Import %s pModule %p ...", file_name,ip_camera_cfg->python->pModule);
	if (!ip_camera_cfg->python->pModule)
    {
    	err_cnt++;
        dy_syslog(LOG_WARNING, "Load %s err_cnt %d failed!", file_name,err_cnt);
		if(err_cnt > 3)
		{
			dy_syslog(LOG_ERR,"%s exit(1)\n",__FUNCTION__);
			exit(1);
		}
		return -1;
    }
	err_cnt = 0;
    ip_camera_cfg->python->pDict = PyModule_GetDict(ip_camera_cfg->python->pModule);	
	if (!ip_camera_cfg->python->pDict)
    {
        dy_syslog(LOG_WARNING, "Can't find dict in %s!", file_name);
        return -1;
    }

	ip_camera_cfg->python->pFunc = PyDict_GetItemString(ip_camera_cfg->python->pDict, IP_CAMERA_FUN);
	if (!ip_camera_cfg->python->pFunc || !PyCallable_Check(ip_camera_cfg->python->pFunc))
    {
        dy_syslog(LOG_WARNING, "Can't find function!\n");
        return -1;
    }
	
	dy_syslog(LOG_INFO, "--------python loadfile file_name %s pName %p pModule %p pDict %p ok...--------", file_name,ip_camera_cfg->python->pName,ip_camera_cfg->python->pModule,ip_camera_cfg->python->pDict);

    return 0;
}

static int exec_encode_script_python(ip_camera_var_t *var, camera_handle_t *python, char *json_str, unsigned short len, char *result_data, int *result_len, encode_info_t *encode_info)
{
    PyObject *pArgs = NULL;
    unsigned char tmp_index = 0;
    int i;
    char *bin_str;
    long json_len = 0, error_code = -1, flow_direction = 0;
	
	if (!python->pFunc || !PyCallable_Check(python->pFunc))
    {
        dy_syslog(LOG_WARNING, "Can't find function!\n");
        return error_code;
    }

	if(result_len)
		tmp_index = *result_len;

    pArgs = PyTuple_New(2);
    PyTuple_SetItem(pArgs, 0, Py_BuildValue("s", json_str));
    PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", len));

	dy_syslog(LOG_DEBUG, "json_str:%s", json_str);
    PyObject *presult = PyObject_CallObject(python->pFunc, pArgs);
	if(presult)
	{
		PyArg_ParseTuple(presult, "isi", &error_code, &bin_str, &json_len);		
    	dy_syslog(LOG_DEBUG, "encode %s error_code %d bin_str %s json_len %d flow_direction %d", __FUNCTION__, error_code, bin_str, json_len, flow_direction);
	}
	else
	{
		python->inited = 0;
		dy_syslog(LOG_WARNING, "encode %s presult %p", __FUNCTION__, presult);
		return error_code;
	}

    if((error_code >> 12) & 0x01 == 0x01)
	{
		encode_info->stream_direction = 1;
	}
	if((error_code >> 13) & 0x01 == 0x01)
	{
		encode_info->no_base64 = 1;
	}

	error_code = error_code & 0xFFF;
	dy_syslog(LOG_DEBUG, "stream_direction %d no_base64 %d error_code %d json_len %d result_data %p", encode_info->stream_direction, encode_info->no_base64,error_code,json_len,result_data);
    if (json_len && result_data)
    {
    	dy_syslog(LOG_DEBUG, "stream_direction %d no_base64 %d error_code %d json_len %d result_data %p", encode_info->stream_direction, encode_info->no_base64,error_code,json_len,result_data);
    	if(!error_code && encode_info->no_base64 == 0)
    	{
	        for (i = 0; i < json_len / 2; i++)
	        {
	            sscanf(bin_str + i * 2, "%02x", &result_data[tmp_index + i]);
	            //dy_syslog(LOG_INFO, "bin[%d] %x", tmp_index + i, bin[tmp_index + i]);
	        }
	        *result_len = tmp_index + json_len / 2;
    	}
		else
		{
			*result_len = json_len;
			strncpy(result_data, bin_str, json_len);
			dy_syslog(LOG_DEBUG, "result_data:%s *result_len %d", result_data, *result_len);
		}
    }

	if (pArgs)
    {
        Py_DECREF(pArgs);
    }

    return error_code;
}

int ipc_get_stream_uri_script(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, encode_info_t *encode_info)
{
	int err_code = 1;
	cJSON *jparam = cJSON_CreateObject();
	//{"identifier":"GetStreamUri","sn":"1111AAAA","mi":5792398,"timestamp":1590137343,"ip_addr":"192.168.0.110","port":80,"term_addr":"1902"}
	cJSON_AddStringToObject(jparam, "identifier", "GetStreamUri");
	cJSON_AddStringToObject(jparam, "ip_addr", ip_camera_cfg->camera_cfg.ip_addr);
	cJSON_AddNumberToObject(jparam, "port", ip_camera_cfg->camera_cfg.port);

	char *json_str = cJSON_PrintUnformatted(jparam);
	char *result_data = calloc(MAXBUF, 1);
	int len = 0;
	
	err_code = exec_encode_script_python(var, ip_camera_cfg->python, json_str, strlen(json_str), result_data, &len, encode_info);
	if(err_code == 0 && len > 0)
	{
		ipc_get_stream_url(var, ip_camera_cfg, result_data);
	}
	
	cJSON_Delete(jparam);
	free(json_str);
	free(result_data);
	
	return err_code;
}

void exec_init_cmd_script(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, encode_info_t *encode_info, char *result_data, int *len)
{
	cJSON *jparam = cJSON_CreateObject();
	cJSON_AddStringToObject(jparam, "identifier", "InitIPCamera");
	cJSON_AddStringToObject(jparam, "ip_addr", ip_camera_cfg->camera_cfg.ip_addr);
	cJSON_AddNumberToObject(jparam, "port", ip_camera_cfg->camera_cfg.port);
	cJSON_AddStringToObject(jparam, "user", ip_camera_cfg->camera_cfg.user);
	cJSON_AddStringToObject(jparam, "password", ip_camera_cfg->camera_cfg.password);

	char *json_str = cJSON_PrintUnformatted(jparam);
	if(ip_camera_cfg->python->inited == 0 && exec_encode_script_python(var, ip_camera_cfg->python, json_str, strlen(json_str), result_data, len, encode_info) == 0)
	{
		ip_camera_cfg->python->inited = 1;
		encode_info_t tmp_info = {0};
		ipc_get_stream_uri_script(var, ip_camera_cfg, &tmp_info);
	}
	
	cJSON_Delete(jparam);
	free(json_str);
}

static void update_depend_package_info(ip_camera_var_t *var)
{
	app_config_t app_cfg = {0};

	strcpy(app_cfg.name, "onvif");
	strcpy(app_cfg.version, "0.2.0");
	strcpy(app_cfg.depend_name, "ip_camera");
	strcpy(app_cfg.cmd, "pip install onvif");
	strcpy(app_cfg.check_cmd, "pip list | grep \"onvif\"");
	
	app_manager_send_package_info(var->session, &app_cfg);


	memset(&app_cfg, 0, sizeof(app_config_t));

	strcpy(app_cfg.name, "ffmpeg");
	strcpy(app_cfg.version, "3.2.2-1");
	strcpy(app_cfg.depend_name, "ip_camera");
	strcpy(app_cfg.cmd, "opkg install --force-depends ffmpeg");
	strcpy(app_cfg.check_cmd, "opkg list-installed | grep \"ffmpeg\"");
	
	app_manager_send_package_info(var->session, &app_cfg);
}

static int ipc_push_video_streaming_check(ip_camera_var_t *var)
{
    int ret = 0;
    char buff[255] = {0};
    char *string = NULL;
	
    snprintf(buff, sizeof(buff), "pgrep ffmpeg");
    ret = system_reply(buff, &string);
	dy_syslog(LOG_DEBUG, "ret %d string %p", ret, string);
    if (ret == 0)
    {
        if (!string)return 0;
		dy_syslog(LOG_DEBUG, "string:%s %d", string, strlen(string));
		if(strlen(string))
			return ret = 1;
        free(string);
		return ret;
    }
    return 0;
}

int ipc_push_video_streaming(ip_camera_var_t *var, pp_real_time_data_t *real_data, ip_camera_config_t *ip_camera_cfg)
{
	char server_url[256] = {0};
	char rtsp_url[256] = {0};
	char replace_buf[256] = {0};
	int streamCnt = 1;
	char *buff = NULL;
	
	cJSON *jparam = cJSON_Parse(real_data->data);
    if (!jparam)
    {
        dy_syslog(LOG_WARNING, "json rsData %s error!!!", real_data->data);
        return -1;
    }

	GET_JSON_VALUE_STRING(jparam, "serverUrl", server_url);

	cJSON *jrtsp = cJSON_Parse(ip_camera_cfg->camera_cfg.rtsp_url_local);
    if (!jrtsp)
    {
        dy_syslog(LOG_WARNING, "json rtsp_url_local %s error!!!", ip_camera_cfg->camera_cfg.rtsp_url_local);
        return -1;
    }

	GET_JSON_VALUE_STRING(jrtsp, "rtspUrl", rtsp_url);
	GET_JSON_VALUE_INT(jrtsp, "streamCnt", streamCnt);
	if(streamCnt > 3)
		streamCnt = 3;
	
	//ffmpeg -nostdin -i "rtsp://admin:a12345678@192.168.0.110:554/cam/realmonitor?channel=1&subtype=0&unicast=true" -vcodec copy -acodec copy -f flv "rtmp://10.3.1.130:1935/live/lnxall" &
	buff = calloc(512, 1);
	snprintf(buff, 512, "ffmpeg -rtsp_transport tcp -nostdin -i \"%s\" -vcodec copy -acodec copy -f flv \"%s\" 2>&1 | logger -t 'ffmpeg' & ", rtsp_url, server_url);

	char *dest = NULL;
	if(strstr(buff, "&subtype=0"))
	{
		snprintf(replace_buf, sizeof(replace_buf), "&subtype=%d", streamCnt-1);//"&subtype=1"
		dest = strreplace(dest, buff, "&subtype=0", replace_buf, 200);
	}
	else
	{
		snprintf(replace_buf, sizeof(replace_buf), "/10%d?", streamCnt);//"/102?"
		dest = strreplace(dest, buff, "/101?", replace_buf, 200);
	}

	dy_syslog(LOG_DEBUG, "buff %p, dest %p", buff, dest);
	if(dest && strlen(dest))
	{
		dy_syslog(LOG_DEBUG, "dest %s", dest);
		system(dest);
		free(dest);
	}
	else
	{
		dy_syslog(LOG_DEBUG, "buff %s", buff);
		system(buff);
		free(buff);
	}
	
    return 0;
}

int ipc_stop_video_streaming(ip_camera_var_t *var)
{
	char buff[128] = {0};
	
	strcpy(buff, "killall -15 ffmpeg");
	dy_syslog(LOG_DEBUG, "buff %s", buff);
	system(buff);
	system(buff);	

	/*int ret = -1;
    char *string = NULL;
    ret = system_reply(buff, &string);
	dy_syslog(LOG_DEBUG, "buff %s ret %d string %p", buff,ret, string);
    if (ret == 0)
    {
        if (!string)return 0;
		dy_syslog(LOG_DEBUG, "string:%s %d", string, strlen(string));
        free(string);
		return 0;
    }
    return 1;*/
}

static void ipc_data_reply(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, pp_real_time_data_t *real_data, char *result_data, int len)
{
	tag_table_t ptag = {0};
	tag_table_t ptag_post = {0};
					
	strcpy(ptag.sn, real_data->sn);
	ptag.mi = real_data->mi;		
	strncpy(ptag.identifier, real_data->src_identifier, strlen(real_data->src_identifier));
	ptag.report_period = 0;
	ptag.data_type = DATA_TYPE_SERVICE;
	ptag.tag_node = calloc((len)+1, 1);
	memcpy(ptag.tag_node, result_data, len);
	ptag.time = time(NULL);

	memcpy(&ptag_post, &ptag, sizeof(tag_table_t));
	strcpy(ptag_post.identifier, "post");
	ptag_post.data_type = DATA_TYPE_PROPERTY;
	ptag_post.tag_node = calloc((len)+1, 1);
	memcpy(ptag_post.tag_node, result_data, len);

	dy_syslog(LOG_DEBUG, "parse result_data:%s post:%s", ptag.tag_node, ptag_post.tag_node);
    if (ptag.tag_node != NULL)
    {
		ptag.port = real_data->port;
        pp_send_tag_data(var->session, &ptag);
        free(ptag.tag_node);
    }
    if (ptag_post.tag_node != NULL)
    {
		ptag_post.port = real_data->port;
        pp_send_tag_data(var->session, &ptag_post);
        free(ptag_post.tag_node);
    }
}

int ipc_link(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, encode_info_t *encode_info, char *result_data, int *len)
{
	if(var->send_package_cnt++ < 1)
		update_depend_package_info(var);
	var->init = 1;
	if((ip_camera_cfg->python == NULL || ip_camera_cfg->python->inited == 0) && strlen(ip_camera_cfg->camera_cfg.user) && strlen(ip_camera_cfg->camera_cfg.user))
	{
		dy_syslog(LOG_DEBUG, "---11 sn:%s", ip_camera_cfg->camera_cfg.sn);
		if(load_script_python_module(ip_camera_cfg, IP_CAMERA_SCRIPT) == 0)
		{
			encode_info_t tmp_info = {0};
			char *tmp_data = calloc(MAXBUF, 1);
			int tmp_len = 0;
			exec_init_cmd_script(var, ip_camera_cfg, &tmp_info, tmp_data, &tmp_len);
			if(encode_info)
				memcpy(encode_info, &tmp_info, sizeof(encode_info_t));
			if(result_data)
				memcpy(result_data, tmp_data, tmp_len);
			if(len)
				*len = tmp_len;
			
			if(ip_camera_cfg->python->inited == 0 && tmp_len)
			{
				if(ip_camera_cfg->camera_cfg.init_info)
				{
					free(ip_camera_cfg->camera_cfg.init_info);
					ip_camera_cfg->camera_cfg.init_info = NULL;
				}
				ip_camera_cfg->camera_cfg.init_info = calloc(tmp_len+1, 1);
				memcpy(ip_camera_cfg->camera_cfg.init_info, tmp_data, tmp_len);
			}
			free(tmp_data);
		}
		dy_syslog(LOG_DEBUG, "---22 sn:%s", ip_camera_cfg->camera_cfg.sn);
	}
	var->init = 0;
}

static int ipc_node_config_ctrl(ip_camera_var_t *var, pp_real_time_data_t *real_data, ip_camera_config_t *ip_camera_cfg)
{
	int i;
	int ret = 0;
	camera_config_t camera_cfg = {0};
	
	cJSON *node = cJSON_Parse(real_data->data);
    if (node)
    {
		GET_JSON_VALUE_STRING(node, "sn", camera_cfg.sn);
		GET_JSON_VALUE_STRING(node, "user", camera_cfg.user);
		GET_JSON_VALUE_STRING(node, "password", camera_cfg.password);
		//如用户名密码相等，则直接跳过
		if(ip_camera_cfg && strcmp(ip_camera_cfg->camera_cfg.user, camera_cfg.user) == 0 && strcmp(ip_camera_cfg->camera_cfg.password, camera_cfg.password) == 0)
		{
			ret = 1;
			goto __config_flag;
		}
		//获取ip_addr，port			
		for(i=0; i<var->nodes_cfg_table->node_cnt; i++)
		{
			if (strcmp(var->nodes_cfg_table->node[i].sn, camera_cfg.sn) == 0)
			{
				//更新配置
				strncpy(camera_cfg.ip_addr, var->nodes_cfg_table->node[i].tcp_ip_addr, sizeof(camera_cfg.ip_addr));
				camera_cfg.port = var->nodes_cfg_table->node[i].tcp_port;
				if(ip_camera_cfg)
				{
					strcpy(ip_camera_cfg->camera_cfg.user, camera_cfg.user);
					strcpy(ip_camera_cfg->camera_cfg.password, camera_cfg.password);
					ipc_update_node_config(var, IP_CAMERA_CFG, &camera_cfg, 0);
				}
				else
				{
					ipc_add_node_config(var, IP_CAMERA_CFG, &camera_cfg);
				}
				break;
			}
		}
    }
	else
    {
        dy_syslog(LOG_WARNING, "json rsData %s error!!!", real_data->data);
    }

__config_flag:
	cJSON_Delete(node);
	return ret;
}

static int ip_camera_status_update(ip_camera_var_t *var, ip_camera_config_t *ip_camera_cfg, int status)
{
	pp_real_time_data_t real_data = {0};

	strcpy(real_data.sn, ip_camera_cfg->camera_cfg.sn);
	strcpy(real_data.src_identifier, "StatusUpdate");
	
	cJSON *jtag = cJSON_CreateObject();
	cJSON_AddNumberToObject(jtag, "status", status);
	char *tag = cJSON_PrintUnformatted(jtag);			
	ipc_data_reply(var, ip_camera_cfg, &real_data, tag, strlen(tag));
	
	free(tag);
	cJSON_Delete(jtag);
}

static int ip_camera_heart_beat(ip_camera_var_t *var)
{
	TIMER_CONFIRM(var->heartbeat_timer);
	
	ip_camera_config_t *ip_camera_cfg = NULL;
	list_for_each_entry(ip_camera_cfg, &var->config_list, list)
	{
		int status = 0;
		dy_syslog(LOG_DEBUG, "sn:%s", ip_camera_cfg->camera_cfg.sn);
		
		//ipc_link(var, ip_camera_cfg, NULL, NULL, NULL);
		if(ip_camera_cfg->python->inited == 1)
		{
			encode_info_t tmp_info = {0};
			
			status = ipc_get_stream_uri_script(var, ip_camera_cfg, &tmp_info);			
			//ip_camera_status_update(var, ip_camera_cfg, status?0:1);
		}
			
	}

    return 0;
}

static int ip_camera_push_video_timer(ip_camera_var_t *var)
{
    int ret = 1;
	time_t now = time(NULL);

	TIMER_CONFIRM(var->push_video_timer);
	
	ip_camera_config_t *ip_camera_cfg = NULL;
	list_for_each_entry(ip_camera_cfg, &var->config_list, list)
	{
		if(ip_camera_cfg->push_video_flag && now >= ip_camera_cfg->last_push + 300)
		{
			ip_camera_cfg->push_video_flag = 0;
			ipc_stop_video_streaming(var);
		}		
	}

    return 0;
}


static void ip_camera_loop(ip_camera_var_t *var)
{
    int ret = -1, maxfd;
    fd_set  rset;
    struct timeval timeout;

    while (1)
    {
        SELECT_INIT();
        SELECT_ADD_FD(var->heartbeat_timer);
		SELECT_ADD_FD(var->push_video_timer);
        timeout.tv_usec = 0;
        timeout.tv_sec = 10;
        ret = select(maxfd + 1, &rset, 0, 0, &timeout);
        if (ret < 0)
        {
            printf("errno %d\n", errno);
            if (errno == EINTR)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        else if (ret == 0)
        {
        }
        else
        {
            if (var->heartbeat_timer > 0 && FD_ISSET(var->heartbeat_timer, &rset))
            {
                FD_CLR(var->heartbeat_timer, &rset);
                ip_camera_heart_beat(var);
            }
			if (var->push_video_timer > 0 && FD_ISSET(var->push_video_timer, &rset))
            {
                FD_CLR(var->push_video_timer, &rset);
                ip_camera_push_video_timer(var);
            }
        }
    }
}

static void ip_camera_subscribe_all(ip_camera_var_t *var)
{
    ipc_session_t *ipc_session = var->session;
    char topic[TOPIC_MAX_LEN] = {0};
	int i = 0;

	for (i = 0; i < ARRAY_SIZE(ports); i++)
    {
        snprintf(topic, TOPIC_MAX_LEN, "ipc/+/%s/device/+/data/%s", port_enum2char(ports[i]), TOPIC_SEND_RGLT_SIGNAL_RAW_DATA);
        ipc_session_subscribe(ipc_session, topic);
    }
}

void ip_camera_msg_ctrl(ip_camera_var_t *var, pp_real_time_data_t *real_data)
{
	int find = 0;
	int ret;	
	ip_camera_config_t *ip_camera_cfg = NULL;

ipc_cmd_ctrl:
	ip_camera_cfg = NULL;
	list_for_each_entry(ip_camera_cfg, &var->config_list, list)
	{
		//检索ipc设备
		dy_syslog(LOG_DEBUG, "%s %d sn:%s %s", __FUNCTION__,__LINE__,real_data->sn, ip_camera_cfg->camera_cfg.sn);
		if(strcmp(real_data->sn, ip_camera_cfg->camera_cfg.sn) == 0)
		{
			int len = 0;
			int ret = 0;
			find = 1;
			encode_info_t encode_info = {0};
			char *result_data = calloc(MAXBUF, 1);
			
			dy_syslog(LOG_DEBUG, "%s %d src_identifier:%s", __FUNCTION__,__LINE__,real_data->src_identifier);
			//如摄像机正在初始化
			if(var->init == 1)
			{
				//之前已执行过初始化，返回原来的错误信息。否则，返回正在初始化
				if(ip_camera_cfg->camera_cfg.init_info)
				{
					len = strlen(ip_camera_cfg->camera_cfg.init_info);
					encode_info.stream_direction = 1;
					memcpy(result_data, ip_camera_cfg->camera_cfg.init_info, strlen(ip_camera_cfg->camera_cfg.init_info));
				}
				else
				{
					generate_common_repay_package(&encode_info, result_data, &len, "Initializing");
					free(result_data);
					return;
				}
			}
			else if(strcmp(real_data->src_identifier, "InitIPCamera") == 0)
			{
				//已初始化，则返回OK。如用户名密码改了，需要更新配置。重新初始化
				//如已连接成功，则不会修改用户名，密码
				if(!ip_camera_cfg->python || ip_camera_cfg->python->inited == 0)
				{
					//exec_init_cmd_script(var, ip_camera_cfg, &encode_info);
					ipc_node_config_ctrl(var, real_data, ip_camera_cfg);
					ipc_link(var, ip_camera_cfg, &encode_info, result_data, &len);
				}
				else
				{
					generate_common_repay_package(&encode_info, result_data, &len, "OK");
				}
			}
			else if(strcmp(real_data->src_identifier, "PushVideoStreaming") == 0)
			{
				//已经在推流，再刷新时间。如果源URL未准备好，则返回ERROR
				if(ip_camera_cfg->push_video_flag == 1 && ipc_push_video_streaming_check(var) == 0)
				{
					ip_camera_cfg->push_video_flag = 0;
				}
				
				if(ip_camera_cfg->push_video_flag == 0 && ipc_push_video_streaming(var, real_data, ip_camera_cfg) == 0)
				{
					ip_camera_cfg->push_video_flag = 1;
					generate_common_repay_package(&encode_info, result_data, &len, "OK");
				}
				else
					generate_common_repay_package(&encode_info, result_data, &len, ip_camera_cfg->push_video_flag?"OK":"ERROR");
				ip_camera_cfg->last_push = time(NULL);
			}
			else if(strcmp(real_data->src_identifier, "StopVideoStreaming") == 0)
			{
				ipc_stop_video_streaming(var);
				ip_camera_cfg->push_video_flag = 0;
				generate_common_repay_package(&encode_info, result_data, &len, "OK");
			}
			else
				//执行python脚本
				ret = exec_encode_script_python(var, ip_camera_cfg->python, real_data->data, real_data->len, result_data, &len, &encode_info);

			//数据上报data_report
			if(encode_info.stream_direction && len > 0)
			{
				dy_syslog(LOG_DEBUG, "result_data:%s len %d", result_data, len);
				if(ret == 0 && strcmp(real_data->src_identifier, "GetStreamUri") == 0)
					ipc_get_stream_url(var, ip_camera_cfg, result_data);
				
				ipc_data_reply(var, ip_camera_cfg, real_data, result_data, strlen(result_data));
			}
			else
				ipc_link(var, ip_camera_cfg, NULL, NULL, NULL);//脚本执行异常，重连摄像机

			free(result_data);
			break;
		}
	}

	if(find == 0 && strcmp(real_data->src_identifier, "InitIPCamera") == 0)
	{
		ipc_node_config_ctrl(var, real_data, NULL);
		find = 1;
		goto ipc_cmd_ctrl;
	}
}

static int ip_camera_mqtt_handle_recv_msg(void *obj, ipc_msg_t *mqtt_msg)
{
    ip_camera_var_t *var = (ip_camera_var_t *)obj;

    dy_syslog(LOG_DEBUG, " MQTT client: received MQTT topic:%s payload length:%d",
              mqtt_msg->topic, mqtt_msg->payloadLen);
    if (strstr(mqtt_msg->topic, TOPIC_SEND_RGLT_SIGNAL_RAW_DATA))
    {
    	int ret = 0;
    	pp_real_time_data_t real_data = {0};

	    ret = get_rt_data_from_json_str(&real_data, mqtt_msg->payload);
	    if (ret < 0)
	    {
	        dy_syslog(LOG_ERR, "parse real data structure failed");
	    }

		dy_syslog(LOG_INFO, "data %s len:%d", real_data.data,real_data.len);

		ip_camera_msg_ctrl(var, &real_data);
		
		if (real_data.data)
	    {
	        free(real_data.data);
	    }
    }
}

// 建立与内部broker之间的MQTT连接
static int ip_camera_mqtt_client_init(ip_camera_var_t *var)
{
    char clientId[MAX_CLIENT_ID_LEN] = {0};

    snprintf(clientId, MAX_CLIENT_ID_LEN, "%s", var->proc_name);
    var->session = ipc_session_new(clientId, (void*)var, IPC_DEFAULT);
    if (var->session == NULL) return -1;

    ipc_session_set_callbacks(var->session, ip_camera_mqtt_handle_recv_msg, NULL);
    ip_camera_subscribe_all(var);
    ipc_session_start(var->session);
}

static int ip_camera_init(ip_camera_var_t *var)
{	
	INIT_LIST_HEAD(&var->config_list);
	
    get_board_sn(var->sn_str);
    get_process_name(var->proc_name);

	system("killall -15 ffmpeg");
	system("killall -15 ffmpeg");

    if (load_nodes_cfg(&var->nodes_cfg_table, NODES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load nodes cfg fail");
    }
	if (load_templates_cfg(&var->template_table, TEMPLATES_CFG_PATH) == -1)
    {
        dy_syslog(LOG_ERR, "load template cfg fail");
    }
	
    if (access(IP_CAMERA_CFG, F_OK) != -1)
    {
        ipc_load_node_config(var, IP_CAMERA_CFG);
    }

	ip_camera_mqtt_client_init(var);

	ip_camera_config_t *ip_camera_cfg = NULL;
	ip_camera_config_t *tmp = NULL;
	list_for_each_entry_safe(ip_camera_cfg, tmp, &var->config_list, list)
	{
		dy_syslog(LOG_DEBUG, "ip_addr %s %d", ip_camera_cfg->camera_cfg.ip_addr,ip_camera_cfg->camera_cfg.port);
		int i=0;
		int find=0;
		for(i=0; i<var->nodes_cfg_table->node_cnt; i++)
		{
			if(strcmp(ip_camera_cfg->camera_cfg.sn, var->nodes_cfg_table->node[i].sn) == 0)
			{
				find = 1;
				if(strcmp(ip_camera_cfg->camera_cfg.ip_addr, var->nodes_cfg_table->node[i].tcp_ip_addr) || 
					ip_camera_cfg->camera_cfg.port != var->nodes_cfg_table->node[i].tcp_port)
				{
					strcpy(ip_camera_cfg->camera_cfg.ip_addr, var->nodes_cfg_table->node[i].tcp_ip_addr);
					ip_camera_cfg->camera_cfg.port = var->nodes_cfg_table->node[i].tcp_port;
					ipc_update_node_config(var, IP_CAMERA_CFG, &ip_camera_cfg->camera_cfg, 0);
				}
				break;
			}
		}

		if(find == 0)
		{
			ipc_update_node_config(var, IP_CAMERA_CFG, &ip_camera_cfg->camera_cfg, 1);
			list_del(&ip_camera_cfg->list);
            free(ip_camera_cfg);
			continue;
		}

		ipc_link(var, ip_camera_cfg, NULL, NULL, NULL);		
		var->node_cnt++;
	}

    var->heartbeat_timer = my_timer_create();
    if (var->heartbeat_timer > 0)
    {
    	my_timer_set(var->heartbeat_timer, 3, 300000);
    }

	var->push_video_timer = my_timer_create();
    if (var->push_video_timer > 0)
    {
    	my_timer_set(var->push_video_timer, 3, 3000);
    }

	update_depend_package_info(var);

    dy_syslog(LOG_INFO, "init done, board SN:%s", var->sn_str);

    return 0;
}

int main(int argc, char *argv[])
{
    ip_camera_var_t *var = &gvar;

    memset(var, 0, sizeof(ip_camera_var_t));

    ip_camera_init(var);
    ip_camera_loop(var);

    return 0;
}
