#include "omc_cleaner.h"

static int table_mtn_timer();
static int file_mtn_timer();
static int table_maintain_proc(int cur_index);
static int file_maintain_proc(int cur_index);
static int check_table(int cur_index);
static int read_conffile();
static int parse_line(FILE *handle,char *line,int max_size);

tableMtnNodeList tbNodeList;
fileMtnNodeList fileNodeList;

DWORD PROC_HEARTBEAT_OID[12]={1,3,6,1,4,1,1373,2,4,10,4};
int PROC_HEARTBEAT_OIDLEN=11;
int sendHeartbeat();
int alterTableAutoIncrement();

int alterTableAutoIncrement()
{
	char alterTableList[32][64];
	int table_count=1;
	int i;
	
	MYSQL *dbConn;
	MYSQL_RES *res;
	char sqlstr[512];

	memset(alterTableList,0,sizeof(alterTableList));
	sprintf(alterTableList[0],"OMC_PUB.parameterComm");
	
	dbConn=mysql_conn("localhost","OMC_PUB");
	if(dbConn == NULL)
	{
	  logMessage("[ERR][alterTableAutoIncrement]:mysql_conn OMC_PUB");
		return 0;
	}
	
	for(i=0;i<table_count;i++)
	{
		sprintf(sqlstr,"select * from %s ",alterTableList[i]);
		res=mysql_getres(dbConn,sqlstr);
		if(res != NULL && mysql_num_rows(res) == 0)
		{
			sprintf(sqlstr,"alter table %s auto_increment=1 ",alterTableList[i]);
			mysql_getnores(dbConn,sqlstr);
		}
		if(res != NULL)
			mysql_free_result(res);
	}
	mysql_close(dbConn);
	return 1;
}

int omc_cleaner_init()
{
	logMessage("omcCleaner start......");
	
	debug_init(1);
	iptrans_init();
	snmp_init(4957);

	read_conffile();
	omc_task_init();
	alterTableAutoIncrement();
	return 1;
}

void omc_cleaner_timer()
{
	omc_task_timer();
	table_mtn_timer();
	file_mtn_timer();
}

int table_mtn_timer()
{
	switch(tbNodeList.state)
	{
	case MTN_STATE_IDLE:
		break;
	case MTN_STATE_INIT:
		logMessage("Start to maintain tables");
		tbNodeList.cur_index=0;
		tbNodeList.state=MTN_STATE_PROC;
		break;
	case MTN_STATE_PROC:
		table_maintain_proc(tbNodeList.cur_index);
		tbNodeList.cur_index++;
		if(tbNodeList.cur_index == tbNodeList.node_count)
			tbNodeList.state=MTN_STATE_FINISH;
		break;
	case MTN_STATE_FINISH:
		tbNodeList.state=MTN_STATE_IDLE;
		break;
	}
	return 1;
}

int file_mtn_timer()
{
	switch(fileNodeList.state)
	{
	case MTN_STATE_IDLE:
		break;
	case MTN_STATE_INIT:
		logMessage("Start to maintain files");
		fileNodeList.cur_index=0;
		fileNodeList.state=MTN_STATE_PROC;
		break;
	case MTN_STATE_PROC:
		file_maintain_proc(fileNodeList.cur_index);
		fileNodeList.cur_index++;
		if(fileNodeList.cur_index == fileNodeList.node_count)
			fileNodeList.state=MTN_STATE_FINISH;
		break;
	case MTN_STATE_FINISH:
		fileNodeList.state=MTN_STATE_IDLE;
		break;
	}
	return 1;
}

int table_maintain_proc(int cur_index)
{
	MYSQL *dbConn;
	MYSQL_RES *res;
	MYSQL_ROW row;
	char sqlstr[512];
	unsigned long delete_time;
	unsigned long record_count;
	
	if(!tbNodeList.node[cur_index].valid)
		return 0;
	
	dbConn=mysql_conn("localhost",tbNodeList.node[cur_index].database_name);
	if(dbConn == NULL)
	{
	  logMessage("[ERR][check_table]:mysql_conn %s",tbNodeList.node[cur_index].database_name);
		return 0;
	}
	
	
	
	if(tbNodeList.node[cur_index].keep_records > 0)
	{
		sprintf(sqlstr,"select count(*) from %s.%s",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name);
		res=mysql_getres(dbConn,sqlstr);
		if(res == NULL)
		{
			logMessage("Get record count fail from %s.%s",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name);
			mysql_close(dbConn);
			return 0;
		}
		row=mysql_fetch_row(res);
		if(row == NULL)
		{
			logMessage("Get record count fail from %s.%s",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name);
			mysql_free_result(res);
			mysql_close(dbConn);
			return 0;
		}
		record_count=strtoul(row[0],NULL,10);
		mysql_free_result(res);

		if(record_count > tbNodeList.node[cur_index].keep_records)
		{
			if(tbNodeList.node[cur_index].keep_seconds > 0)
			{
				delete_time=time(NULL)-tbNodeList.node[cur_index].keep_seconds;
				sprintf(sqlstr,"delete from %s.%s where UNIX_TIMESTAMP(%s) < %ld ",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name,tbNodeList.node[cur_index].time_fieldname,delete_time);
				mysql_getnores(dbConn,sqlstr);
				logMessage("%s, affected rows num=%d",sqlstr,mysql_affected_rows(dbConn));
			}
			/*
			sprintf(sqlstr,"delete from %s.%s order by %s LIMIT %ld",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name,tbNodeList.node[cur_index].time_fieldname,record_count - tbNodeList.node[cur_index].keep_records);
			mysql_getnores(dbConn,sqlstr);
			logMessage("%s, affected rows num=%d",sqlstr,mysql_affected_rows(dbConn));
		*/
		}
	}
	
	mysql_close(dbConn);
	
	return 1;
}

int file_maintain_proc(int cur_index)
{
	struct dirent* pDirEnt;
	DIR* dir;
	struct stat fileStat;
	char fullpathname[256];
	
	dir=opendir(fileNodeList.node[cur_index].directory);
	if(dir == NULL)
	{
		logMessage("Fail to open directory %s",fileNodeList.node[cur_index].directory);
		return 0;
	}
	
	while((pDirEnt = readdir(dir))!=NULL)
	{
		if(strstr(pDirEnt->d_name,fileNodeList.node[cur_index].keyword))
		{
			sprintf(fullpathname,"%s/%s",fileNodeList.node[cur_index].directory,pDirEnt->d_name);
			stat(fullpathname,&fileStat);
			if((time(NULL) - fileStat.st_mtime) > fileNodeList.node[cur_index].keep_seconds)
			{
				if(unlink(fullpathname) == 0)
					logMessage("Delete file %s successfully",fullpathname);
				else
					logMessage("Delete file %s fail",fullpathname);
			}
		}
	}
	closedir(dir);
	return 1;
}

int check_table(int cur_index)
{
	MYSQL *dbConn;
	MYSQL_RES *res;
	MYSQL_ROW row;
	char sqlstr[512];
	int tmpflag;
	
	dbConn=mysql_conn("localhost",tbNodeList.node[cur_index].database_name);
	if(dbConn == NULL)
	{
	  logMessage("[ERR][check_table]:mysql_conn %s",tbNodeList.node[cur_index].database_name);
	  tbNodeList.node[cur_index].valid=0;
		return 0;
	}
	
	//check database
	sprintf(sqlstr,"show databases");
	res=mysql_getres(dbConn,sqlstr);
	if(res == NULL)
	{
		logMessage("[ERR][check_table]:mysql_getres=%s",sqlstr);
	  tbNodeList.node[cur_index].valid=0;
	  mysql_close(dbConn);
		return 0;
	}
	tmpflag=0;
	while((row = mysql_fetch_row(res)) != NULL)
	{
		if(strstr(row[0],tbNodeList.node[cur_index].database_name))
		{
			tmpflag=1;
			break;
		}
	}
	if(!tmpflag)
	{
		logMessage("Database %s not exist",tbNodeList.node[cur_index].database_name);
	  tbNodeList.node[cur_index].valid=0;
	  mysql_free_result(res);
	  mysql_close(dbConn);
	  return 0;
	}
	mysql_free_result(res);
	
	//check table
	sprintf(sqlstr,"show tables from %s where Tables_in_%s = '%s' ",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name);
	res=mysql_getres(dbConn,sqlstr);
	if(res == NULL)
	{
		logMessage("[ERR][check_table]:mysql_getres=%s",sqlstr);
	  tbNodeList.node[cur_index].valid=0;
	  mysql_close(dbConn);
		return 0;
	}
	if(mysql_num_fields(res) == 0)
	{
		logMessage("Table %s not exist",tbNodeList.node[cur_index].table_name);
	  tbNodeList.node[cur_index].valid=0;
	  mysql_free_result(res);
	  mysql_close(dbConn);
	  return 0;
	}
	mysql_free_result(res);
	
	//check field
	sprintf(sqlstr,"show fields from %s.%s where Field = '%s' ",tbNodeList.node[cur_index].database_name,tbNodeList.node[cur_index].table_name,tbNodeList.node[cur_index].time_fieldname);
	res=mysql_getres(dbConn,sqlstr);
	if(res == NULL)
	{
		logMessage("[ERR][check_table]:mysql_getres=%s",sqlstr);
	  tbNodeList.node[cur_index].valid=0;
	  mysql_close(dbConn);
		return 0;
	}
	if(mysql_num_fields(res) == 0)
	{
		logMessage("Field %s not exist",tbNodeList.node[cur_index].time_fieldname);
	  tbNodeList.node[cur_index].valid=0;
	  mysql_free_result(res);
	  mysql_close(dbConn);
	  return 0;
	}
	mysql_free_result(res);
	mysql_close(dbConn);
	
	tbNodeList.node[cur_index].valid=1;
	return 1;
}

int sendHeartbeat()
{
	snmp_pdu pdu;
	snmp_addr addr;
	char proc_name[16];
	
	memset(proc_name,0,16);
	sprintf(proc_name,"omcCleaner");
	
	//pdu
	memset(&pdu,0,sizeof(snmp_pdu));
	pdu.pdu_type=7;
	pdu.request_id=0;
	sprintf(pdu.community,"public");
	pdu.var_num=1;
	pdu.error_status=0;
	pdu.error_index=0;
	
	//Addr
	addr.local_port = 4957;
	//addr.remote_ip = inet_addr("127.0.0.1");
	addr.remote_ip = GetLocalIP();
	addr.broadcast = 0;
	addr.remote_port = 4957;
	
	//Varlist
	memcpy(pdu.var[0].oid,PROC_HEARTBEAT_OID,PROC_HEARTBEAT_OIDLEN*sizeof(DWORD));

	pdu.var[0].oidlen=PROC_HEARTBEAT_OIDLEN;
	pdu.var[0].vartype=0x04;
	pdu.var[0].msglen=16;
	memcpy(pdu.var[0].msg,proc_name,16);

	if(snmp_send(&pdu, &addr) <= 0)
	{
		logMessage("Send heartbeat fail");
		return 0;
	}
	return 1;
}

int read_conffile()
{
	FILE *handle;
	char line[512];
	char tmpline[512];
	char *pstr;
	
	int i;
	int tableMntFlag=0;
	int fileMntFlag=0;
	
	handle=fopen(CONF_FILE,"r");
	if(handle == NULL)
	{
		printf("Read conf file %s fail\n",CONF_FILE);
		logMessage("Read conf file %s fail",CONF_FILE);
		exit(1);
	}
	
	memset(&tbNodeList,0,sizeof(tbNodeList));
	memset(&fileNodeList,0,sizeof(fileNodeList));
	
	logMessage("Read conf file %s",CONF_FILE);
	
	while(parse_line(handle,line,512))
	{
		if(line[0] == '#' || strlen(line) < 4)
			continue;
		
		if(strstr(line,"clean"))
		{
			tableMntFlag=1;
			fileMntFlag=0;
			continue;
		}
		else if(strstr(line,"remove_log"))
		{
			tableMntFlag=0;
			fileMntFlag=1;
			continue;
		}
		
		if(tableMntFlag)
		{
			sprintf(tmpline,"%s",line);
			pstr=strtok(tmpline,",");
			if(pstr)
			{
				sprintf(tbNodeList.node[tbNodeList.node_count].database_name,"%s",pstr);
			}
			else
			{
				logMessage("Error configure database_name in line '%s'",line);
				continue;
			}
			pstr=strtok(NULL,",");
			if(pstr)
			{
				sprintf(tbNodeList.node[tbNodeList.node_count].table_name,"%s",pstr);
			}
			else
			{
				logMessage("Error configure table_name in line '%s'",line);
				continue;
			}
			pstr=strtok(NULL,",");
			if(pstr)
			{
				sprintf(tbNodeList.node[tbNodeList.node_count].time_fieldname,"%s",pstr);
			}
			else
			{
				logMessage("Error configure time_fieldname in line '%s'",line);
				continue;
			}
			pstr=strtok(NULL,",");
			if(pstr)
			{
				tbNodeList.node[tbNodeList.node_count].keep_seconds=atoi(pstr) * 24 * 60 * 60;
			}
			else
			{
				logMessage("Error configure keep_seconds in line '%s'",line);
				continue;
			}
			pstr=strtok(NULL,",");
			if(pstr)
			{
				tbNodeList.node[tbNodeList.node_count].keep_records=strtoul(pstr,NULL,10);
			}
			else
			{
				logMessage("Error configure keep_records in line '%s'",line);
				continue;
			}
			tbNodeList.node_count++;
			if(tbNodeList.node_count >= MAX_NODE_NUM)
			{
				logMessage("Table node count overflow");
				break;
			}
		}
		else if(fileMntFlag)
		{
			sprintf(tmpline,"%s",line);
			pstr=strtok(tmpline,",");
			if(pstr)
			{
				sprintf(fileNodeList.node[fileNodeList.node_count].directory,"%s",pstr);
			}
			else
			{
				logMessage("Error configure directory in line '%s'",line);
				continue;
			}
			pstr=strtok(NULL,",");
			if(pstr)
			{
				sprintf(fileNodeList.node[fileNodeList.node_count].keyword,"%s",pstr);
			}
			else
			{
				logMessage("Error configure keyword in line '%s'",line);
				continue;
			}
			pstr=strtok(NULL,",");
			if(pstr)
			{
				fileNodeList.node[fileNodeList.node_count].keep_seconds=atoi(pstr) * 24 * 60 * 60;
			}
			else
			{
				logMessage("Error configure keep_records in line '%s'",line);
				continue;
			}
			fileNodeList.node_count++;
			if(fileNodeList.node_count >= MAX_NODE_NUM)
			{
				logMessage("File node count overflow");
				break;
			}
		}
	}
	
	logMessage("[TableMaintainNode Count=%d]",tbNodeList.node_count);
	for(i=0;i<tbNodeList.node_count;i++)
	{
		check_table(i);
		logMessage("[%s,%s,%s,%ld,%ld][valid=%d]",tbNodeList.node[i].database_name,tbNodeList.node[i].table_name,tbNodeList.node[i].time_fieldname,tbNodeList.node[i].keep_seconds,tbNodeList.node[i].keep_records,tbNodeList.node[i].valid);
	}
	
	logMessage("[FileMaintainNode Count=%d]",fileNodeList.node_count);
	for(i=0;i<fileNodeList.node_count;i++)
		logMessage("[%s,%s,%ld]",fileNodeList.node[i].directory,fileNodeList.node[i].keyword,fileNodeList.node[i].keep_seconds);
	
	fclose(handle);
	return 1;
}

int parse_line(FILE *handle,char *line,int max_size)
{
	unsigned char chr;
	int cur_size=0;
	
	memset(line,0,max_size);
	while(fread(&chr,1,1,handle))
	{
		if(chr == '\n' || cur_size >= (max_size-1))
			return 1;
		line[cur_size]=chr;
		cur_size++;
	}
	return 0;
}

void logMessage(const char *fmt,...)
{
	char logFile[64];
	FILE *fp;
	time_t l_time;
	va_list ap;
	char buf[8192];
	struct tm *t;
	char timestr[64];
	
	l_time=time(NULL);
	t=localtime(&l_time);
	sprintf(logFile,"../log/omcCleaner%04d%02d%02d.log",t->tm_year+1900,t->tm_mon+1,t->tm_mday);
	fp=fopen(logFile,"a");
	if(fp!=NULL)
	{
		va_start(ap,fmt);
		vsprintf(buf,fmt,ap);
		sprintf(timestr,"%02d:%02d:%02d: ",t->tm_hour,t->tm_min,t->tm_sec);
		fputs(timestr,fp);
		fputs(buf,fp);
		fputs("\n",fp);
		fflush(fp);
		va_end(ap);
		fclose(fp);
	}
}
