#include "unp.h"
#include "unpipc.h"

static char HostName[512];
static char report_update_port[16];
static char report_send_port[16];

void report_thread_make(int whatis)
{
	void    *report_thread_send_main(void *);
    void    *report_thread_update_main(void *);

	int		a = 0;
	int		b = 1;

	GetProfile("PARAM", "HOSTNAME", HostName, "");
	GetProfile("PARAM", "REPORT_UPDATE_PORT", report_update_port, "");
	GetProfile("PARAM", "REPORT_SEND_PORT", report_send_port, "");

	if (whatis == 0)
	{
		/* make server list update thread (for changing server information [INSERT, UPDATE, DELETE]) */
		Pthread_create(&report_tptr[a].thread_tid, NULL, &report_thread_update_main, (void *)a);
	}
	else if (whatis == 1)
	{
		/* make server list send thread (for SMS WEB service */
		Pthread_create(&report_tptr[b].thread_tid, NULL, &report_thread_send_main, (void *)b);
	}
	else
	{
		Pthread_create(&report_tptr[a].thread_tid, NULL, &report_thread_update_main, (void *)a);
	    Pthread_create(&report_tptr[b].thread_tid, NULL, &report_thread_send_main, (void *)b);
	}

	/*
	pthread_detach(report_tptr[a].thread_tid);
	pthread_detach(report_tptr[b].thread_tid);
	*/

	return;
}

void * report_thread_send_main(void *arg)
{
    struct sockaddr_storage cliaddr;
	char *start_point = NULL;
    char *pTmpData = NULL;
    char szLineBuffer[1024];
	int offset;
	int str_len;
    int nLeft, nWrite=0;
	int eWrite=0;
    int SndBlockSize = 1024;
    socklen_t len;
    ssize_t n;
    char rcvBuff[MAXREADLINE];
    char sndBuff[MaxSizeOfSndBuffer];

	WriteSHLog_safe("report server list send thread(1) starting..\n");

	report_tptr[(int) arg].deadORalive = 1;

    /* ToDo thread : UDP connection */
    send_reportfd = Udp_server((char *)HostName, (char *)report_send_port, NULL);
	report_tptr[(int) arg].thread_count++;
    for ( ; ; )
    {
        len = sizeof(cliaddr);
		memset(rcvBuff, 0, MAXREADLINE);
		memset(sndBuff, 0, MaxSizeOfSndBuffer);

        n = Recvfrom(send_reportfd, rcvBuff, MAXREADLINE, 0, (SA *)&cliaddr, &len);
		
		if (n < 0)
		{
			pthread_exit(0);
		}

#ifdef __DEBUG__
        fprintf(stderr, "receive contents : %s\n", rcvBuff);
        fprintf(stderr, "datagram from %s\n", Sock_ntop((SA *)&cliaddr, len));
#endif
        report_tptr[(int) arg].thread_count++;

        if (strncmp(rcvBuff, GetServStatusCmd, 14))
        {
            memset(sndBuff, 0, MaxSizeOfSndBuffer);
            snprintf(sndBuff, MaxSizeOfSndBuffer, "Invalid Argument!");
            eWrite = sendto(send_reportfd, sndBuff, strlen(sndBuff), 0, (SA *)&cliaddr, len);
			if(nWrite < 0)
			{
#ifdef __SETLOG__
				WriteSHLog_safe("Error! send to sms web. sendto : %s\n", strerror(errno));
#endif
			}
            continue;
        }

        /* send to SMS server */
        pTmpData = make_status_string(&str_len);
		start_point = pTmpData;
#ifdef __DEBUG__
		fprintf(stderr , "report_send@@@@@@@@@@@@@@\n");
#endif
        nLeft = str_len;

        /* view udp data */
#if 0 
		//WriteSHLog_safe("%s(%d)\n", pTmpData, nLeft);
        WriteSHLog_safe("string length to send SMS: (%d)\n", nLeft);
#endif
		
		do
        {
            offset = 0;
			SndBlockSize = 1024;
            memset(szLineBuffer, 0, 1024);

            if(nLeft < SndBlockSize)
                SndBlockSize = nLeft;

            while(offset < SndBlockSize)
                szLineBuffer[offset++] = *pTmpData++;

            szLineBuffer[offset] = '\0';
			usleep(10);
            nWrite = sendto(send_reportfd, szLineBuffer, offset + 1, 0, (SA *)&cliaddr, len);
            nWrite -= 1;
			
            if(nWrite < 0)
            {
#ifdef __SETLOG__
				WriteSHLog_safe("Error! send to sms web. sendto : %s\n", strerror(errno));
#endif
                break;
            }
            else if(nWrite == 0)
            {
                break;
            }
            nLeft -= nWrite;
        }while(nLeft >= 0);
		free(start_point);
    }
}

char *make_status_string(int *str_len)
{
    servinfo_t *i, *start_servinfo;

	char sztmpBuffer[1024+5];
	//char logstring[1024];
	char *status_str;
    int len = 0;
    int cnt;
	int offset = 0;
    int inc_size = 0;
	int adding = 0;
	int shm_size = 0;

    char host[128], host2[128], *p;
    cnt = 0;

	shm_size = get_sizeof_shm();
	while ((start_servinfo = get_shm_start_pointer_readonly()) == (void *)-1)
		usleep(1000);

	status_str = (char *)malloc(1024);
    for (i = start_servinfo; strcmp(i->m_pszServName, END_OF_SHM); i++)
    {
		if (i->m_pszServName[0] == '\0')
	        break;

        memset(sztmpBuffer, 0, 1024);
        len = snprintf(sztmpBuffer, 1024, "%d|%d|%s|%s|%d|%ld|"
                ,i->m_Status
                ,i->m_ServType
                ,i->m_pszServName
                ,i->m_szIpString
                ,i->m_sPort
                ,i->m_StatChgTime
				);

        if (i->m_pszDomainName && strlen(i->m_pszDomainName) > 0) {
            if (!strcmp(i->ss.du.domain, i->ss.du.hostname) || i->ss.du.hostname[0] == '\0')
            {
                strcpy(host, i->ss.du.domain);
            }
            else
            {
                strcpy(host2, i->ss.du.hostname);
                p = strchr(host2, '.');
                if (p) {
                    *p = '\0';
                }
                sprintf(host, "%s(%s)", i->ss.du.domain, host2);
            }
            adding = snprintf(sztmpBuffer + len, 1024 - len,
                    "%ld|%s|%llu|%llu|%d|%d|%d|%d|%d|%d|%u|%u|%u|%u|\r\n"
                    ,(long)(i->ss.stamp)
                    ,host
                    ,(unsigned long long)(i->ss.du.total)
                    ,(unsigned long long)(i->ss.du.free)
                    ,(int)(i->ss.du.manual_disable)
                    ,(int)(i->ss.du.upload_level)
                    ,(int)(i->ss.du.disk_backlog)
                    ,(int)(i->ss.du.disk_percent)
                    ,(int)(i->ss.du.connection_established)
                    ,(int)(i->ss.du.connection_total)
                    ,(i->ss.du.traffic_ip)
                    ,(i->ss.du.traffic_ib)
                    ,(i->ss.du.traffic_op)
                    ,(i->ss.du.traffic_ob));
        }
		else {
			adding = snprintf(sztmpBuffer + len, 1024 - len,
                    "%s", "-|-|-|-|-|-|-|-|-|-|-|-|-|-|\r\n");
        }
        /* realloc status_str */
		inc_size += (len + adding);

        status_str = (char *)realloc(status_str, inc_size);
        if (!status_str)
        {
            WriteSHLog_safe("Cannot reallocation heap!\n");
            exit(0);
        }
        //strncat(status_str, sztmpBuffer, strlen(sztmpBuffer));
        memcpy(status_str + offset, sztmpBuffer, len+adding);
		offset += (len + adding);
        cnt++;
    }
	*str_len = inc_size;

	munmap((void *)start_servinfo, shm_size);
    return status_str;
}

void * report_thread_update_main(void *arg)
{
    //char * make_status_string(char *status_str);

    struct sockaddr_storage cliaddr;
    int res = 0;
	int eWrite;
    int SndBlockSize = 1024;
    socklen_t len;
    ssize_t n;

    char rcvBuff[MAXREADLINE];
    char sndBuff[128];

	report_tptr[(int) arg].deadORalive = 1;

    /* ToDo thread : UDP connection */
	Pthread_mutex_lock(&report_u_lock);
    update_reportfd = Udp_server((char *)HostName, (char *)report_update_port, NULL);
	report_tptr[(int) arg].thread_count++;
	Pthread_mutex_unlock(&report_u_lock);
    WriteSHLog_safe("report serverList update thread(0) starting..\n");

    for ( ; ; )
	{
        SndBlockSize = 1024;
		len = sizeof(cliaddr);

		n = Recvfrom(update_reportfd, rcvBuff, MAXREADLINE, 0, (SA *)&cliaddr, &len);
		
		if (n < 0)
		{
			pthread_exit(0);
		}
		
#ifdef __SETLOG__
		WriteSHLog_safe("[UPDATE] receive contents : %s\n", rcvBuff);
#endif
        if (strncmp(rcvBuff, RequestServUpdateCmd, 19))
        {
            memset(sndBuff, 0, MaxSizeOfSndBuffer);
            snprintf(sndBuff, MaxSizeOfSndBuffer, "Invalid Argument!");
            eWrite = sendto(update_reportfd, sndBuff, strlen(sndBuff), 0, (SA *)&cliaddr, len);
			if (eWrite < 0)
			{
#ifdef __SETLOG__
				WriteSHLog_safe("report update thread fail to send web. but don't care\n");
#endif
			}
            continue;
        }
        /* Update server list from DB */
		Semop(report_semid, &waitop, 1);
        res = update_report_func();
		Semop(report_semid, &postop, 1);
#ifdef __DEBUG__
		fprintf(stderr , "report_update@@@@@@@@@@@@@@\n");
#endif
        if (res == 0)
        {
#ifdef __SETLOG__
			WriteSHLog_safe("report(update) Job Fail!!!!\n");
#endif
            strncpy(sndBuff, "FAILURE!", sizeof(sndBuff));
        }
        else
        {
#ifdef __DEBUG__
            fprintf(stderr, "\nreport(update) Job Success!\n");
#endif
            strncpy(sndBuff, "SUCCESS_0222", sizeof(sndBuff));
        }
        eWrite = sendto(update_reportfd, sndBuff, strlen(sndBuff), 0, (SA *)&cliaddr, len);
		if (eWrite < 0)
		{
#ifdef __SETLOG__
			WriteSHLog_safe("report update thread fail to send web. but don't care\n");
		}
#endif
        usleep(100);
    }
}

int update_report_func()
{
    MYSQL   mysql;
    MYSQL_RES *res;
    MYSQL_ROW row;

    servinfo_t  *temp_servinfo, *servinfo_head;
    servinfo_t  *init_servinfo, *start_servinfo;
	servinfo_t  *servinfo_ptr;
	g_shm_t *g_shm_ptr;

	void *shared_memory = (void *)0;
    char    mysql_db[8];
    char    mysql_user[16];
    char    mysql_pass[16];
	char	logString[1024];

    int     fd;
    int     shm_size;
    int     mysql_port, fields;
    int     cnt;
	int 	shmid;
    long    numRows;

    /* initialize mysqlDB */
    mysql_init(&mysql);

    GetProfile("MYSQL", "DATABASE_NAME", mysql_db, "CCDB");
    GetProfile("MYSQL", "DATABASE_ACCT", mysql_user, "root");
    GetProfile("MYSQL", "DATABASE_PW", mysql_pass, "alfkzmf!?{}");
    mysql_port = GetProfileInt("MYSQL", "DATABASE_PORT", 3306);
    /* connect mysql */
    if (!mysql_real_connect(&mysql, NULL, mysql_user, mysql_pass, mysql_db, mysql_port, (char *)NULL, 0))
    {
		WriteSHLog_safe("[MYSQL] %s\n", mysql_error(&mysql));
        return 0;
    }
    /* start transaction */
    mysql_autocommit(&mysql, 0);
    if (mysql_query(&mysql, MYQUERY))
    {
        WriteSHLog_safe("[error]%s\n", mysql_error(&mysql));
        mysql_rollback(&mysql);
        mysql_close(&mysql);
        return 0;
    }
    else
    {
#ifdef __DEBUG__
        fprintf(stderr, "%s\n", "[MySQL]Query Success!!");
#endif
        mysql_commit(&mysql);
    }

	shm_size = get_sizeof_shm();
	numRows = (int)(shm_size/sizeof(servinfo_t));
	/* get the global SHM start pointer */
    start_servinfo = servinfo_ptr = get_shm_start_pointer();
	/****************** store old SHM to Temporary ************************/
    servinfo_head = Calloc(numRows+1, sizeof(servinfo_t));
    temp_servinfo = (servinfo_t *)servinfo_head;
    while (strcmp(servinfo_ptr->m_pszServName, END_OF_SHM))
    {
		if (servinfo_ptr->m_pszServName[0] == '\0')
	        break;
        /* tmporary servinfo_t */
        memcpy(temp_servinfo, servinfo_ptr, sizeof(servinfo_t));
        temp_servinfo++;
        servinfo_ptr++;
    }
    strncpy(temp_servinfo->m_pszServName, END_OF_SHM, 11);
    /***********************************************************************/

    /****************** delete old SHM and create new SHM ******************/
	/*
    munmap((void *)g_servinfo, shm_size);
	g_servinfo = NULL;
	shm_unlink(SHM_NAME);
	*/
    /***********************************************************************/

	/****************** GET new server list from mysql *********************/
	res = mysql_store_result(&mysql);
	fields = mysql_num_fields(res);
	numRows = mysql_num_rows(res);
#ifdef __DEBUG__
	fprintf(stderr, "[NEW LIST] numRows --> %ld\n", numRows);
#endif
	if (numRows == 0)
	    numRows = 1;

	munmap((void *)start_servinfo, shm_size);
	fd = Shm_open(SHM_NAME, O_RDWR | O_CREAT | O_TRUNC, FILE_MODE);
	Ftruncate(fd, 0);
	usleep(100);
	Ftruncate(fd, sizeof(servinfo_t)*(numRows+1));
    init_servinfo = Mmap(NULL, sizeof(servinfo_t)*(numRows+1), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	memset(init_servinfo, 0, sizeof(servinfo_t)*(numRows+1));
	servinfo_ptr = init_servinfo;
    cnt = 1;
    while((row = mysql_fetch_row(res)))
    {
        addServerToList(servinfo_ptr, row);
		servinfo_ptr++;
        cnt++;
    }
    strncpy(servinfo_ptr->m_pszServName, END_OF_SHM, 11);
    Close(fd);

	/* if server_update button click then system V shm's value is dirty */
    shmid = shmget((key_t)6677, sizeof(g_shm_t), IPC_CREAT);
    if (shmid == -1)
    {
        WriteSHLog_safe("system V shmget failed\n");
        exit(EXIT_FAILURE);
    }
    shared_memory = shmat(shmid, (void *)0, 0);
    if (shared_memory == (void *)-1)
    {
        WriteSHLog_safe("system V shmat failed\n");
        exit(EXIT_FAILURE);
    }
    g_shm_ptr = (g_shm_t *)shared_memory;
    g_shm_ptr->is_dirty = 1;

    if (shmdt(shared_memory) == -1)
    {
        WriteSHLog_safe("system V shmdt failed\n");
        exit(EXIT_FAILURE);
    }
	
	/* update server list */
    //update_server_list(init_servinfo, servinfo_head);
	/* close mysqlDB */
	mysql_free_result(res);
	mysql_close(&mysql);
	free(servinfo_head);
	munmap((void *)init_servinfo, (sizeof(servinfo_t)*numRows));
    return 1;
}

void update_server_list(servinfo_t *new, servinfo_t *old)
{
    servinfo_t  *ii;

    while (strcmp(new->m_pszServName, END_OF_SHM))
    {
		if (new->m_pszServName[0] == '\0')
	        break;
        for (ii = old; strcmp(ii->m_pszServName, END_OF_SHM); ii++)
        {
			if (ii->m_pszServName[0] == '\0')
	            break;
            if (!strcmp(new->m_pszServName, ii->m_pszServName))
            {
				memcpy(new->m_pszDomainName, ii->m_pszDomainName, MAX_DOMAIN_NAME);
                memcpy((char *)&(new->ss), (char *)&(ii->ss), sizeof(struct svr_status));
                break;
            }
        }
        new++;
    }
}
