/* 
 * Copyright (c) 2008, Can ILHAN.
 * 
 * This agent tries to find whether caching strategy (against not caching) will
 * maximize his/her utility for * content delivery game. Assumes that system is
 * calling startDay function with the calculated random X value (in Gb's) * and
 * will get a boolean array which has length K. The algorithm of the startDay
 * is commented step by step. I added some * more global variables but I assume
 * the statistics of X and Dk is not changing ( mean is 1Gb and 10.000users
 * with power law/exponential dist).  * The endDay function is called by the
 * system with parameters Ck and Bk. I use those values to estimate the number
 * of users (see function for details) * and check any congestion has appeared
 * using some thresholds after investigating the distribution of Dk. If there
 * is any congestion, the utility that * I lost is written into an array so I
 * can use it for evaluating whether to cache or not when no one is caching.
	
* Without the package for system files, I couldnt able to run so there may need
* some addit[ions to the code to make it compatible with interface function
	
 */
package edu.columbia.ee.e6773;

/**
 * Interface for player agent representing Information Provider in Content Delivery Game.
 * http://www.ee.columbia.edu/~nemo/teaching/Content_Delivery_Game.html
 * @author Nemo Semret
 */
public class CDNAgent_ci2137 implements CDNAgent {
    //Global arrays for assigning b and c
    public long[] bk;
    public long[] ck;
    //Number of users in the game (4 as a min. starting point)
    public double N = 4;
    //Counter for day iteration
    public int dayCount = 0;
    //Variable for predicting the number of users
    public double predictN = N*K;
    //Needed for converting predictN (aggregated value) into N for averaging
    public int countPredict = K;
    //Making X global to use it in endDay function
    public long GlobalX;
    //Array calculated at the end of the day holding the loss from congestion (if there is, 0 otherwise)
    public double[] CongestionLoss;
    //boolean array (size K) that will contain 1 or 0's depending on what the algorithm produces
    public boolean[] ak;

    public CDNAgent_ci2137() {
	ak = new boolean[K];
	CongestionLoss = new double[K];
	bk = new long[K];
	ck = new long[K];
    }

    /**
     * At the beginning of each day, the system generates today's
     * value of X and gives it to each of the players. X is random iid
     * with distribution F(x) = 1 - P (X >x) = 1- (x_min/x)^2, for x
     * >= xmin, and 0 otherwise, with x__min = 0.5 Gbytes = 536870912 bytes.
     *
     * @param the value of X in bytes
     * @return a boolean action vector representing his decisions to
     * cache (k-th element is true iff this provider decided to cache
     * in network k)
     */
    public  boolean[] startDay(long X)
    {
	//So that I can access in endday function
	GlobalX = X;
		
	//Incrementing the number of days
	dayCount++;
		
	//cost of caching with given X and Sc values for any network
	double costCaching = (Sc + Pc*X/1073741824.0);  // FIXED: $/Gbyte

	//For each network, go over the algorithm and see whether it is a wise choice to cache or not
	for(int i = 0; i < K; i++)
	    {	
		//True If I did cache in the prev. day for given network
		if ( ak[i] == true )
		    {
			if ( ck[i]*V < costCaching )
			    {
				ak[i] = false; //don't cache there since I lost money
			    }
			else
			    ak[i] = true; //else continue caching (like gambling)
		    }
			
		//I didn't cache there yesterday...
		else
		    {
			//True if at least one player is (probably) caching. My
			//threshold for that is 4000/N because: I am assuming
			//Dk is between 4000-20000 (%55 prob.) Can not make it
			//cover larger space since threshold will collide (for
			//instance: for N=4, if no one is caching, 1000-5000
			//will download from me and if someone is caching
			//200-1000 will download from me. Thats why 1000 is the
			//boundary for deciding dk = 4000-20000 range (assuming
			//10000 is mean)).
			if ( bk[i] < 4000/N )  // someone was caching yesterday
			    {
				if ( 0 < (10000/(N/3))*q*V - costCaching ) // FIXED: divide by N/3 not multiply
				    // someone was caching (assuming 1/3rd of
				    // other guys on average) but maybe caching
				    // still makes sense
				    ak[i] = true;
				else
				    ak[i] = false;
			    }
			else //no one is caching there (assumption) including me
			    {
				//what happens if I start caching, do I earn
				//more by caching?  if so, use that advantage
				//and cache (assuming other players are not
				//trying the same strategy) if there was
				//congestion it will make this if case more
				//relaxed thats why adding the congestionloss
				//cause most probably it will end the
				//congestion problem
				if ( 10000*q*V > costCaching + CongestionLoss[i] )
				    ak[i] = true; 
			    }				
		    }
	    }
	return ak;
    }

    //Function for getting the number of users that uses my cache and download service as well as calculating 
    //the number of players and congestion case ( if so, saves the loss from congestion to global array )
    public void endDay(long[] b, long[] c)
    {
	//At the end of the day, I am saving the number of users that has used my service via downloading or caching
	bk = b;
	ck = c;
		
	for (int k = 0; k < K; k++)
	    {
		if ( ck[k] != 0 || bk[k] < 2000/N )
		    //I cached there today, guaranteed to have 1-q ratio of
		    //Dk/N has downloaded from me or someone else probably
		    //cached using a more strict threshold
		    {			
			predictN += (10000*(1-q)/bk[k]); // FIXED: 10.000 -> 10000
			countPredict++;
		    }
	    }
	N = Math.round(predictN/countPredict);
	//Try to see which links are congested and how much I am losing there
	//if it is higher than expected gain/loss comparing to caching, next day I can cache there
	for (int k = 0; k < K; k++)
	    {
		CongestionLoss[k] = 0; //reset to zero in the beginning
		if ((C[k]*60*60*24*1000000)/8 < GlobalX*N*(bk[k]))  // FIXED: Gbytes -> bytes
		    {//congestion case 
			CongestionLoss[k] = -(GlobalX/1073741824.0)*Pb*bk[k]; //save the loss // FIXED: $/Gbyte
		    }
	    }
    }
}
