//==============================================================================
//The Society of Actuaries (SOA) makes this computer model and its computer
//code available to its members for educational purposes. The model and its
//code may be modified and redistributed without prior authorization from the
//SOA. The SOA distributes this computer model and its computer code in the
//hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
//implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
//PURPOSE.
//==============================================================================

package agents;

import java.util.ListIterator;

import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.parameter.Parameter;
import repast.simphony.ui.probe.ProbeID;
import resources.AgentID;
import agents.Agent;

@SuppressWarnings("unused")
public class PenaltyTaxAgency extends Agent
{
//==============================================================================
// Attribute variables
// These variables do not change during the agent's life (unless the user
// changes an attribute parameter during a simulation).
//------------------------------------------------------------------------------
    private double maximumPenaltyTaxRate;
    private double uninsuredDecreaseTarget;

//==============================================================================

//==============================================================================
// Memory variables
// These variables can change during an agent's life.
// There are two types of memory variables:
// 1. Currently updated variables:  Variables that the agent updates during the
//    period to which they apply.
// 2. Previously updated variables:  Variables that the agent updates during the
//    period prior to the period in which they apply.
//------------------------------------------------------------------------------

    //Currently updated memory variables
    //Variables from p1_SetPenaltyTaxrate()
    private static double currentPenaltyTaxRate;
    private double priorPenaltyTaxRate;
    private double priorUninsuredPercentage;
    private boolean currentUninsuredGoalAchieved;

    //Previously updated memory variables
    //None

//==============================================================================


//==============================================================================
// Other variables
// These are other variables used in the class.
//------------------------------------------------------------------------------
    private Context<Object> simulationContext;
    private double tickCount;

//==============================================================================


//==============================================================================
// Method:  PenaltyTaxAgency() constructor
//------------------------------------------------------------------------------
    public PenaltyTaxAgency(Context<Object> pContext, AgentID pPenaltyTaxAgencyID)
    {

        setAgentID(pPenaltyTaxAgencyID);
        simulationContext = pContext;

        init_InitializeVariables_Constructor();

    }//end PenaltyTaxAgency()

//==============================================================================


//==============================================================================
// Methods: Initialization methods for the agent. These are used in
//          the agent's constructor method or at the beginning of each
//          simulation period.
//==============================================================================

//==============================================================================
// Method:  init_InitializeVariables_Constructor()
// The constructor does the following:
// 1. Initializes variables that remain constant throughout
//    an agent's life (unless the user changes parameters).
//    These are the agent's "attribute" variables.
// 2. Initializes the value of all other variables.
// This method gives a valid (non-null) value to all the agent's variables.
//------------------------------------------------------------------------------
    private void init_InitializeVariables_Constructor()
    {

        // 1. Initialize "attribute" variables.
        maximumPenaltyTaxRate = Environment.getPenaltyTaxAgency_MaximumPenaltyTaxLevel();
        uninsuredDecreaseTarget = Environment.getPenaltyTaxAgency_UninsuredDecreaseTarget();

        // 2. Initialize the value of all other variables.
        currentPenaltyTaxRate = 0.0; 
        priorPenaltyTaxRate = 0.0;
        priorUninsuredPercentage = 0.0;
        currentUninsuredGoalAchieved = false;

    }//end init_InitializeVariables_Constructor()
//------------------------------------------------------------------------------

//==============================================================================
// Method:  init_InitializeVariables_BOP() (beginning of period)
// This method does the following:
// 1. Updates attribute variables. If the user changes an attribute parameter
//    during a simulation, these may change.
// 2. Updates the prior period values of all variables (after the first period).
// 3. Provides "current" values for certain variables that the agent
//    does not set at the beginning of the period with a separate behavior.
//    This is done for those variables will be needed by behaviors of this agent
//    or by other agents during the period.
// 4. Re-initialize all CURRENT (NOT PRIOR) variables (except those that would cause
//    display or chart problems (flickering, etc.).
// 5. removes agents that have died.
//------------------------------------------------------------------------------
    public void init_InitializeVariables_BOP()
    {

        // 1. Update attribute variables.
        maximumPenaltyTaxRate = Environment.getPenaltyTaxAgency_MaximumPenaltyTaxLevel();
        uninsuredDecreaseTarget = Environment.getPenaltyTaxAgency_UninsuredDecreaseTarget();

        // 2. Update prior period values of all variables (after the first period).
        tickCount = RunEnvironment.getInstance().getCurrentSchedule().getTickCount();
        if (tickCount >= 1.0)
        {
            priorPenaltyTaxRate = currentPenaltyTaxRate;
        }//end if

        // 3. Provide "current" values for certain variables that the agent does not set at the
        //    beginning of the period with a separate behavior.
        // None

        // 4. Re-initialize all CURRENT (NOT PRIOR) variables (except those that would cause
        //    display or chart problems (flickering, etc.).
        currentPenaltyTaxRate = 0.0; 
        priorUninsuredPercentage = 0.0; // This variable is recalculated during the period.
        currentUninsuredGoalAchieved = false;

        // 5. Remove agents that have died
        // None

    }//end init_InitializeVariables_BOP()
//------------------------------------------------------------------------------

//==============================================================================


//==============================================================================
// Methods:  "Input" methods for the agent. These are described in the
// detailed description of the model. Each method is preceded by "i#".
//==============================================================================

// None

//==============================================================================


//==============================================================================
// Methods:  "Process" methods for the agent. These are described in the
// detailed description of the model. Each method is preceded by "p#"
// to indicate its number according to the numbering scheme used in the
// detailed description.
//==============================================================================

//==============================================================================
// Method:  p1_SetPenaltyTaxRate()
// The Penalty Tax Agency sets the penalty tax rate according to
// Rule 1 (Determine penalty tax rate).
//------------------------------------------------------------------------------
    public void p1_SetPenaltyTaxRate()
    {
        tickCount = RunEnvironment.getInstance().getCurrentSchedule().getTickCount();
        if (tickCount < 1.0 )
        {
            currentPenaltyTaxRate = Environment.getPenaltyTaxAgency_InitialPenaltyTaxRate();
        }//end if

        else r1_DeterminePenaltyTaxRate();

    }//end p1_SetPenaltyTaxRate()
//------------------------------------------------------------------------------

//==============================================================================


//==============================================================================
// Methods:  "Rule" methods for the agent. These are described in the
// detailed description of the model. Each method is preceded by "r#"
// to indicate its number according to the numbering scheme used in the
// detailed description.
//==============================================================================

//==============================================================================
// Method:  r1_DeterminePenaltyTaxRate()
// If the Agency has not reached its goal, it increases the penalty tax rate
// by 1.0 percent each simulation period, up to the maximum level of
// “Maximum penalty tax rate” (parameter E2 on the parameter pane).
// If the Agency has attained its goal, it does not change the penalty tax rate.
//------------------------------------------------------------------------------
    private void r1_DeterminePenaltyTaxRate()
    {
        ListIterator<Person> iterator1 = Environment.getPersonList().listIterator();
        int numberOfLivingPersonAgents = 0;
        int numberOfCoveredPersonAgents = 0;

        while (iterator1.hasNext())
        {
            Person person = iterator1.next();
            numberOfCoveredPersonAgents = numberOfCoveredPersonAgents + (person.isPriorExchangeParticipationStatus() ? 1: 0);
            numberOfLivingPersonAgents = numberOfLivingPersonAgents + 1;

        }//end while

        if (numberOfLivingPersonAgents == 0) priorUninsuredPercentage = 1.0;
        else priorUninsuredPercentage = 1.0 - 
                (double) numberOfCoveredPersonAgents/ (double) numberOfLivingPersonAgents;
        
        if (1.0 - priorUninsuredPercentage < uninsuredDecreaseTarget)
        {
            currentPenaltyTaxRate = Math.min(priorPenaltyTaxRate + 0.01, maximumPenaltyTaxRate);

        }//end if
        else
        {
            currentPenaltyTaxRate = priorPenaltyTaxRate;
            currentUninsuredGoalAchieved = true;
        }//end else

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Test 
// This block tests the method.
// To run the test, remove comments from the code below.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//    System.out.println("PenaltyTaxAgency r1_DeterminePenaltyTaxRate() at " +
//            RunEnvironment.getInstance().getCurrentSchedule().getTickCount());
//
//    System.out.println("numberOfLivingPersonAgents:  " + numberOfLivingPersonAgents);
//    System.out.println("numberOfCoveredPersonAgents:  " + numberOfCoveredPersonAgents);
//    System.out.println("priorUninsuredPercentage:  " + priorUninsuredPercentage);
//    System.out.println("uninsuredDecreaseTarget:  " + uninsuredDecreaseTarget);
//    System.out.println("priorPenaltyTaxRate:  " + priorPenaltyTaxRate);
//    System.out.println("currentPenaltyTaxRate:  " + currentPenaltyTaxRate);
//    System.out.println("--------------------------------------");
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    }//end r1_DeterminePenaltyTaxRate()
//------------------------------------------------------------------------------


//==============================================================================


//==============================================================================
// Methods:  General methods for the agent.
//==============================================================================


//==============================================================================


//==============================================================================
//Methods: "Probe" methods for the model user to probe the agent's data.
//Note:    As a simulation runs, the model user can probe an agent by
//	       double-clicking on its icon in the display. For more information
//	       about probes, see the Repast Simphony reference documentation.
//==============================================================================

// The "ProbeID" annotation provides the probe ID
    @ProbeID
    public String getName()
    {
        return getAgentName();
    }

    @Parameter (usageName="currentPenaltyTaxRate", displayName="1. Current penalty tax rate")
    public double getCurrentPenaltyTaxRate()
    {
        return currentPenaltyTaxRate;
    }

    @Parameter (usageName="priorPenaltyTaxRate", displayName="2. Prior penalty tax rate")
    public double getPriorPenaltyTaxRate()
    {
        return priorPenaltyTaxRate;
    }

    @Parameter (usageName="maximumPenaltyTaxRate", displayName="3. Maximum penalty tax rate")
    public double getMaximumPenaltyTaxRate()
    {
        return maximumPenaltyTaxRate;
    }

    @Parameter (usageName="priorUninsuredPercentage", displayName="4. Prior uninsured percentage")
    public double getPriorUninsuredPercentage()
    {
        return priorUninsuredPercentage;
    }

    @Parameter (usageName="uninsuredDecreaseTarget", displayName="5. Uninsured decrease target")
    public double getUninsuredDecreaseTarget()
    {
        return uninsuredDecreaseTarget;
    }

    @Parameter (usageName="currentUninsuredGoalAchieved", displayName="6. Uninsured goal achieved")
    public boolean isCurrentUninsuredGoalAchieved()
    {
        return currentUninsuredGoalAchieved;
    }



//==============================================================================


//==============================================================================
// Methods:  "Analysis" methods to support simulation charts and graphs.
//==============================================================================

// None

//==============================================================================


//==============================================================================
// Methods:  getter and setter methods
//------------------------------------------------------------------------------


//==============================================================================

}//end PenaltyTaxAgency class