/*****************************************************************************
File: stat.c
Author: Salas Lopez, Jorge
Date:   03/01/2005
Description: Statistics for Middle-R.
Invocation:  Nothing
*****************************************************************************/

/*****************************************************************************
   Table of Contents:
   Reusable Functions:
    
   Intern Functions:
    ---
   Includes:
    
   Source code in this file:
    All
*********************************************************************************/

/********************************************************************************
Import Libraries
*********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>
#include "tools.h"
#include "stat.h"

/********************************************************************************
Prototype Functions
*********************************************************************************/


/********************************************************************************
Defines
*********************************************************************************/
/* Log Management */
#define FATAL_DATABASE
#define ERROR_DATABASE
//#define INFO_DATABASE
//#define WARN_DATABASE
//#define DEBUG_DATABASE

/********************
 *  IMPLEMENTATION  *
 *******************/
 //struct DATASTAT *space = NULL;
//struct DATASTAT ****steps;
FILE *pFile;

/* Properties */
#define MAXSTRING 256
char properties[MAXSTRING];
char pattern[MAXSTRING];
int ipos = 0, fpos = 0;
char pattern_stat[MAXSTRING];
char pattern_datastat[MAXSTRING];
int numclients = 1;
int txnperclient = 1;
int initwarmup = 0;
int finishwarmup = 0;
int numtables = 36;
int initial_members = 1;

/* Read from line command */
void setFileProperties(char *filename){
	strcpy(properties, filename);
	//printf("READ FROM FILE: <%s>\n", properties);
}
void setNumClients(int clients){
	numclients = clients;
}
void setReplicas(int replicas){
	initial_members = replicas;
}

/* Read from FileProperties */
void setNumTables(int ntables){
	numtables = ntables;	
}
void setNumTransactions(int transactions){
	if (numclients == 0){
		numclients = 1;
	}
	txnperclient = (transactions*numtables)/numclients;
}
void setWarmup(int init, int finish){
	initwarmup = init;
	finishwarmup = finish;
}
void setPattern(char *pattern_in){
	int i;
	char c;
	char p1[MAXSTRING];
	char p2[MAXSTRING];
	char p3[MAXSTRING];
	
	i = 0;
	c = pattern_in[i];
	while ((c != '\0') && (i<MAXSTRING)){
		//printf("C: <%c>\n", c);
		if ((c == '/') || (c == '\\')){
			ipos = i;
		}
		if (c == '.'){
			fpos = i;
		}
		c = pattern_in[++i];		
	}
	bzero(p1, sizeof(p1));
	bzero(p2, sizeof(p2));
	bzero(p3, sizeof(p3));		
	strncpy(p1, pattern_in, ipos+1);
	strncpy(p2, pattern_in+ipos+1, i-fpos);
	strcpy(p3, pattern_in+fpos);
	
	bzero(pattern_stat, sizeof(pattern_stat));
	strcpy(pattern_stat, p1);
	strcat(pattern_stat, "stat_");
	strcat(pattern_stat, p2);
	strcat(pattern_stat, "_MIDDLER_");
	
	bzero(pattern_datastat, sizeof(pattern_datastat));
	strcpy(pattern_datastat, p1);
	strcat(pattern_datastat, "datastat_");
	strcat(pattern_datastat, p2);
	strcat(pattern_datastat, "_MIDDLER_");
	
	//printf("IPOS: %d <%s>; FPOS: %d <%s> <%s>\n", ipos, p1, fpos, p2, p3);
	//printf("pattern_stat: %s\n", pattern_stat);
	//printf("pattern_datastat: %s\n", pattern_datastat);
}

void getProperties(){
	int transactions = 0;
	int init = 0, finish = 0;
	char pattern_in[MAXSTRING];
	int ntables = 0;
	
	/* Read Properties */
	char prop[MAXSTRING*2];
	char value[MAXSTRING*2];	
  	FILE * fprop;
  	int err;
  	char c;
  	int i = 0, pos = 0;
  	
  	bzero(pattern_in, sizeof(pattern_in));
  	//printf("1 READ FROM FILE: <%s>\n", properties);
  	fprop = fopen (properties, "r");  	
  	err = fscanf (fprop, "%s\n", prop);  	  		
  	while(err != EOF){
  		//printf("PROP<%s>\n", prop);  	
	  	//Adjust Values
	  	i = 0;
		c = prop[i];
		while (c != '\0'){
			//printf("CC[%d] = %c \n", i, c);
			if (c == '='){
				pos = i;
			}
			c = prop[++i];
		}
		strcpy(value, prop+pos+1);
		prop[pos] = '\0';
  		//printf("ROUND: <%d> <%s> <%s>\n", err, prop, value);	
  		if (strcmp(prop, "num_tables") == 0){
  			ntables = atoi(value); 			
  			
  		}else if (strcmp(prop, "file_result") == 0){
  			strcpy(pattern_in, value);
  			
  		}else if (strcmp(prop, "items") == 0){
  			transactions = atoi(value);
  			
  		}else if (strcmp(prop, "init_warmup") == 0){
  			init = atoi(value);
  			
  		}else if (strcmp(prop, "finish_warmup") == 0){
  			finish = atoi(value);	
  		}
  		err = fscanf(fprop, "%s=%s", prop, value);
  	}  	
  	fclose (fprop);
  		 
	setNumTables(ntables); //before setNumTransactions
	setNumTransactions(transactions);
	setWarmup(init, finish);
	setPattern(pattern_in);
	//printf("getProperties()-> <%d> <%s> <%d> <%d> <%d>\n", numtables, pattern_stat, txnperclient, initwarmup, finishwarmup);
}
/********************************************************************************
			ALL FUNCTIONS TO MANAGEMENT DATASTAT
*********************************************************************************/
/** SET **/
void setStartTime(struct timeval time, struct DATASTAT *stat) {
	stat->startTime = time;
	stat->inUse = 1;
}
void setFinishTime(struct timeval time, struct DATASTAT *stat) {
	stat->finishTime = time;
	stat->inUse = 1;
}
void setStatTime(struct timeval starttime, struct timeval finishtime, struct DATASTAT *stat) {
	stat->startTime = starttime;
	stat->finishTime = finishtime;
	stat->inUse = 1;
}

/** GET **/
int isInUse(struct DATASTAT *stat) {
	return stat->inUse;
}

/** IN SECONDS */
struct timeval *getStartTimeInSec(struct DATASTAT stat) {
	if (stat.inUse = 1){
		return &(stat.startTime);
	}
	return NULL;
}
time_t getFinishTimeInSec(struct DATASTAT stat) {
	if (stat.inUse = 1){
		return stat.finishTime.tv_sec;
	}
	return 0;	
}
time_t getDurationInSec(struct DATASTAT stat) {
	if (stat.inUse = 1){
		return stat.finishTime.tv_sec - stat.startTime.tv_sec;
	}
	return 0;	
}

/* IN MICROSECONDS */
time_t getStartTimeInUSec(struct DATASTAT stat) {
	if (stat.inUse = 1){
		return stat.startTime.tv_usec;
	}
	return 0;		
}
time_t getFinishTimeInUSec(struct DATASTAT stat) {
	if (stat.inUse = 1){
		return stat.finishTime.tv_usec;
	}
	return 0;	
}
time_t getDurationInUSec(struct DATASTAT stat) {
	if (stat.inUse = 1){
		return stat.finishTime.tv_usec - stat.startTime.tv_usec;
	}
	return 0;	
}

/********************************************************************************
			ALL FUNCTIONS TO MANAGEMENT ARRAYSTATDATA
*********************************************************************************/
void initStatData(char *filename, int clients, int replicas){
	int s, c, i;		
	for (s = 0; s < NUMSTEPS; s++){               	        	        
	    for (c = 0; c < NUMCLIENTS; c++){
		    for (i = 0/*INITWARMUP*/; i < (ALLTRANSACTIONS/*-FINISHWARMUP*/); i++) {
		       /* Init Steps */		       
		       (steps[s][c][i]).startTime.tv_sec = 0;
		       (steps[s][c][i]).startTime.tv_usec = 0;
		       (steps[s][c][i]).finishTime.tv_sec = 0;
		       (steps[s][c][i]).finishTime.tv_usec = 0;
		       (steps[s][c][i]).inUse = 0;
		       local[s][c][i] = 0;
		    }	    		    	
	    }
	    /* Init Stats */	    
	    (stats[s]).mean = 0;
	    (stats[s]).std = 0;
  		(stats[s]).var = 0;
  		(stats[s]).throughput = 0;  
  		(stats[s]).totaltime = 0;
  		(stats[s]).length = 0;              
	}
	
	bzero(properties, sizeof(properties));
	bzero(pattern, sizeof(pattern)); 
	setNumClients(clients);
	setReplicas(replicas);
	setFileProperties(filename);
	getProperties();
}

struct DATASTAT *getTime(int step, int client, int index) {
    if ((step < NUMSTEPS) &&
    	(client < numclients) && 
        (index < txnperclient+1)) {
        struct DATASTAT *actual = (struct DATASTAT *) &(steps[step][client][index]);
        return actual;
    }
    return NULL;
}

/*void setStartTimeArray(int step, int client, int index, struct timeval times) {    
    if ((step < NUMSTEPS) &&
    	(client < NUMCLIENTS) && 
        (index < ALLTRANSACTIONS)) {
        struct DATASTAT *stat = (struct DATASTAT *) &(steps[step][client][index]);	        
        stat->startTime.tv_sec = times.tv_sec;
        stat->startTime.tv_usec = times.tv_usec;
        stat->inUse = 1;
    }
}

void setFinishTimeArray(int step, int client, int index, struct timeval times) {    
    if ((step < NUMSTEPS) &&
    	(client < NUMCLIENTS) && 
        (index < ALLTRANSACTIONS)) {
        struct DATASTAT *stat = (struct DATASTAT *) &(steps[step][client][index]);	                
        stat->finishTime.tv_sec = times.tv_sec;
        stat->finishTime.tv_usec = times.tv_usec;
        stat->inUse = 1;
    }
}*/

/** STATISTICS  **/
void mean (){	
	int s, c, i;				
	int length = 0;
	double mean = (double) 0.0;	
	double fst_txn_inittime = (double) 0.0;
	double fst_txn_finishtime = (double) 0.0;	
	for (s = 0; s < NUMSTEPS; s++){               
	    mean = 0.0;
	    length = 0;    	        
	    for (c = 1; c <= numclients; c++){
		    for (i = initwarmup+2; i < (txnperclient+2-finishwarmup); i++) {		       
		       if ((steps[s][c][i]).inUse == 1){
		       	if (local[s][c][i] == 1){
		       		//printf("inUse[%d][%d][%d] = %d\n", s, c, i, (steps[s][c][i]).inUse);			       			       
		       		fst_txn_inittime = ((steps[s][c][i]).startTime.tv_sec*1000.0 + ((steps[s][c][i]).startTime.tv_usec/1000.0));
		       		fst_txn_finishtime = ((steps[s][c][i]).finishTime.tv_sec*1000.0 + ((steps[s][c][i]).finishTime.tv_usec/1000.0));    	
		       		mean = mean + (fst_txn_finishtime - fst_txn_inittime);
		       		length++;
		       		if ((fst_txn_finishtime - fst_txn_inittime) > 10000){
		       			printf("inittime[%d][%d][%d] = %.4f\n", s, c, i, fst_txn_inittime);
		       			printf("finishtime[%d][%d][%d] = %.4f\n", s, c, i, fst_txn_finishtime);		       	
		       		}
		       	}else{
		       	}		       	
		       }
		    }	    		    	
	    }
	    stats[s].length = length;
	    stats[s].totaltime = (double) mean;
	    if (length != 0){	    			    	    	
	    	stats[s].mean = ((double) mean) / ((double) ((length)));
	    }else{
	    	printf("ERROR DIV 0\n");
	    	//printf("inUse[%d][%d][%d] = %d\n", 5, 1, 1, (steps[5][1][1]).inUse);
	    	stats[s].mean = 0;
	    }
	    //printf("Mean[%d]=%.4lf | %lf | %d\n", s, stats[s].mean, mean, length); 
	    	    
	}    
}
    
void std_and_var (){               
    int s, c, i;				
	int length = 0;
	double mean = (double) 0.0;
	double var = (double) 0.0;
    double ds = (double) 0.0;
	double fst_txn_inittime = (double) 0.0;
	double fst_txn_finishtime = (double) 0.0;
	struct DATASTAT *actual = NULL;
	for (s = 0; s < NUMSTEPS; s++){               	    
	    length = 0;
	    mean = stats[s].mean;    	        
	    for (c = 1; c <= numclients; c++){
		    for (i = initwarmup+2; i < (txnperclient+2-finishwarmup); i++) {		    	
		       	if ((steps[s][c][i]).inUse == 1){
		       		if (local[s][c][i] == 1){		       	
			       		fst_txn_inittime = ((steps[s][c][i]).startTime.tv_sec*1000.0 + ((steps[s][c][i]).startTime.tv_usec/1000.0));
			       		fst_txn_finishtime = ((steps[s][c][i]).finishTime.tv_sec*1000.0 + ((steps[s][c][i]).finishTime.tv_usec/1000.0));    	
			       		ds = (double) (ds + pow((fst_txn_finishtime - fst_txn_inittime) - mean, 2));
			       		length++;
		       		}else{
		       		}
		       	}
		    }	    		    	
	    }
	    if (length != 0){	    
	    	stats[s].var = ds / (double) ((length));
	    }else{
	    	printf("ERROR DIV 0\n");
	    	stats[s].var = 0;
	    }
    	stats[s].std = (double) sqrt(var);	    
    	//printf("Var[%d]=%.4f\n", s, stats[s].var);
    	//printf("Std[%d]=%.4f\n", s, stats[s].std);
	}         
}

void throughput (){
	int s;						
	for (s = 0; s < NUMSTEPS; s++){               	    
	    if (stats[s].length != 0){
	    	stats[s].throughput = ((((double)stats[s].length) * 1000) / stats[s].totaltime);
	    }else{
	    	printf("ERROR DIV 0\n");
	    	stats[s].throughput = 0;
	    }
	    //printf("Throughput[%d]=%.4f\n", s, stats[s].throughput);    
	}
}

void printStatMiddler(){
	int s, c, i;				
	int length = 0;
	double mean = (double) 0.0;
	double throughput = (double) 0.0;
	double var = (double) 0.0;
	double std = (double) 0.0;    
	double fst_txn_inittime = (double) 0.0;
	double fst_txn_finishtime = (double) 0.0;
      
    fprintf(pFile, "\tmean\tthroughput\tstd\tvar\t\n");   
    for (s = 0; s<NUMSTEPS; s++){
    	mean = stats[s].mean;
		throughput = stats[s].throughput;
    	std = stats[s].std;
    	var = stats[s].var;
    	fprintf(pFile, "\t%f\t%f\t%f\t%f\t\n", mean, throughput, std, var);
    }     
}

void calculateStat(int print){
	//printf("MEAN 1\n");
    mean();
	//printf("MEAN 2\n");
    std_and_var();
   	//printf("MEAN 3\n");
    throughput();
   	//printf("MEAN 4\n");
    if (print == 1){
    	//printf("MEAN 5\n");
        printStatMiddler();
        //printf("MEAN 6\n");
    }    
    //printf("MEAN 7\n");
}

void toFile(){
	char filename[1024];
	char nclients[256];
	char ntx[256];
	int s, c, i;				
	int length = 0;	
	double fst_txn_inittime = (double) 0.0;
	double fst_txn_finishtime = (double) 0.0;	
	char *nodename = NULL;
	static struct utsname node_name;
	
printf("TOFILE\n");	
	uname(&node_name);
  	nodename = strtok(node_name.nodename, ".");
  	
	itoa (numclients, nclients, 10);
	itoa (txnperclient, ntx, 10);		
	sprintf(filename, "%s%s_%d_%d_%s.txt", pattern_stat, nodename, numclients, initial_members, nclients);	
//	printf("FILENAME: %s\n", filename);
	pFile = fopen (filename,"w");                        
    calculateStat(1);
//    printf("FLUSH\n");    
    fflush(pFile);
//    printf("FCLOSE\n");
    fclose(pFile);
//    printf("FCLOSE OK\n");
    
    for (c = 1; c < numclients+1; c++){
    	itoa (c, nclients, 10);
    	bzero(filename, sizeof(filename));		
		sprintf(filename, "%s%s_%d_%d_%s.txt", pattern_datastat, nodename, numclients, initial_members, nclients);
//		printf("FILENAME DATASTAT: %s\n", filename);
		pFile = fopen (filename,"w");
		fprintf(pFile, "--------------- CLIENT %d ---------------\n", c);
	    for (i = 0+2/*INITWARMUP*/; i < (txnperclient+2/*-FINISHWARMUP*/); i++) {
	    	for (s = 0; s<NUMSTEPS; s++){		    	
		       	if ((steps[s][c][i]).inUse == 1){		       	
		       		fst_txn_inittime = ((steps[s][c][i]).startTime.tv_sec*1000.0 + ((steps[s][c][i]).startTime.tv_usec/1000.0));
		       		fst_txn_finishtime = ((steps[s][c][i]).finishTime.tv_sec*1000.0 + ((steps[s][c][i]).finishTime.tv_usec/1000.0));    	
		       		if (s == 0){
//printf("UNO\n");		       			
		       			fprintf(pFile, "%d\t%f\t", i, (fst_txn_finishtime-fst_txn_inittime));
		       		} else if (s == NUMSTEPS-1){
		       			fprintf(pFile, "%f\n", (fst_txn_finishtime-fst_txn_inittime));
//printf("DOS\n");		       			
		       		} else {
		       			fprintf(pFile, "%f\t", (fst_txn_finishtime-fst_txn_inittime));
//printf("TRES\n");		       			
		       		}
		       		length++;
		       	}
	    	}
	    }
	    printStatMiddler();
	    
	    fflush(pFile);
    	fclose(pFile);	    		    	
    }      
    printf("TOFILE OK\n");				
}

void initStatDataOLD(){
	//int s, c, i, diff;
	//struct DATASTAT *actual = NULL;
	//struct DATASTAT *space = NULL;    
//printf("1\n");
    /* first we set aside space for the array itself */
    //space = (struct DATASTAT*) malloc(NUMSTEPS * NUMCLIENTS * ALLTRANSACTIONS * sizeof(struct DATASTAT));
//printf("1\n");
    /* next we allocate space of an array of pointers, each
       to eventually point to the first element of a
       2 dimensional array of pointers to pointers */
    //steps = (struct DATASTAT ****) malloc (NUMSTEPS * sizeof(struct DATASTAT ***));
//printf("1\n");
    /* and for each of these we assign a pointer to a newly
       allocated array of pointers to a row */
    //for (s = 0; s < NUMSTEPS; s++)
    //{
//printf("1 %d\n", s);
        //steps[s] = (struct DATASTAT ***) malloc (NUMCLIENTS * sizeof(struct DATASTAT **));
//printf("1 %d\n", s);
        /* and for each space in this array we put a pointer to
           the first element of each row in the array space
           originally allocated */
        //for (c = 0; c < NUMCLIENTS; c++)
        //{
//printf("1 %d %d\n", s, c);        	
            //steps[s][c] = (struct DATASTAT **) malloc (ALLTRANSACTIONS * sizeof(struct DATASTAT *));
            
            //space + (s*(ALLTRANSACTIONS * NUMCLIENTS) + c*ALLTRANSACTIONS);
            //for (i = 0; i < ALLTRANSACTIONS; i++){
            	//steps[s][c][i] = (struct DATASTAT *) malloc (sizeof(struct DATASTAT));
            	//space + (s*(ALLTRANSACTIONS * NUMCLIENTS) + c*ALLTRANSACTIONS + i*(sizeof(struct DATASTAT)));
            //}
//printf("1 %d %d\n", s, c);            
        //}
    //}

    /* And, now we check each address in our 3D array to see if
       the indexing of the Arr3d pointer leads through in a
       continuous manner */

/*    for (s = 0; s < NUMSTEPS; s++)
    {
        printf("Location of array %d is %p\n", s, *steps[s]);
        printf("sizeof struct %d\n", sizeof(struct DATASTAT));
        for ( c = 0; c < NUMCLIENTS; c++)
        {
        	for (i=0; i<ALLTRANSACTIONS; i++){
	            printf("  Array %d and Row %d %d starts at %p", s, c, i, steps[s][c][i]);
	            diff = sizeof(steps[s][c][i]);
	            printf("    diff = %d  ",diff);
	            printf(" z = %d  y = %d\n x = %d", s, c, i);
        	}
        }
    }
*/	
	//struct DATASTAT steps[NUMSTEPS][NUMCLIENTS][ALLTRANSACTIONS];						
	/*steps = (struct DATASTAT *) calloc (sizeof(void *), NUMSTEPS);
	for (s = 0; s < NUMSTEPS; s++){
		steps[s] = (void *) calloc (sizeof(void *), NUMCLIENTS);
		for (c = 0; c < NUMCLIENTS; c++){
			steps[s][c] = calloc (sizeof(struct DATASTAT), ALLTRANSACTIONS);
		} 
	}*/
/*printf("2\n");	
	for (s = 0; s < NUMSTEPS; s++){               	        	        
	    for (c = 0; c < NUMCLIENTS; c++){
		    for (i = 0INITWARMUP; i < (ALLTRANSACTIONS-FINISHWARMUP); i++) {
printf("2 %d %d\n", s, c);		    	
		       //actual = *steps[s][c][i];
		       steps[s][c][i]->startTime.tv_sec = 0;
		       steps[s][c][i]->startTime.tv_usec = 0;
		       steps[s][c][i]->finishTime.tv_sec = 0;
		       steps[s][c][i]->finishTime.tv_usec = 0;
		       steps[s][c][i]->inUse = 0;
printf("2 %d %d %d\n", s, c, i);		       
		    }	    		    	
	    }	    
	}*/
}
