/*
 *  $Id: Xavier.java,v 1.5 2008/07/06 23:45:46 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;

import java.util.Random;

/**
 * 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 Xavier implements CDNAgent {
    /*set day counter to zero*/
    public int day = 0;
    int randnum = 0; // FIXED: moved randnum to instance variable

    public double N_g = 0;
    public long[] bi;
    public long[] ci;
    public long X;

    /**
     * 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)
    {
        boolean [] a_i;
        Random rand = new Random(System.currentTimeMillis());
        a_i = new boolean [K];
	double Thresh = 0.0;
        long sum_bik=0;
        long sum_cik=0;
        int D_g=1200;
        int i;
        for (i=0;i<K;i++)
            {
                a_i[i]=false;
            }
        /*this is the day counter, which will be used to know which day it is. 
         * This counter will be important for the determination of a decision of
         * how to change, or not the strategy. In a way, it will serve as a type
         * of memory with other variables.
         */
        day += 1;
        if(day==1)
            {
                /*Here, a integer random variable is generated from 1 - K so that I
                 * choose randomly a network to cache on the first day, and i cache
                 *it. This is done to at least know that one network is cached, and
                 * to be able to guess "N", the amount of players in the system
                 * using the amount of recieved b in the next day, since we know for
                 * sure that in this cached network we will have (1-q)*Dk in the
                 * next day. I also proposed to some players that we be 
                 *smart about this, and to get a better "N", and we openly establish 
                 *which networks we were going to cache, but they thought that this
                 * could be considered as cheating. I thought this as a sort of alliance,
                 * but in the end, the player who i proposed this to did not agree.
                 */
                randnum = rand.nextInt(K);
                a_i[randnum]=true;
                return a_i;
            }
        if(day==2)
            {
                /*Here we check the previously cached network, the be parameter to 
                 * try to guess N, to see if we can establish a criterium for caching
                 * all the networks or not. Since the difference between one player
                 * and the others only is given by the decision to cache or not,
                 * this would be the only advantage a player can have over any other
                 * . So, I established a criterium to try to take that decision or
                 * not. "N_g" represents the guessed "N" and a threshold is set
                 * using the values of using the cache, compared to the value of 
                 * price per user. 
                 *
                 * This Threshold parameter is derived from using the result of
                 * the reward, dependent on the users who use the cache (In the
                 * worst case, that is when all users cache a network), and the
                 * price of the cache. 
                 */
                N_g=(10000*(1-q))/bi[randnum]; // FIXED: q -> 1-q
                Thresh=((Pc*X/1073741824.0+Sc)*N_g)/(V*q);
                /*"D_g" is a parameter that represents the minimum amount of people
                 * possible in a network, that makes the network worth caching.
                 * In this case, if Thresh is greater than D_g then It is not worth
                 * Caching.
                 */              
                if(Thresh>=D_g) 
                    {
                        for(i=0;i<K;i++)
                            {
                                a_i[i]=false;
                            }
                        return a_i;
                    }
                /*Similarly, if D_g is less than the threshold, this means that 
                 * the system is profitable at a given level of users. It is chosen
                 * low (1200) so that If it is profitable at a low level of users,
                 * then it will be worth caching, since a higher number of users
                 * makes the scheme more profitable.
                 * */
                if(Thresh<D_g)
                    {
                        for(i=0;i<K;i++)
                            {
                                a_i[i]=true;
                            }
                
                    }
                return a_i;
            }
        /* The main idea now is to use the cached vector ck to determine the N
         * with more samples of bk, in this case in day 2, if we cached, we 
         * cache all the networks.
         * 
         * If no networks were cached in day 2, then in day 3, no networks will
         * be cached either
         */
        if(day==3)
            {
		sum_cik = 0; //FIXED
		sum_bik = 0;
                for(i=0;i<K;i++)
                    {
                        sum_cik += ci[i]; //FIXED
                    }
                if(sum_cik!=0)
                    {
                        for(i=0;i<K;i++)
                            {
                                sum_bik+=bi[i];   
                            }
			N_g=(10000*q)/((((10000*q)/N_g)+(sum_bik))/(K+1));
			//FIXME: the above should probably be
			//N_g=10000/(10000*q/N_g+(sum_bik/K));
                        Thresh=((Pc*X/1073741824.0+Sc)*N_g)/(V*q);
                        if(Thresh >= D_g) // FIXED
                            {
                                for(i=0;i<K;i++)
                                    {
                                        a_i[i]=false;
                                    }
                                return a_i;
                            }
                        if(Thresh < D_g)
                            {
                                for(i=0;i<K;i++)
                                    {
                                        a_i[i]=true;
                                    }
                                return a_i;
                            }
                    }
                if(sum_cik==0)
                    {
                        for(i=0;i<K;i++)
                            {
                                a_i[i]=false;
                            }
                        return a_i;
                    }
            }
        /* After day 3, the system will be deemed profitable or not, since for
         * these conditions to hold in a profitable case, it is highly
         * improbable that a unprofitable scenario will trigger the cache in any
         * of the previous days, since only highly profitable scenarios of 
         * (high parameters of "V", or lower values of "Sc" and/or "Pc") 
         * the network. So, if it is profitable up to day 3, it will keep on
         * being profitable to cache after day 3 (meaning all networks will be
         * cached from this day on). Otherwise, the networks will not be cached
         * after this point.
         */ 
        if(day>3)
            {
		Thresh=((Pc*X/1073741824.0+Sc)*N_g)/(V*q); // FIXED
                if(Thresh >= D_g)
                    {
                        for(i=0;i<K;i++)
                            {
                                a_i[i]=false;
                            }
                        return a_i;
                    }
                if(Thresh < D_g)
                    {
                        for(i=0;i<K;i++)
                            {
                                a_i[i]=true;
                            }
                        return a_i;
                    }
            }

	return a_i;
    }

    /*The idea behind all of this is the fact that the utility regarding the
     * subscribers who use the network will be the SAME for ALL PLAYERS. In
     * other words, regardless of whether a player caches or not, the function
     * which defines the utility of the subscribers who use the network
     * ((1-q)*Dk) and not the cache will be the same for all Players. Hence the
     * difference between players will be given by the decision to cache or
     * not.  Since this is a competition, and we do not care if the utility is
     * positive or not but only that the utility should be greater than the
     * other players utility, i must maximize the utility due to the cached
     * networks, so, i set up that Thresh criterium in order to set a tight
     * bound when to cache or not. The variable that we do not know is N so I
     * try to inferr it the first time. If it works, the second time, i try to
     * do it again, by averaging the amount of players Dk in all the networks
     * in day 3, and the info on Dk in day 2.  With this, we get a better
     * aproximation of N, and then recalculate. By this time, if it still
     * works, it means that the system is highly profitable, and is worth
     * caching.  */
    
    public void endDay(long[] b, long[] c)
    {
        bi=b;
        ci=c;
    }
}
