#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/stat.h>

#include "./include/cdr.h"

static _cdr_vm_struct  *cdr_vm_ptr;
static int cdr_sem_id;
static _cdr_param cdr_param;
static char cdr_time[8];
static int cdr_counter0=0,cdr_counter1=0;        
static int ssn_counter[256];
     
int cdr_init(char plane_id, char type_flag) /* type=0/1: slave(MSS), master */
{
    int cdr_shm_id;
    
    GetCurrentTime(cdr_time);
    
    cdr_vm_ptr = (_cdr_vm_struct *)shm_init(cdr_shm_id,
    				"cdr_init", 
    				CDR_SHM_KEY, 
    				sizeof(_cdr_vm_struct),
    				CDR_SHM_PERM|IPC_CREAT);
    cdr_sem_id = sem_init("cdr_init", CDR_SEM_KEY, 1, CDR_SEM_PERM|IPC_CREAT );
    
    if(type_flag == 0)
    {
        memset(cdr_vm_ptr, 0x00, sizeof(_cdr_vm_struct));
        cdr_vm_ptr->plane_id = plane_id;
    }
    else
    {
    	cdr_config();
    	cdr_vm_ptr->plane_id = cdr_param.system_id;
    }
    
    
    return 0;
}

int cdr_timer()
{
    static int cdr_timer_counter = 0;
    
    if(cdr_timer_counter++%200 == 0) /*every 2 seconds */
    {
        GetCurrentTime(cdr_time);
        if(cdr_time[4] == 0 && cdr_time[5]>0 && cdr_time[5] <= 2)
        {
            cdr_open_all_new_fd();
        }
        if(cdr_time[3] == 0 && cdr_time[4] ==0 && cdr_time[5] <= 2)
        {
            clean_expired_backup_file();
        }
    }
    
    cdr_backup();
    
    return 1;
}

/* -------- initialisation functions *---------- */

_cdr_param default_param=
{
    0,
    "/usr/local/backup/cdr",
    ".csv",
    0,
    7,
};

int cdr_open_ssn_file(int index)
{
    char *file_name, file_name0[128],file_name_new[128];
    
    if(!cdr_param.ssn_param[index].ssn)
        return 0;
    file_name = &file_name0[0];
    
    if(cdr_param.max_records_per_file == 0)
    {
        sprintf(file_name,"%s/cdrFrom%s%d_%d_%02d_%02d_%02d%s",
            cdr_param.base_dir,
            cdr_param.ssn_param[index].name,
    	    cdr_vm_ptr->plane_id,
    	    cdr_time[0]+2000,
    	    cdr_time[1],
    	    cdr_time[2],
    	    cdr_time[3],
    	    cdr_param.file_suffix);
    }
    else
    {
    	if(cdr_param.init_flag == 0)
    	{
            DIR *dp;            
            struct dirent *dirp;
            int  no=0,n;
            
            if((dp=opendir(cdr_param.base_dir))==NULL)
                printf("can't open %s",cdr_param.base_dir);
                
            while (((dirp=readdir(dp))!=NULL) && (n<=50))
            {
                sprintf(file_name_new,"cdrFrom%s%d_%d_%02d_%02d_%02d",    	   
                    cdr_param.ssn_param[index].name,
    	            cdr_vm_ptr->plane_id,
    	            cdr_time[0]+2000,
    	            cdr_time[1],
    	            cdr_time[2],
    	            cdr_time[3]);
    	        no = 0;
    	        if(!strncasecmp(dirp->d_name,file_name_new,strlen((char *)file_name_new)))
    	        {
    	            while(1)
    	            {
    	                sprintf(file_name,"%s_%d%s",    	   
                            file_name_new,
                            no,
    	                    cdr_param.file_suffix);
    	                if(strncasecmp(dirp->d_name,file_name,strlen((char *)file_name)<0))
    	                    break;
    	                else if(!strncasecmp(dirp->d_name,file_name,strlen((char *)file_name)))
    	                {
    	                    if((no+1)>cdr_param.ssn_param[index].file_sn) /* a new file */
    	                        cdr_param.ssn_param[index].file_sn = no+1;
    	                    break;
    	                }
    	                no++;
    	            } //while
    	        } //if
            }//while
            
            closedir(dp);
    	    
    	    sprintf(file_name,"%s/cdrFrom%s%d_%d_%02d_%02d_%02d_%d%s",
    	        cdr_param.base_dir,
                cdr_param.ssn_param[index].name,
    	        cdr_vm_ptr->plane_id,
    	        cdr_time[0]+2000,
    	        cdr_time[1],
    	        cdr_time[2],
    	        cdr_time[3],
    	        cdr_param.ssn_param[index].file_sn++,
    	        cdr_param.file_suffix);	
    	        
        }
        else
        {
            sprintf(file_name,"%s/cdrFrom%s%d_%d_%02d_%02d_%02d_%d%s",
                cdr_param.base_dir,
                cdr_param.ssn_param[index].name,
    	        cdr_vm_ptr->plane_id,
    	        cdr_time[0]+2000,
    	        cdr_time[1],
    	        cdr_time[2],
    	        cdr_time[3],
    	        cdr_param.ssn_param[index].file_sn++,
    	        cdr_param.file_suffix);	
       	}
    }

    strcpy(cdr_param.ssn_param[index].file_name,file_name);
    
    if(cdr_param.ssn_param[index].fd != NULL)
        fclose(cdr_param.ssn_param[index].fd);
 
    cdr_param.ssn_param[index].fd = fopen(file_name,"a+b");    	    
    cdr_param.ssn_param[index].total_records = 0;
    
    return 1;
}

int cdr_open_all_new_fd()
{
    int index;
    
    for(index=0;index<MAX_CDR_APP_NUM;index++)
    {
    	cdr_open_ssn_file(index);
    }
    
    return 1;
}

int cdr_config()
{
    char file_name[128]="./conf/cdr.conf";
    FILE *fp=NULL;
    char s[80],len=0;
    char index=-1;

    memcpy(&cdr_param, &default_param, sizeof(_cdr_param));
    
    fp = fopen(file_name, "r");
    if(fp == NULL)
        return 0;
    
    strcpy(s,"");

    while(fgets(s,80,fp) !=(char *)0)
    {
        if( (int *)strchr(s,'#') !=NULL) continue;
        if( (len= strlen(s))==0 ) continue;
        s[len-2] = 0;
        
        if(!strncasecmp(s,"[global]"))
            continue;
        if(!strncasecmp(s,"system id=",10))
	{
	    cdr_param.system_id = atoi(&s[10]);
	    continue;
	}    
	if(!strncasecmp(s,"base dir=",9))
	{
	    strcpy(cdr_param.base_dir, &s[9]);
	    continue;
	}
	if(!strncasecmp(s,"file suffix=",12))
	{
	    strcpy(cdr_param.file_suffix,&s[12]);
	    continue;
	}
	if(!strncasecmp(s,"max records=",12))
	{
	    cdr_param.max_records_per_file = atoi(&s[12]);
	    continue;
	}
        if(!strncasecmp(s,"max days=",9))
        {
            cdr_param.max_days = atoi(&s[9]);
            continue;
        }
        if(!strncasecmp(s,"[ system",8))
        {
            index++;
            continue;
        }
        if(index<0 || index>=MAX_CDR_APP_NUM) continue;
        
	if(!strncasecmp(s,"ssn=",4))
	{
	    cdr_param.ssn_param[index].ssn = atoi(&s[4]);
	    continue;
	}
	if(!strncasecmp(s,"name=",5))
	{
	    strcpy(cdr_param.ssn_param[index].name,&s[5]);
	}
    }    
    fclose(fp);        
 
    for(index=0;index<MAX_CDR_APP_NUM;index++)
    {
    	cdr_param.ssn_param[index].file_sn = 0;
	cdr_param.ssn_param[index].fd = NULL;
    }
    
    cdr_param.init_flag = 0;
    cdr_open_all_new_fd();
    cdr_param.init_flag = 1;
    
    return 1;
}


int clean_expired_backup_file()
{
    DIR *dp;            
    struct dirent *dirp;
    struct stat fileinfo;
    char name[128];

    if(cdr_param.max_days == 0)
    	return 1;
    
    if((dp=opendir(cdr_param.base_dir))==NULL)
    {
        printf("can't open %s",cdr_param.base_dir);
        return 0;
    }
    while ((dirp=readdir(dp))!=NULL)
    {
	sprintf(name,"%s//%s",cdr_param.base_dir, dirp->d_name);
        stat(name,&fileinfo);        
        
        if(time(NULL)>=(fileinfo.st_mtime+cdr_param.max_days*3600*24) )
        {
            remove(name);    
        }
    }
    closedir(dp);
    
    return 1;
}

/* -------- END of initialisation functions *----*/

/* -------  CDR submit & write file--------------*/

int cdr_submit1(char ssn, unsigned short length, char *data)
{
    int head, tail;
    _cdr_record *ptr=NULL;

    head = cdr_vm_ptr->head_ptr;
    tail = cdr_vm_ptr->tail_ptr;

    ptr = &cdr_vm_ptr->cdr_data[head];
    ptr->ssn = ssn;
    ptr->length = length%CDR_RECORD_SIZE;
    memcpy(ptr->data, data , ptr->length);

   // sem_lock(cdr_sem_id, 1, 1, IPC_NOWAIT);
    cdr_vm_ptr->head_ptr ++;
    if(cdr_vm_ptr->head_ptr>=MAX_CDR_RECORDS)
        cdr_vm_ptr->head_ptr = 0;
/*
    if(cdr_vm_ptr->head_ptr == tail)
    {
        cdr_vm_ptr->tail_ptr ++;
        if(cdr_vm_ptr->tail_ptr>=MAX_CDR_RECORDS)
            cdr_vm_ptr->tail_ptr = 0;
    }
*/
   // sem_unlock(cdr_sem_id, 1, 1, IPC_NOWAIT);

    cdr_counter0++;
    ssn_counter[ssn]++;
    return 1;
}

int cdr_submit(char ssn, unsigned short length, char *data)
{
    int head, tail;
    _cdr_record *ptr=NULL;
    
    head = cdr_vm_ptr->head_ptr;
    tail = cdr_vm_ptr->tail_ptr;
    
    ptr = &cdr_vm_ptr->cdr_data[head];
    ptr->ssn = ssn;
    ptr->length = length%CDR_RECORD_SIZE;
    memcpy(ptr->data, data , ptr->length);
 
   // sem_lock(cdr_sem_id, 1, 1, IPC_NOWAIT);
    cdr_vm_ptr->head_ptr ++;
    if(cdr_vm_ptr->head_ptr>=MAX_CDR_RECORDS)
        cdr_vm_ptr->head_ptr = 0;
/*
    if(cdr_vm_ptr->head_ptr == tail)
    {
        cdr_vm_ptr->tail_ptr ++;
        if(cdr_vm_ptr->tail_ptr>=MAX_CDR_RECORDS)
            cdr_vm_ptr->tail_ptr = 0;
    }
*/
   // sem_unlock(cdr_sem_id, 1, 1, IPC_NOWAIT);
    
    cdr_counter1++;
    ssn_counter[ssn]++;
    return 1;
}

int cdr_get_ssn_index(int ssn)
{
    int i;
    
    for(i=0;i<MAX_CDR_APP_NUM;i++)
    {
        if(cdr_param.ssn_param[i].ssn == ssn)
            return i;	
    }
    return -1;    
}


int cdr_back_record(_cdr_record *ptr)
{
    int index;
    char data[1024];
    
    if(ptr == NULL)
        return 0;
        
    if((index = cdr_get_ssn_index(ptr->ssn))<0)
        return 0;
        
    if(cdr_param.ssn_param[index].fd == NULL)
        return 0;
        
    BcdToAscii(data,ptr->data,(ptr->length%CDR_RECORD_SIZE)*2);
    
    fprintf(cdr_param.ssn_param[index].fd,"%s\n",data);
    cdr_param.ssn_param[index].total_records++;
    
    if(cdr_param.max_records_per_file>0)
    {
    	if(cdr_param.ssn_param[index].total_records>=cdr_param.max_records_per_file)
    	    cdr_open_ssn_file(index);
    }
    
    return 1;
}

int cdr_backup()
{
    int head, tail;
    _cdr_record *ptr=NULL;
    register int loop;
    
    head = cdr_vm_ptr->head_ptr;
      
    for(loop=0;loop<MAX_CDR_PER_CYCLE;loop++)
    {    	
        
        tail = cdr_vm_ptr->tail_ptr;
        if(head == tail)
            break;
            
        ptr = &cdr_vm_ptr->cdr_data[tail];
        //memcpy(ptr, &cdr_vm_ptr->cdr_data, sizeof(_cdr_record));
        
        cdr_back_record(ptr);
        
      //  sem_lock(cdr_sem_id, 1, 1, IPC_NOWAIT);
        cdr_vm_ptr->tail_ptr ++;
        if(cdr_vm_ptr->tail_ptr>=MAX_CDR_RECORDS)
            cdr_vm_ptr->tail_ptr = 0;
      //  sem_unlock(cdr_sem_id, 1, 1, IPC_NOWAIT);
        
      //  if(cdr_vm_ptr->tail_ptr == head)
      //  {
       //     break;
       // }             
    }
    return 1;
}
