#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"


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



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

typedef struct{
	int state;
	vpCFGInfo cfg_info;
	int updateFlag;
}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){
		printf("open err.\n");
		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){
		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);
}

void kk_vp_set_updateFlag(int flag)
{
	vp_mag.updateFlag = (flag!=0)?1:0;
}



void kk_vp_config_file_update(void)
{
	if(vp_mag.updateFlag==0){
		return ;
	}
	
	if(vp_mag.state == UPDATING_8009_CONFIG_FILE_INFO||
		vp_mag.state == START_8009_CONFIG_FILE_UPDATE){
		kk_vp_set_state_machine(STOP_8009_CONFIG_FILE_UPDATE);
	}else{
		kk_vp_set_state_machine(START_8009_CONFIG_FILE_UPDATE);
	}
	
	kk_vp_set_updateFlag(0);
}

void kk_vp_set_state_machine(int state)
{
	if(vp_mag.state!=state){
		INFO_PRINT("[vp state machine]%d->%d\n",vp_mag.state,state);
		vp_mag.state = state;
	}
}

void kk_vp_get_config_file_version(int ver)
{
	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);
		kk_vp_set_updateFlag(1);
		printf("[%s][%d]update config file.\n",__FUNCTION__,__LINE__);
	}
}

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);
		kk_vp_set_state_machine(GET_8009_CONFIG_FILE_INFO);
	}else{
		kk_vp_set_updateFlag(1);
		printf("[%s][%d]update config file.\n",__FUNCTION__,__LINE__);
	}
}







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

	kk_vp_set_state_machine(UPDATING_8009_CONFIG_FILE_INFO);

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

		kk_vp_set_state_machine(UPDATING_8009_CONFIG_FILE_INFO);
		
		return 1;
	}
	return 0;
}



void kk_vp_manage_init(void)
{
	vp_scene_id_map_load();
	printf("[%s][%d]\n",__FUNCTION__,__LINE__);
	_vp_config_file_version_load(); 
	printf("[%s][%d]\n",__FUNCTION__,__LINE__);
	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)
	{
		kk_vp_config_file_update();
		
		switch(vp_mag.state){
			case GET_8009_SNAPSHOOT_STATE:
				kk_vp_get_8009_snapshoot();
				sleep(5);
				break;

			case SET_8009_SYSTEM:
				kk_vp_set_8009_system_time();
				sleep(5);
				break;

			case START_8009_CONFIG_FILE_UPDATE:
				
				kk_vp_config_file_update_start(vp_mag.cfg_info.next_ver);
				kk_vp_set_state_machine(UPDATING_8009_CONFIG_FILE_INFO);
				break;

			case UPDATING_8009_CONFIG_FILE_INFO:
				//debug_log(LOG_INFO,"updating...\n");
				sleep(1);
				//todo :超时取消
				break;

			case STOP_8009_CONFIG_FILE_UPDATE:
				kk_vp_config_file_update_stop(vp_mag.cfg_info.f_ver);
				if(vp_mag.updateFlag==1){
					kk_vp_set_state_machine(UPDATING_8009_CONFIG_FILE_INFO);
				}else{
					kk_vp_set_state_machine(GET_8009_CONFIG_FILE_INFO);
				}
				sleep(3);
				break;

			case GET_8009_CONFIG_FILE_INFO:
				kk_vp_get_config_file_info();
				sleep(15);
				break;
				
			default:
			break;
		}
		usleep(50*1000);
	}
	ERROR_PRINT("[%s]thread end...\n",__FUNCTION__);
}


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_FOCUS_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_FOCUS_LEVEL,"serialDev=%s\n",serialDev);
}

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

	pthread_t uart_tid = 0;
	pthread_t mag_tid = 0;
		
	pthread_attr_t attr;
	pthread_attr_init(&attr);

	kk_voice_panel_uart_dev_chose(argc,argv);

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

	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(&tid3, NULL, kk_voice_panel_333, NULL))!= 0 ) {
		ERROR_PRINT("pthread_create kk_voice_panel fail\n");
		return -4;
	}*/


	return 0;
}
































