/* Written by Abdy Abhari , June 2009                           */
/* This program should be used only for research                */
/* or educational purposes with proper citation to the paper    */
/* A. Abhari, M. Soraya, Workload Generation for YouTube,       */ 
/* Multimedia Tools and Applications journal, June 2009         */ 
/* It generates YouTbe variants and can be compiled in linux as */
/* gcc -lm  youtubeworkld.c                                     */


#include <stdlib.h>
#include <math.h>
#include <assert.h>
#include <stdio.h>
#include <time.h>               /* for seeding random generator */

int N=50000;
int maxrelated=6;
int maxclientsession =6;

void popularweeklydb(int i);
void populardailydb(int i);
void regulardb(int i);
int getRandomInt(int minval, int maxval);
int clientsession(int i);
int selectedvideo(int pos);
double weibull(float alpha, float beta, float gamma);
double weibull2 (double alpha, double beta);
double log_logistic(double alpha, double beta);

typedef struct
{
  	int FileSize;
  	int ViewCount ;
  	int Duration ;
  	int AvgRating ;
  	int RatingCount ;
  	long SelectionProb ;
  	int relatedvideos;
  	int * ChildPointer;
  } 
video;
video * video_list ;

/* main */
main()
{
	int i,j;
	float alpha= 0;
	float beta= 0;
	float gamma=0; // it is location parameter with setting to 0 it will be two parameter
          /*
           * Generate the object sizes
          */
          srandom((long)getpid()); /* seed for random */
          srand48((double) getpid()); /* is uniform */
           video_list = (video *) malloc (N  * sizeof (video));

           for(i = 0; i < N; i++) 
	 {
		/* create database  daily */
  	         populardailydb(i);     
           }
           i= getRandomInt(0,N-1);
           j=1;
           while (j<2000) /*client number*/
           {
		i= clientsession(i);
                 printf("%d %d %d \n",j, video_list[i].FileSize,i);
                 j++; 
            }
 
} 

void popularweeklydb(int i)
{
 	 int j;
  	float alpha= 0;
  	float beta= 0;
  	float gamma=0;                          /* it is location parameter with setting to 0 it will be two parameter*/
         alpha =1.13 ; beta = 11212;     /* file size */
         video_list[i].FileSize= weibull2(alpha,beta);
         alpha =2.05 ; beta = 195492;  /* view count */
         video_list[i].ViewCount = log_logistic(alpha,beta);
         alpha =1.13 ; beta = 246.07;   /* Duration */
         video_list[i].Duration = weibull2(alpha,beta);
         alpha =4.73 ; beta = 4.25;        /* AvgRating */
         video_list[i].AvgRating = weibull2(alpha,beta);
         alpha =0.75 ; beta = 668;         /* RatingCount */
         video_list[i].RatingCount = weibull2(alpha,beta);
         if (video_list[i].Duration > 5 )   /* partial size  play back */
              video_list[i].FileSize = (5* video_list[i].FileSize)/video_list[i].Duration; 
         if (i==0)
              video_list[i].SelectionProb= video_list[i].ViewCount;
        else
              video_list[i].SelectionProb=video_list[i].ViewCount +
              video_list[i-1].SelectionProb ;
        video_list[i].relatedvideos =getRandomInt(0,maxrelated);
        video_list[i].ChildPointer = (int *)
        malloc(video_list[i].relatedvideos * sizeof (int));
        for (j=0;j<video_list[i].relatedvideos;j++)
               video_list[i].ChildPointer[j] = getRandomInt(0,N-1);
}

void populardailydb(int i)
 {
  int j;
  float alpha= 0;
  float beta= 0; 
  float gamma=0; // it is location parameter with setting to 0 it will be two parameter

		  alpha =1.14 ; beta = 11193;      /* file size */
                  video_list[i].FileSize= weibull2(alpha,beta);
                  alpha =2.32 ; beta = 30149;         /* view count alpha changed from 2.32 */
                  video_list[i].ViewCount = log_logistic(alpha,beta);
                  alpha =1.13 ; beta = 278.03;        /* Duration */
                  video_list[i].Duration = weibull2(alpha,beta);
                  alpha =3.63 ; beta = 4.44;             /* AvgRating */
                  video_list[i].AvgRating = weibull2(alpha,beta);
                  alpha =0.62 ; beta = 148;              /* RatingCount */
                  if (video_list[i].Duration > 5 )       /* partial size  play back */
                    video_list[i].FileSize = (5* video_list[i].FileSize)/video_list[i].Duration; 
                  video_list[i].RatingCount = weibull2(alpha,beta);
                  if (i==0)
                     video_list[i].SelectionProb= video_list[i].ViewCount;
                  else
                     video_list[i].SelectionProb=video_list[i].ViewCount +
                                    video_list[i-1].SelectionProb ;
                 video_list[i].relatedvideos =getRandomInt(0,maxrelated);
                 video_list[i].ChildPointer = (int *)
                  malloc(video_list[i].relatedvideos * sizeof (int));
                 for (j=0;j<video_list[i].relatedvideos;j++)
                     video_list[i].ChildPointer[j] = getRandomInt(0,N-1);
 }

void regulardb(int i)
 {
  int j;
  float alpha= 0;
  float beta= 0;
  float gamma=0; // it is location parameter with setting to 0 it will be two parameter
                 
                  alpha =2.19 ; beta = 7794;       /* file size */
                  video_list[i].FileSize= weibull2(alpha,beta);
                  alpha =0.55 ; beta = 290130;   /* view count */
                  video_list[i].ViewCount = weibull2(alpha,beta);
                  alpha =2.54 ; beta = 226.54;    /* Duration */
                  video_list[i].Duration = log_logistic(alpha,beta);
                  alpha =15.95 ; beta = 4.73;       /* AvgRating */
                  video_list[i].AvgRating = weibull2(alpha,beta);
                  alpha =0.52 ; beta = 629.24;     /* RatingCount */
                  video_list[i].RatingCount = weibull2(alpha,beta);
                  if (i==0)
                     video_list[i].SelectionProb= video_list[i].ViewCount;
                  else
                     video_list[i].SelectionProb=video_list[i].ViewCount +
                                    video_list[i-1].SelectionProb ;
                 video_list[i].relatedvideos =getRandomInt(0,maxrelated);
                 video_list[i].ChildPointer = (int *)
                  malloc(video_list[i].relatedvideos * sizeof (int));
                 for (j=0;j<video_list[i].relatedvideos;j++)
                     video_list[i].ChildPointer[j] = getRandomInt(0,N-1);
 }
        
int getRandomInt(int minval, int maxval)
{
        return random() % (maxval-minval+1)+minval;
}

int clientsession(int i)
{
	int j,maxsession;
	maxsession = getRandomInt(1,maxclientsession); 
	for (j=1; j<= maxsession; j++)
	{  
 		i=selectedvideo(i);
 		printf("  %d %d %d %d %d %d %d %d %d \n",  i,
                  video_list[i].FileSize,
                  video_list[i].ViewCount, video_list[i].Duration ,
                  video_list[i].AvgRating, video_list[i].RatingCount,
                  video_list[i].SelectionProb,video_list[i].relatedvideos,video_list[i].ChildPointer[0]);                
          }
}

int selectedvideo(int pos)
 {
  	int i,j;
  	long k;
  	long relatedvcount[maxrelated];
	for (i=0;i<maxrelated;i++)
   		relatedvcount[i]= 0;
	if (getRandomInt(0,1)== 1)  
 	  {
  		   k = getRandomInt(0,video_list[N-1].SelectionProb);
    		   i=0;  
     		   while (k > video_list[i].SelectionProb)
        			i++;  
                      return(i);
	  }
          else 
	  {  
		/* related videos */
   		if (video_list[pos].relatedvideos > 0)
    		{
			relatedvcount[0]= video_list[video_list[pos].ChildPointer[0]].ViewCount ;
   		          for (j=1;j < video_list[pos].relatedvideos; j++)
                                     relatedvcount[j]=video_list[video_list[pos].ChildPointer[j]].ViewCount + 
                                     relatedvcount[j-1];
    			 k = getRandomInt(0,relatedvcount[j-1]);
     			 i=0;
    			 while (k> relatedvcount[i])
    			          i++; 
                            return(video_list[pos].ChildPointer[i]);
		}
            } 
}

double weibull2 (double alpha, double beta)
{
        float u=0; 
        double i; 
        u = (float)drand48();                /* do not need seed */
        i=  pow(-log(u),1/alpha);        /* it is uniform so 1-u = u */
        i= beta * i ;
        return(i);
}

double log_logistic(double alpha, double beta)
{
        float u=0;
        double i;
        u = (float)drand48();
        i=  pow(u/(1-u),1/alpha);
        i= beta * i ;
        return(i);
}