/**---------------------------------------------------------------------------
* 版权 2004 啄木鸟基金会
* 保留一切权利。
* 
* 重新分发或者使用源代码格式和二进制格式，无论是否修改，必须在符合
* 以下许可条件的情况下进行：
* 1. 重新分发的源代码必须保留上述版权信息、本许可条件列表以及下列
*    否认声明。
* 2. 重新分发的二进制格式程序必须再次产生上述版权信息，本许可条件列
*    表以及在本分发中的文档或者其他材料中提供的否认声明。
*
* 本软件是由作者和参与者“照此”提供，并且任何显式或隐式的保证，只
* 包含在内但不被其限制，否认任何商业性和特殊目的适切性的隐式担保
* 之效力。本软件的作者或参与者不对由于本软件造成的任何直接地、
* 间接地、连带地、特殊地、惩戒性地，或者由此而产生地损害（还包括
* 以下的不被其限制的内容在内：替代品或服务地取得；使用过程、数据、
* 或由此产生的收益之损失；或商业行为的中断）发生在即使被告知可能
* 出现上述损害后，仍设法摆脱使用本软件的过程中，无论其起因和任何
* 责任地推测，其是否属于合同范畴、限定的义务、或者民事侵权行为
*（包括疏忽及其他）都否认其责任。
* 
* 
*
* Copyright (c) 2004 The Woodpecker Foundation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
**---------------------------------------------------------------------------
*/

#include "utils.h"
#define _INUTILS_
#define CHECKLOGFN \
    curtime(curt, "%Y%m%d"); \
    if ( strncmp(g_logfn + (strlen(g_logfn) - 12), curt, 8) != 0) \
        memcpy(g_logfn + (strlen(g_logfn) - 12), curt, 8);

char    g_logfn[256];
int     g_loglevel = LOGLEVEL_NORMAL;
char    g_filename[256];
int     g_lineno;

char* trim(char *str)
{
    char *p;
    int l, r, i, len;

    len = strlen(str);
    p = (char *)malloc(sizeof(char) * (len + 1));
    
    for(l = 0; l < len ; l++)
        if (str[l] != ' ')
            break;
    if (l == len){ 
        str[0] = 0;
        return 0;
    }
    for(r = len - 1; r >= 0; r--)
        if (str[r] != ' ')
            break;
    if (r < 0){ 
        str[0] = 0;
        return 0;
    }

    memset(p, 0, len + 1);
    for(i = l; i <= r; i ++)
        p[i - l] = str[i];
    strcpy(str, p);

    free(p);
    return str;
} 

/**
 * get an item from key,value string
 * key,value string - "(key1:value2, key2:value3 ...)"
 */
char *get_item(const char *s, const char *key, char *value, char *default_value)
{
    char *pstart, *pend, *pvalue;
    int  len;

//    printf("XXXX:%s\n", default_value);
    strcpy(value, default_value);
//    printf("s=%s, value=%s\n", s, value);

    if ( (pstart = strstr(s, key)) == NULL)
        return value;
    if ( (pend = strchr(pstart, ',')) == NULL)
        if ( (pend = strchr(pstart, ')')) == NULL)
            return value; 
    pend--;
    
    pvalue = strnstr(pstart,  ":",  pend - pstart + 1) + 1;
    len = pend - pvalue + 1;
    memcpy(value, pvalue, len);
    value[len] = 0;
    return trim(value);
//    return value;
}
int getinivals(const char *inifn, const char *segname, char *name, char ***vals)
{
    FILE *fd;
    char line[1024], tmpstr[128], *p;
    int status = 1;
    int i, counter = 0;
    char *tmp_vals[128];

    //tmp_vals = (char **)

    if ( (fd = fopen(inifn, "r")) == 0)
        return -1;

    for (;;){
        if (fgets(line, 1024, fd) == 0){
            break;
        }
        line[strlen(line) - 1] = 0;
        trim(line);
        if ( (line[0] == 0) || (line[0] == '#'))    /* line to ignore */
            continue;

        if (status == 1){                       /* finding segname */
            if (line[0] != '[') 
                continue;
            memset(tmpstr, 0, 128);
            memcpy(tmpstr, line + 1, strlen(line) - 2);
            trim(tmpstr);
            if ( strcmp(segname, tmpstr) == 0){
                status = 2;
            }
        }
        else {                                  /* finding name */
            if (status == 2){
                if (line[0] == '[')             /* occupy next segment */
                    break;
                p = strchr(line, '=');
                memset(tmpstr, 0, 128);
                memcpy(tmpstr, line, (unsigned int)p - (unsigned int)line);
                trim(tmpstr);
                if ( strcmp(name, tmpstr) == 0){
                    sprintf(tmpstr, p + 1);     /* found it! */
                    tmp_vals[counter] = (char *)malloc(strlen(tmpstr) + 1);
                    strcpy(tmp_vals[counter] , tmpstr);
                    counter++;
                    if (counter >= 128)
                        break;
                }
            }
        }
    }
    if (counter > 0){
        *vals = (char **)malloc(sizeof(char *) * counter);
        for (i = 0 ; i < counter; i++){
            (*vals)[i] =  tmp_vals[i];
        }
    }
    fclose(fd);
    return counter;
}
char *getinival(const char *inifn, const char *segname, char *name, char *val, char *default_val)
{
    FILE *fd;
    char line[1024], tmpstr[128], *p;
    int status = 1;

    if ( (fd = fopen(inifn, "r")) == 0)
        return default_val;

    for (;;){
        if (fgets(line, 1024, fd) == 0){
            fclose(fd);
            return default_val;
        }
        line[strlen(line) - 1] = 0;
        trim(line);
        if ( (line[0] == 0) || (line[0] == '#'))    /* line to ignore */
            continue;

        if (status == 1){                       /* finding segname */
            if (line[0] != '[') 
                continue;
            memset(tmpstr, 0, 128);
            memcpy(tmpstr, line + 1, strlen(line) - 2);
            trim(tmpstr);
            if ( strcmp(segname, tmpstr) == 0){
                status = 2;
            }
        }
        else {                                  /* finding name */
            if (status == 2){
                if (line[0] == '[')             /* occupy next segment */
                    return default_val;
                p = strchr(line, '=');
                memset(tmpstr, 0, 128);
                memcpy(tmpstr, line, (unsigned int)p - (unsigned int)line);
                trim(tmpstr);
                if ( strcmp(name, tmpstr) == 0){
                    sprintf(tmpstr, p + 1);     /* found it! */
                    strcpy(val , tmpstr);
                    fclose(fd);
                    return val;
                }
            }
            else {
                fclose(fd);
                return default_val;
            }
        }
    }
    return default_val;
}

int    err_quit(const char *fmt, ...)
{
    va_list args;

    va_start(args, fmt);
    vprintf(fmt, args);
    va_end(args);
    exit(1);
}

const char* curtime(char* curt, const char *fmt)
{
    char    s[64];
    time_t  curtime;

    time(&curtime);
    strftime(s, 64, fmt, localtime(&curtime));

    strcpy(curt, s);
    return curt;
}

int loginit(const char *logname, int loglevel)
{
    FILE *fd;

    if ( (fd = fopen(logname, "a+")) == 0){
        printf("open log file:%s fail. "
            "log will redirectory to stdout\n", logname);
        strcpy(g_logfn, "");
    }
    else {
        fclose(fd);
        strcpy(g_logfn, logname);
    }
    
    if (   (loglevel == LOGLEVEL_BRIEF) || (loglevel == LOGLEVEL_NORMAL) 
        || (loglevel == LOGLEVEL_DETAIL) )
        g_loglevel = loglevel;
    else{
        printf("\n[I]:unknown loglevel:%d, loglevel will set to "
            "LOGLEVEL_NORMAL(=%d)", loglevel, LOGLEVEL_NORMAL);
        g_loglevel = LOGLEVEL_NORMAL;
    }
    return 0;
}
int _logmsg(const char *format, ...)
{
    FILE *fd;
    char curt[64], exformat[256];
    va_list ap;

    if (g_loglevel < LOGLEVEL_BRIEF) 
        return 0;

    CHECKLOGFN

    if ( (fd = fopen(g_logfn, "a+")) == 0)
        fd = stdout;
    
    va_start(ap, format);
    curtime(curt, "%H:%M:%S");
    sprintf(exformat, "%s %5d %-7s,%3d%s", curt, getpid(), 
            g_filename, g_lineno, format);
    vfprintf(fd, exformat, ap);
    va_end(ap);
    if (ferror(fd)){
        printf("log file write error\n");
        return -1;
    }
    if (fd != stdout)
        fclose(fd);
    return 0;
}
int _logpacket(const void *vptr, size_t n)
{
    FILE *fd;
    char *ptr, curt[32];

    if (g_loglevel < LOGLEVEL_NORMAL) return 0;

    CHECKLOGFN

    if ( (fd = fopen(g_logfn, "a+")) == 0)
        fd = stdout;

    fwrite("----------PACKET----[begin]--\n", 1, 30, fd);
    ptr = (char *)malloc(sizeof(char) * n);
    memcpy(ptr, (char *)vptr, n);
    fwrite(ptr, sizeof(*ptr), n, fd);
    free(ptr);
    fwrite("\n", 1, 1, fd);
    fwrite("----------PACKET----[ end ]--\n", 1, 30, fd);
 
    if (ferror(fd)){
        printf("log file write error\n");
        return -1;
    }

    if (fd != stdout)
        fclose(fd);

    return 0;
}

int _logitem(void *pitem, const char *name, char type, int vcount, int width)
{
    FILE    *fd;
    int     i, len;
    char    *ptr, head[32], curt[32], strtmp[256];

    if (g_loglevel < LOGLEVEL_NORMAL) return 0;

    CHECKLOGFN

    if ( (fd = fopen(g_logfn, "a+")) == 0)
        fd = stdout;

    curtime(curt, "%H:%M:%S");
    sprintf(head, "%s %5d %-7s,%3d[I]:", curt, getpid(), g_filename, g_lineno);

    switch(type){
        case 'c':
            ptr = (char *)pitem;
            if (vcount == 0){
                if ((ptr[0] == 0) || (ptr[0] == ' '))   break;
                fprintf(fd, "%s%s:|%c|\n", head, name, ptr[0]);
            }
            else{
                for (i = 0; i < vcount; i++){
                    if ((ptr[i] == 0) || (ptr[i] == ' '))   break;
                    fprintf(fd, "%s%s[%d]:|%c|\n", head, name, i, ptr[i]);
                }
            }
            break;
        default:
            ptr = (char *)pitem;
            if (vcount == 0){
                len = strlen(ptr);
                len = len < (width - 1) ? len : (width - 1);
                memcpy(strtmp, ptr, len); strtmp[len] = 0;
                trim(strtmp);
                if (strtmp[0] == 0) break;
                if ( (strncmp(name, "CustPwd", 7) == 0) ||
                     (strncmp(name, "BankPwd", 7) == 0) ||
                     (strncmp(name, "SecuPwd", 7) == 0) ||
                     (strncmp(name, "NewPwd", 6) == 0) )
                    strcpy(strtmp, "**********");
                fprintf(fd, "%s%s:|%s|\n", head, name, strtmp);
            }
            else{
                for (i = 0; i < vcount; i++){
                    len = strlen(ptr);
                    len = len < (width - 1) ? len : (width - 1);
                    memcpy(strtmp, ptr, len); strtmp[len] = 0;
                    trim(strtmp);
                    if (strtmp[0] == 0) break;
                    fprintf(fd, "%s%s[%d]:|%s|\n", head, name, i, strtmp);
                    ptr += width;
                }
            }
    }
    if (fd != stdout)
        fclose(fd);

    return 0;
}
#define LOGI(item, name, type, vcount) \
            _logitem(&item, name, type, vcount, sizeof(item))

/*
        if (vcount == 0) \
            _logitem(item, name, type, vcount, 0); \
        else \
*/
int _logzp(const void *vptr, size_t n)
{
    FILE *fd;
    const char *ptr = (const char *)vptr;
    char    curt[32];

    if (g_loglevel < LOGLEVEL_DETAIL) return 0;

    CHECKLOGFN

    if ( (fd = fopen(g_logfn, "a+")) == 0)
        fd = stdout;

    fwrite(ptr, sizeof(*ptr), n, fd);
    fwrite("\n", 1, 1, fd);
 
    if (ferror(fd)){
        printf("log file write error\n");
        return -1;
    }

    if (fd != stdout)
        fclose(fd);

    return 0;
}
