#include <sys/time.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <stdint.h>
#include <math.h>             // Needed for log()
#include <assert.h>             // Needed for assert() macro
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#define  FALSE          0       // Boolean false
#define  TRUE           1       // Boolean true
#define MAX_THREADS     380
#define NUM_TOT_CONTENT 1000

void *ccn_func( void *ptr );
void *cancel_thread();

uint32_t
get_time()
{
	struct timeval  tv;
	struct timezone tz;
	struct tm      *tm;
	uint32_t         start;

	gettimeofday(&tv, &tz);
	tm = localtime(&tv.tv_sec);

	start = tm->tm_hour * 3600 * 1000 + tm->tm_min * 60 * 1000 +
		tm->tm_sec * 1000 + tv.tv_usec / 1000;

	return (start);

}


pthread_t thread[10000];
uint32_t thread_start_times[10000];
uint32_t thread_status[10000];//0 not init, 1 executing, 2 exited
FILE *file;

struct thread_args
 {
    char req_msg[250];
    int num;
    int n_seq;
};
int count_retry;
int num_req_content;

int main(int argc ,const char* argv[]) {

	int index;
	int count;
	int rc;
	int threshold;
	int n_req;
	int i;
	int start;
	int stop_simulation;
	int index_thread_status;
	uint32_t sim_start;  //simulation start
	uint32_t sim_stop;   //simulation stop


       if (argc < 4){
                printf("too few arguments---\n enter:\n number of content to dowload concurrently\n total number of content to request\n start point\n");
                exit(1);
        }

        if (argc > 4){

                printf("too few arguments---\n enter:\n number of content to dowload concurrently\n total number of content to request\n start point\n");
     		exit(1);
        }


	start =0;
	count_retry=0;

	pthread_attr_t attr;
	pthread_attr_init(&attr);
   	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	memset(thread_start_times,0x00,10000);
	memset(thread_status,0x00,10000);

	threshold = atoi(argv[1]);
	num_req_content = atoi(argv[2]);
	start = atoi(argv[3]);

	n_req=1;

	file = fopen("/home/andrea/ccn/workload/time.txt","w");
	fclose(file);
	file = fopen("/home/andrea/ccn/workload/time.txt","a+"); /* apend file (add text to */

	sim_start = get_time();

	while(n_req <= num_req_content){

		index=0;
		count =0;

		struct thread_args *Structthread =(struct thread_args*) malloc(sizeof(struct thread_args));
		for (i = 0; i < num_req_content;i++){
			if (thread_status[i]==1)
			count ++;
		}
		
				
		if (count <threshold){

			sprintf (Structthread->req_msg,"ccncatchunks2 -s -p 4 ccnx:/pippo%d.ccn > /dev/null",n_req+start);
			Structthread->num = n_req+start;
	      		Structthread->n_seq = n_req-1; 

			rc = pthread_create( &thread[n_req], &attr, ccn_func, (void*) Structthread);
	      		if (rc) {
              			printf("ERROR; return code from pthread_create() is %d\n", rc);
				thread_status[n_req-1]=3;
              		}	
	 
			//if thread is created correctly stop it after 30 seconds
	      		else{
				thread_start_times[n_req-1]=get_time();
				thread_status[n_req-1]=1;
				n_req++;
			}
			if(n_req <=threshold)
				usleep(50000);
			else
				usleep(50000);
		}	
		else{
			usleep(100000);
		}
	}
	stop_simulation =0;
	while(stop_simulation == 0){
		stop_simulation = 1;
		for(index_thread_status = 0; index_thread_status < num_req_content ; index_thread_status ++){		
			if (thread_status[index_thread_status]==1){
				stop_simulation = 0;
				sleep(1);
				break;
			}
		}	

	}
	sim_stop = get_time();
	return(1);
}
void *ccn_func( void *ptr)
	{
	      int num;
	      int seq;
	      uint32_t time_start;
	      uint32_t time_stop;
	      char *message;
	      struct thread_args *args = (struct thread_args *)ptr;
	      int res=65280;
	   
	      message = args->req_msg;
	      num = args->num;
	      seq = args->n_seq;
 
	      pthread_detach( thread[seq]);

	      time_start = get_time();
	      while(res==65280){
		res = system(message);
		if(res==65280){
			usleep(1500000);
			count_retry++;
			printf("RETRY: %d, tot:%d \n",num,count_retry);
		}
	      }
	      time_stop = get_time();

	      fprintf(file,"%d	%d	%d	%d	%d\n",seq,num,time_stop-time_start,time_start,time_stop);
	      fflush(file);
	      thread_status[seq]=2;
	      return(NULL);
	}

void *cancel_thread(){

	int index;
	int count;
	while(thread_start_times[num_req_content-1]==0){
		index=0;
		count =0;
		while(thread_status[index]!=0){	
			if(thread_start_times[index]!=0 &&
		   		get_time()-thread_start_times[index]>30*1000 &&
		    		thread_status[index]==1){

					pthread_cancel(thread[index]);
					printf("start:%d,now:%d CANCEL\n",thread_start_times[index],get_time());
					thread_status[index]=2;
			}
			else if (thread_status[index]==1){
				count ++;	
			}
			index++;
			//printf("ATTIVI: %d\n",count);
		}
	sleep(1);
	}
	sleep(10);
	return(NULL);
}
