/*
 *  $Id: CDAgent_ag2672.java,v 1.3 2008/07/08 03:36:51 nemo Exp $
 * 
 * Copyright (c) 2008, Nemo Semret.
 * 
 * Your agent must implement this interface. All the constants of the
 * game are set here as well. Do not hardcode the constants in your
 * agent. You should refer to them as these static variables. Some of
 * these values may change in the final run so you must design your
 * algorithm for the general case.
 */
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 CDAgent_ag2672 implements CDNAgent {

    /******************* Variables I have included ********************************/

    /* bk is the array  that holds the number of users that  uses network bandwidth*/
    public long[] bk;
    /* ck is the array  that holds the number of users that  uses the cache*/
    public  long[] ck;
    /* day_counter is used to indicate the current day */
    public  int day_counter = 0;
    /* ak is the array of boolens that will be returns tellling us which networks will need cache */
    public  boolean[] ak;
    /* avg_N is an array that contains the avg N for every network for a given day*/
    public  double[] avg_N; // FIXME: unnecessary array you are just updating day_N locally anyway
    /* day_N is the array that contains the N value for evey day */
    public  double[] day_N;
    /* expected congestion is the array the save 0 if no congestion or the loss due to congestion*/
    public  double[] expected_cong;

    public CDAgent_ag2672 () {
	bk = new long[K];
	ck = new long[K];
	ak = new boolean [K];
	avg_N = new double [K];
	day_N = new double [1000]; 
	expected_cong = new double[K];
	for (int k = 0; k < K; k++) {
	    ak[k] = true;
	}
    }

    /**  Coded By Abdulhamid Ghandour
     *  UNI: ag2672
     * Submitted May-19-2008
     * The function startDay will take the input X in Gbytes. In the beginning
     * i will estimate N for evey Network and find an average for the day.
     * Then i will Find the N for that day by averaging the estimated N over
     * all previous day and will use that N later on.  Then using the values of
     * C (capacity) and bk, i can predict if there is congestion in a network
     * or not, and that will help me in some cases.  No i check, If i
     * previously cached on a network and the netork gave me positive revenue,
     * then i stay cache it, else i will stop caching.  On the other had If i
     * didnt previously cache, but i know that someone is caching, i check if
     * sharing the users using cache by adding a cache will give positive
     * revenue, then I will cache, else i will not add a cache.  Also is no one
     * is caching, including me, then if my revenue is a bit better than the
     * congestion loos, i will cache, else i won't cache.  */
    public boolean[] startDay(long X)
    {
	// FIXED: always cache first round or else N remains zero throughout and never cache
	if (day_counter == 0) {
	    for(int j = 0; j < K; j++) {
		ak[j] = true;
	    }
	    day_counter++;
	    return ak;
	}

	int    N_counter =0;
	int    avg_users= 10000;
	double N_total = 0;
	double N = 0 ;
	double current_N_tot = 0;
	double CACHE_COST = (Sc + Pc * X/1073741824.0); // FIXED
	
	/*try to find N from every network that we had used a cache in it using the value bk*/
	for(int j = 0; j < K; j++)
	    {
		if ( ak[j] == true && bk[j]>0){
		    /*if we cached in that network, then our bk is on avergve  1/N *( 1-q) *avg_user   */
		    avg_N[j]= (avg_users * (1-q))/bk[j];
		    /* we add these N we estimated for every network for that day */
		    N_total = N_total + avg_N[j]; 
		    N_counter++;
		}
		else
		    avg_N[j]=0;
	    }
	/*this will calculate the Avg N for that day and will store it in day_N array */
	if (N_counter>0) { //FIXED
	    day_N[day_counter] = (N_total / N_counter);
	} else {
	    day_N[day_counter] = day_N[day_counter - 1];
	}
	/*Encrement the day counter*/
	day_counter++;
	
	/*this will add the N values for all previous day */
	for(int r = 0; r < day_counter; r++)
	    current_N_tot = current_N_tot + day_N[r];
		
	/*and this N will be the average over all days  and round it */
	N = Math.round(current_N_tot / day_counter);

	for (int t = 0; t < K; t++){
	    expected_cong[t] = 0;
	    /* if the capacity c is small, then congestion happens and we lose
	     * some resources the expected_cong arry will have zero if no
	     * congestion is predicted or it will have *a negative value
	     * crosponding to the loss of mony on bandwidth */
	    if (C[t]*60*60*24*1000000 < X*8*bk[t]*N) // FIXED Gbyte -> byte
		expected_cong[t] = -Pb*bk[t]*X/1073741824.0;
	}

	for(int i = 0; i < K; i++){
	    /*if the previuos day, i have chached this network then */ 
	    if ( ak[i] == true ){
		/* this is if caching gave me positive revenue  then keeep caching else,stop caching*/
		if ( (ck[i] * V) > CACHE_COST)
		    ak[i] = true; 
		else
		    ak[i] = false;
	    }				
	    /*the other case, if previously i didnt cache, then i can cache if
              i can make revenue doing so */
	    else{
		/* this is if i am getting a low value which means someone is
                   caching then i check if cache will make me better of, then i
                   will cache*/
		if ( bk[i] < (avg_users * (1-q) /(N*2) )){ // FIXED: 2 is in denominator
		    /*estimate my ck[i] as 10000 /(1+N/3) assuming that N/3
		     *will be caching if using this estimation we can see that
		     *caching will give us positive revenue then we cache*/
		    if ( (avg_users * q * V/(1+N/3)) > CACHE_COST ) 
			ak[i] = true;
		    else 
			ak[i] = false;		
		}
		else{ /*this mean that my bk[i] is high which implies that no
                        one is caching, thus i should cache if it gives
                        positive revenue taking into acount congestion*/
		    if (avg_users * q * V > CACHE_COST + expected_cong[i])
			ak[i] = true;
		    else
			ak[i] = false;
		}
	    }
	}	

	return ak;
    }

    public void endDay(long[] b, long[] c)
    {   
	/* at the end og the day, the arrays contains the number of users for
           each network will be given and saved to arrays bk and ck*/
	bk = b;
	ck = c;
    }
}
