#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include<getopt.h>

#include "kk_log.h"
#include "kk_lan_voice_panel.h"
#include "kk_voice_panel_cfg.h"
#include "kk_voice_panel_handle.h"
#include "kk_lan_debug.h"
#include "Serial.h"
#include "uart_proto.h"

#ifdef VOICE_SUPPORT
static pthread_mutex_t v_mux;





extern int serial_fd;



static void *kk_vp_uart_thread(void *arg)
{
	fd_set rd;
	int nFlag;
	struct timeval tval = {2,0};

	int count = 0;
	unsigned char data_buf[512];
	teSerial_Status ret = E_SERIAL_ERROR;

	INFO_PRINT("[%s] start...\n",__FUNCTION__);
	
	eSerial_start();

	while (1)
	{
		while(serial_fd<0){
			eSerial_start();
			sleep(1);
		}
		
		FD_ZERO(&rd);
		FD_SET(serial_fd,&rd);

		nFlag = select(serial_fd + 1, &rd, NULL, NULL, &tval);

		if(0 > nFlag)
		{
			ERROR_PRINT("uartRecv():select error !\n");
			ERROR_PRINT("uartRecv errno = %d", errno);
			usleep( 100000 );
		}
		else if(0 == nFlag)
		{
			usleep( 100000 );
		}
		else
		{
			if(FD_ISSET(serial_fd, &rd))
			{
		
				ret = eSerial_Read(&data_buf[count]);
				
				if(ret == E_SERIAL_OK)
				{
					if(get_uart_frame((uint8_t *)data_buf,1))
					{
						uart_frame_handle();
					}
				}
				else if(ret == E_SERIAL_FD_ERROR)
				{
					eSerial_start();
				}
			}
		}
	}

	ERROR_PRINT("[%s]thread end...\n",__FUNCTION__);
	return 0;
}



typedef struct {
	int next_ver;
	int f_ver;
	int f_size;
	int crc32;
}vpCFGInfo;

typedef struct{
	int set_time_flag;
	int get_ver_flag;

	int ota_update_flag;
	int file_update_flag;

	vpCFGInfo cfg_info;

}VP_MANAGE;


VP_MANAGE vp_mag;

char *vp_file_load(const char *path)
{
	char *buff = NULL;
	char *pRead = NULL;
	int t_len = 0;
	int remain = 0;
	int r_len = 0;

	FILE *fp = NULL;
	int size = 0;

	INFO_PRINT("[%s]vp load file(%s)\n",__FUNCTION__,path);
	
	fp = fopen (path,"r");
	if(fp==NULL){
		debug_log(LOG_WARNING_LEVEL,"[%s]fopen err!\n",path);
		return NULL;
	}
	
	fseek (fp, 0, SEEK_END);
	size=ftell(fp);
	printf("size=%d\n",size);

	fseek (fp, 0, SEEK_SET);

	buff = malloc(size+1);
	memset(buff,0,size+1);
	pRead = buff;
	remain = size;
	
	while(remain>0){
		r_len = fread(pRead, 1, size, fp);
		
		if(remain>=r_len){
			remain -= r_len;
			pRead+=r_len;
		}else{
			remain = 0;
			pRead[size] = '\0';
		}
	}

	fclose(fp);

	return buff;
}

static int _vp_config_file_version_load(void)
{
	cJSON *json = NULL;
	cJSON *version = NULL;
	char *pFile = vp_file_load(VP_CONFIG_FILE);

	if(pFile==NULL){
		printf("[%s][%d]\n",__FUNCTION__,__LINE__);
		return 0;
	}

	if((json = cJSON_Parse(pFile))==NULL){
		free(pFile);
		return 0;
	}

	version = cJSON_GetObjectItem(json,"version");
	if(version!=NULL &&version->type==cJSON_Number){

		if(version->valueint<=0){
			vp_mag.cfg_info.f_ver = 0;
			vp_mag.cfg_info.next_ver = 0;
		}else{
			vp_mag.cfg_info.f_ver = version->valueint;
			vp_mag.cfg_info.next_ver = version->valueint;
		}
		printf("[vp load config version]%d\n",vp_mag.cfg_info.f_ver);
	}

	cJSON_Delete(json);
	free(pFile);
	return 1;
}



void kk_voice_update_config_file(void)
{
	kk_vp_config_file_update_stop(vp_mag.cfg_info.f_ver);

	kk_vp_config_file_update_start(vp_mag.cfg_info.next_ver);

	vp_mag.file_update_flag = 1;
}





int kk_vp_get_config_file_version(void)
{
	return vp_mag.cfg_info.next_ver;
}

void kk_vp_set_config_file_version(int ver)
{
	vp_mag.cfg_info.f_ver = (vp_mag.cfg_info.f_ver>ver)?vp_mag.cfg_info.f_ver:ver;

	printf("[cfg ver]File Version=%08x\n",vp_mag.cfg_info.f_ver);
}

void kk_vp_cfg_info_set(uint32_t f_ver,uint32_t f_size,uint32_t crc32)
{
	vp_mag.cfg_info.next_ver = f_ver;
	vp_mag.cfg_info.f_ver = f_ver;
	vp_mag.cfg_info.f_size = f_size;
	vp_mag.cfg_info.crc32 = crc32;
	printf("[set cfg info]File Version=%08x,File Size=%08x,CRC32=%08x\n",f_ver,f_size,crc32);
}

void kk_vp_cfg_info_check(uint32_t f_ver,uint32_t f_size,uint32_t crc32)
{
	if(vp_mag.cfg_info.f_ver!=f_ver ||
		vp_mag.cfg_info.crc32!=crc32){
		
		printf("[VP]File Version=%08x,File Size=%08x,CRC32=%08x\n",f_ver,f_size,crc32);
		printf("[LAN]File Version=%08x,File Size=%08x,CRC32=%08x\n",vp_mag.cfg_info.f_ver,vp_mag.cfg_info.f_size,vp_mag.cfg_info.crc32);

		debug_log(LOG_EMERG_LEVEL,"-------------------->start update config file<------------------\n");
		kk_voice_update_config_file();
	}
}

void kk_vp_update_result_check(uint8_t status,uint32_t f_ver)
{
	if(status==0 && (vp_mag.cfg_info.f_ver==f_ver) ){
		vp_mag.cfg_info.next_ver=vp_mag.cfg_info.f_ver+1;
		printf("[cfg ver]File Version=%08x\n",vp_mag.cfg_info.f_ver);
	}else{
		debug_log(LOG_EMERG_LEVEL,"-------------------->start update config file again<------------------\n");
		//kk_voice_update_config_file();
	}
}

void kk_voice_reset_ver_flag(void)
{
	vp_mag.get_ver_flag = 0;
	vp_mag.ota_update_flag = 0;
}
void kk_voice_set_time_flag(void)
{
	vp_mag.set_time_flag = 1;
}
void kk_get_voice_version(void)
{



	debug_log(LOG_INFO_LEVEL,"mark!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
	vp_mag.get_ver_flag = 1;
}






int kk_vp_config_file_info_check(int f_ver,int f_size,int crc32)
{


	if(vp_mag.cfg_info.f_ver==f_ver &&
		vp_mag.cfg_info.f_size==f_size &&
		vp_mag.cfg_info.crc32==crc32){

	
		return 1;
	}
	return 0;
}
int kk_voice_exit_factory_mode(void)
{
    uint8_t data[1] = {1};
    vp_send_data_build(OPCODE_COMPLETED_TEST_OP,sizeof(data),data);
    return 1;
}
void kk_voice_ota_mtu_set(uint16_t mtu)
{
	uint8_t res[3] = {0};

	res[0] = 0xff;
	res[1] = (mtu>>8)&0xff;
	res[2] = mtu&0xff;
	INFO_PRINT("[set] MTU OTA SIZE = %d\n",mtu);
	vp_send_data_build(OPCODE_VOICE_SWITCH,sizeof(res),res);
}

void kk_vp_manage_init(void)
{
	kk_voice_ota_mtu_set(KK_VOICE_OTA_MTU);

	vp_scene_id_map_load();
	_vp_config_file_version_load(); 
	vp_mag.cfg_info.f_size = _vp_get_cfg_file_size();
	vp_mag.cfg_info.crc32 = _vp_get_cfg_file_crc32();
}

void *kk_vp_manage_thread(void *arg)
{
	INFO_PRINT("[%s] start...\n",__FUNCTION__);

	kk_vp_manage_init();

	while (1)
	{
		if(vp_mag.file_update_flag==1||vp_mag.ota_update_flag==1){
			sleep(1);
			continue;
		}
		kk_vp_get_config_file_info();
		sleep(60*30);
	}
	
	ERROR_PRINT("[%s]thread end...\n",__FUNCTION__);
	return 0;
}

static void *kk_voice_ctrl_status_thread(void *arg)
{
	debug_log(LOG_INFO_LEVEL,"[%s] start...\n",__FUNCTION__);

	usleep(100*1000);
	#define SET_8009_TIME						(60*60)


	static time_t set_time;

	while (1)
	{
		int delay = 1;
		time_t curTime = time(NULL);

		if(vp_mag.get_ver_flag == 0){
			debug_log(LOG_DEBUG_LEVEL,"get 8009 snapshoot\n");
			kk_vp_get_8009_snapshoot();
			sleep(2);
			continue;
		}

		if(vp_mag.set_time_flag == 0){
			struct tm *c = localtime(&curTime);
			if(c->tm_year!=70){
				set_time = curTime;
				debug_log(LOG_NOTICE_LEVEL,"set 8009 system time\n");
				kk_vp_set_8009_system_time();
			}
			sleep(2);
			continue;
		}
		
		if(vp_mag.file_update_flag==1||vp_mag.ota_update_flag==1){
			sleep(1);
			continue;
		}


		if((curTime-set_time)>=SET_8009_TIME){
			set_time = curTime;
			debug_log(LOG_NOTICE_LEVEL,"[timing %ds] set 8009 system time\n",SET_8009_TIME);
			kk_vp_set_8009_system_time();
		}


		if(delay){
			usleep(100*1000);
		}
	}

	return 0;
}




void kk_voice_panel_uart_dev_chose(int argc, char* argv[])
{
	int flag = 0;
	int opt;
	int option_index = 0;
	char *string = "";

	static struct option long_options[] =
	{
		{"uart", optional_argument,NULL, 0xAA5555AA},
		{NULL,     0,                      NULL, 0},
	};

	debug_log(LOG_CRIT_LEVEL,"kk_voice_panel_uart_dev_chose\n");
	while((opt =getopt_long_only(argc,argv,string,long_options,&option_index))!= -1)
	{
		if(opt==0xAA5555AA){
			memset(serialDev,0,sizeof(serialDev));
			snprintf(serialDev,sizeof(serialDev),"%s",optarg);
			flag =1;
			break;
		}
	}
	if(flag==0){
		memset(serialDev,0,sizeof(serialDev));
		snprintf(serialDev,sizeof(serialDev),"%s",SERIAL_NAME);
	}
	
	debug_log(LOG_CRIT_LEVEL,"serialDev=%s\n",serialDev);
}


static int kk_vp_cfg_file_dir_create(void){
	char cmd[128] = {0};

	snprintf(cmd,sizeof(cmd),"mkdir -p %s",VP_VP_CONFIG_FILE_DIR);

	return system(cmd);
}




static pthread_mutex_t voice_uart_mutex;
void voice_uart_lock(void)
{
	pthread_mutex_lock(&voice_uart_mutex);
} 

void voice_uart_unlock(void)
{
	pthread_mutex_unlock(&voice_uart_mutex);
} 

void kk_voice_ota_start(char *in)
{
	char file[128] = {0};
	char *ptr = strstr(in,"_");
	if (ptr!=NULL) {
		snprintf(file,sizeof(file),"/data/OTA/%s", ptr+1);
	}else {
		snprintf(file, sizeof(file), "/data/OTA/%s", in);
	}
	debug_log(LOG_WARNING_LEVEL,"%s.\n",file);
	kk_vp_ota_file_update_start(file);
}



int kk_voice_panel_init(int argc, char* argv[])
{
	size_t s = 1500;

	pthread_t uart_tid = 0;
	pthread_t mag_tid = 0;
	pthread_t t_tid = 0;

	
	pthread_attr_t attr;
	pthread_attr_init(&attr);

	kk_voice_panel_uart_dev_chose(argc,argv);

	kk_vp_cfg_file_dir_create();

	pthread_attr_setstacksize(&attr, s);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	kk_vp_ac_mutex_init();

	if (pthread_mutex_init(&v_mux, NULL) != 0) {
		pthread_attr_destroy(&attr);
		ERROR_PRINT("pthread_mutex_init v_mux fail.\n");
		return -1;
	}
	
	if((pthread_create(&uart_tid, &attr, kk_vp_uart_thread, NULL))!= 0 ) {
		pthread_attr_destroy(&attr);
		ERROR_PRINT("pthread_create kk_voice_panel fail\n");
		return -2;
	}

	if((pthread_create(&mag_tid, NULL, kk_vp_manage_thread, NULL))!= 0 ) {
		ERROR_PRINT("pthread_create kk_voice_panel fail\n");
		return -3;
	}

	if((pthread_create(&t_tid, NULL, kk_voice_ctrl_status_thread, NULL))!= 0 ) {
		return -4;
	}
	
	return 0;
}
#endif































