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

#include "stdarg.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define MAXLOGSTR 4096

int get_sizeof_shm()
{
	struct stat stat;

	int memsize;
	int filed;

	/***        Posix Share Memory        ***/
	filed = Shm_open(SHM_NAME, O_RDONLY, FILE_MODE);
	Fstat(filed, &stat);
	Close(filed);
	/* get size of mapping memory */
	memsize = stat.st_size;
	return memsize;
}

servinfo_t *get_shm_start_pointer()
{
	struct stat stat;
	servinfo_t *start_ptr;
	int fd;

	fd = Shm_open(SHM_NAME, O_RDWR, FILE_MODE);
	Fstat(fd, &stat);
	start_ptr = Mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

	Close(fd);
	return start_ptr;
}

servinfo_t *get_shm_start_pointer_readonly()
{
	struct stat stat;
	servinfo_t *start_ptr;
	int fd;

	fd = Shm_open(SHM_NAME, O_RDONLY, FILE_MODE);
	Fstat(fd, &stat);
	start_ptr = Mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);

	Close(fd);
	return start_ptr;	
}

int devide(char **val, char *str, char delim)
{
	char *p;
	int i, j;

	val[0] = (char *)malloc(512);
	memset(val[0], 0, 512);

	for (p=str, i=0, j=0; *p != '\0'; p++)
	{
		if (*p == delim)
		{
			*(val[i] + j) = '\0';
			j = 0;
			i++;
			val[i] = (char *)malloc(512);
			memset(val[i], 0, 512);
			continue;
		}
		else if (*p == '\n')
		{
			continue;
		}
		else
		{
			*(val[i] + j++) = *p;
		}
	}
	*(val[i] + j) = '\0';
	return (i+1);
}

char* timeToString(struct tm *t) {
	static char s[20];
	sprintf(s, "%04d-%02d-%02d %02d:%02d:%02d",
              t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
              t->tm_hour, t->tm_min, t->tm_sec
          );
	return s;
}

char *makeLogString()
{
	struct tm *t;
	time_t timer;
	static char log_path_file[128];

	timer = time(NULL);
	t = localtime(&timer);

	snprintf(log_path_file, 128, "%ssh_statusd_%04d%02d%02d.log", DEFAULT_LOGFILE_PATH,
			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
	return log_path_file;
}

char *makeLogString_para(const char *prefix)
{
	struct tm *t;
	time_t timer;
	static char log_path_file[128];

	timer = time(NULL);
	t = localtime(&timer);

	snprintf(log_path_file, 128, "%s%s_%04d%02d%02d.log", DEFAULT_LOGFILE_PATH, prefix,
			t->tm_year + 1900, t->tm_mon + 1, t->tm_mday);
	return log_path_file;
}

int fd_isopen(int fd)
{
    struct flock lock;

    lock.l_type = F_WRLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;

    return fcntl(fd, F_SETLKW, &lock);
}

int fd_unlock(int fd)
{
    struct flock lock;

    lock.l_type = F_UNLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;

    return fcntl(fd, F_SETLK, &lock);
}

void WriteSHLog(char *fmt, ...) {
    va_list ap;
    struct tm *t;
    time_t timer;
    int shLogFile;

    char *para_ptr;
    char logStr[MAXLOGSTR];

    para_ptr = fmt;
    timer = time(NULL);
    t = localtime(&timer);

    shLogFile = open(makeLogString(), O_CREAT | O_RDWR | O_APPEND);
    if (shLogFile == -1)
    {
        fprintf(stderr, "Cannot open SH Log file!!\n");
        exit(EXIT_FAILURE);
    }
    if (fd_isopen(shLogFile) == -1)
    {
        fprintf(stderr, "log file lock fail!!!\n");
        exit(0);
    }

    snprintf(logStr, MAXLOGSTR,  "[%s] ", timeToString(t));
    write(shLogFile, logStr, strlen(logStr));

    va_start(ap, para_ptr);
    while (*para_ptr) {
        memset(logStr, 0, MAXLOGSTR);
        switch(*para_ptr) {
            case 0x25:
                if (*(para_ptr+1) == 'c') {                                 /* char */
                    snprintf(logStr, MAXLOGSTR,  "%c",(char)va_arg(ap, int));
                } else if (*(para_ptr+1) == 'd') {                          /* int */
                    snprintf(logStr, MAXLOGSTR,  "%d", va_arg(ap, int));
                    para_ptr++;
                } else if (*(para_ptr+1) == 'u') {                          /* unsigned int */
                    snprintf(logStr, MAXLOGSTR,  "%u", va_arg(ap, unsigned int));
                    para_ptr++;
                } else if (*(para_ptr+1) == 'f') {                          /* float */
                    snprintf(logStr, MAXLOGSTR,  "%f", (float)va_arg(ap, double));
                    para_ptr++;
                } else if (*(para_ptr+1) == 's') {                          /* string */
                    snprintf(logStr, MAXLOGSTR,  "%s", va_arg(ap, char *));
                    para_ptr++;
                } else if (*(para_ptr+1) == 'l' && *(para_ptr+2) == 'd') {  /* long int */
                    snprintf(logStr, MAXLOGSTR,  "%ld", va_arg(ap, long int));
                    para_ptr++;
                    para_ptr++;
                } else if (*(para_ptr+1) == 'l' && *(para_ptr+2) == 'u') {  /* unsigned long int */
                    snprintf(logStr, MAXLOGSTR,  "%lu", va_arg(ap, unsigned long int));
                    para_ptr++;
                    para_ptr++;
                } else if (*(para_ptr+1) == 'l' && *(para_ptr+1) == 'l' && *(para_ptr+2) == 'd') {  /* long long int */
                    snprintf(logStr, MAXLOGSTR,  "%lld", va_arg(ap, long long int));
                    para_ptr++;
                    para_ptr++;
                    para_ptr++;
				} else if (*(para_ptr+1) == 'l' && *(para_ptr+1) == 'l' && *(para_ptr+2) == 'u') {  /* unsigned long long int */
                    snprintf(logStr, MAXLOGSTR,  "%llu", va_arg(ap, unsigned long long int));
                    para_ptr++;
                    para_ptr++;
                    para_ptr++;
                }
                write(shLogFile, logStr, strlen(logStr));
                break;
            default:
                snprintf(logStr, MAXLOGSTR, "%c", *para_ptr);
                write(shLogFile, logStr, strlen(logStr));
                break;
        }
        para_ptr++;
    }
    va_end(ap);
    if (fd_unlock(shLogFile) == -1)
    {
        fprintf(stderr, "file unlock error\n");
    }

    close(shLogFile);
}

void WriteSHLog_safe(char *fmt, ...) {
    va_list ap;
    struct tm *t;
    time_t timer;
    FILE *shLogFile = NULL;

    char *para_ptr;
    char logStr[MAXLOGSTR];

    para_ptr = fmt;
    timer = time(NULL);
    t = localtime(&timer);

    shLogFile = fopen(makeLogString(), "a+");
    if (shLogFile == NULL)
    {
        fprintf(stderr, "Cannot open SH Log file!!\n");
        exit(EXIT_FAILURE);
    }
    flockfile(shLogFile);

    snprintf(logStr, MAXLOGSTR,  "[%s] ", timeToString(t));
    fwrite(logStr, strlen(logStr), 1, shLogFile);

    va_start(ap, para_ptr);
	#ifdef  HAVE_VSNPRINTF
    vsnprintf(logStr, MAXLOGSTR, fmt, ap);   /* safe */
#else
    vsprintf(logStr, fmt, ap);                 /* not safe */
#endif
    va_end(ap);

	fwrite(logStr, strlen(logStr), 1, shLogFile);
    funlockfile(shLogFile);
    fclose(shLogFile);
}
