//==============================================================================
//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 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 resources.Constants;
import agents.Agent;

@SuppressWarnings("unused")
public class RiskAdjustmentAgency extends Agent
{

//==============================================================================
// Attribute variables
// These variables do not change during the agent's life (unless the user
// changes an attribute parameter during a simulation).
//------------------------------------------------------------------------------


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


//==============================================================================
// 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.
//------------------------------------------------------------------------------

    // 1. Currently updated memory variables
    // Variables from p1_ReallocatePremiums()
    private double currentPremiumReallocationAmount_PlanA1;
    private double currentPremiumReallocationAmount_PlanA2;
    private double currentPremiumReallocationAmount_PlanB1;
    private double currentPremiumReallocationAmount_PlanB2;

    // 2. Previously updated memory variables
    private double nextCurrentPremiumReallocationAmount_PlanA1;
    private double nextCurrentPremiumReallocationAmount_PlanA2;
    private double nextCurrentPremiumReallocationAmount_PlanB1;
    private double nextCurrentPremiumReallocationAmount_PlanB2;

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


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

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


//==============================================================================
// Method:  RiskAdjustmentAgency() constructor
//------------------------------------------------------------------------------

    public RiskAdjustmentAgency(Context<Object> pContext, AgentID pRiskAdjustmentAgencyID)
    {

        setAgentID(pRiskAdjustmentAgencyID);
        simulationContext = pContext;

        init_InitializeVariables_Constructor();

    }//end RiskAdjustmentAgency()

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


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

//==============================================================================
// 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.
        // None

        // 2. Initialize the value of all other variables.
        currentPremiumReallocationAmount_PlanA1 = 0.0;
        currentPremiumReallocationAmount_PlanA2 = 0.0;
        currentPremiumReallocationAmount_PlanB1 = 0.0;
        currentPremiumReallocationAmount_PlanB2 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanA1 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanA2 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanB1 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanB2 = 0.0;


    }//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.
        // None

        // 2. Update prior period values of all variables (after the first period).

        if (tickCount >= 1.0)
        {
            //None
        }//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.
        currentPremiumReallocationAmount_PlanA1 = nextCurrentPremiumReallocationAmount_PlanA1;
        currentPremiumReallocationAmount_PlanA2 = nextCurrentPremiumReallocationAmount_PlanA2;
        currentPremiumReallocationAmount_PlanB1 = nextCurrentPremiumReallocationAmount_PlanB1;
        currentPremiumReallocationAmount_PlanB2 = nextCurrentPremiumReallocationAmount_PlanB2;

        // 4. Re-initialize all CURRENT (NOT PRIOR) variables (except those that would cause
        //    display or chart problems (flickering, etc.).
        // currentPremiumReallocationAmount_PlanA1 = 0.0; Initialized above
        // currentPremiumReallocationAmount_PlanA2 = 0.0; Initialized above
        // currentPremiumReallocationAmount_PlanB1 = 0.0; Initialized above
        // currentPremiumReallocationAmount_PlanB2 = 0.0; Initialized above
        nextCurrentPremiumReallocationAmount_PlanA1 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanA2 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanB1 = 0.0;
        nextCurrentPremiumReallocationAmount_PlanB2 = 0.0;

        // 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_ReallocatePremiums()
// The Agency provides each Health Insurance Company with reallocated premiums,
// calculated according to Rule 1 (Compute premium reallocation) for each plan.
//------------------------------------------------------------------------------
    public void p1_ReallocatePremiums()
    {
        r1_ComputePremiumReallocation();

    }//end p1_ReallocatePremiums()
//------------------------------------------------------------------------------


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


//==============================================================================
// 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_ComputePremiumReallocation()
// For each plan type (that is, with or without co-payment), calculate the
// amount of additional premium to be allocated to Health Insurance Company A
// and taken away from Health Insurance Company B.
//------------------------------------------------------------------------------
    public void r1_ComputePremiumReallocation()
    {
        double currentAverageDiseaseStatus_PlanA1 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_A)
                .getCurrentAverageDiseaseStatus_Plan1();
        double currentAverageDiseaseStatus_PlanA2 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_A)
                .getCurrentAverageDiseaseStatus_Plan2();
        double currentAverageDiseaseStatus_PlanB1 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_B)
                .getCurrentAverageDiseaseStatus_Plan1();
        double currentAverageDiseaseStatus_PlanB2 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_B)
                .getCurrentAverageDiseaseStatus_Plan2();

        double currentClaimsPaid_PlanA1 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_A)
                .getCurrentClaimsPaid_Plan1();
        double currentClaimsPaid_PlanA2 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_A)
                .getCurrentClaimsPaid_Plan2();
        double currentClaimsPaid_PlanB1 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_B)
                .getCurrentClaimsPaid_Plan1();
        double currentClaimsPaid_PlanB2 =
                Environment.getHealthInsuranceCompanyList().get(Constants.HEALTH_INSURANCE_COMPANY_B)
                .getCurrentClaimsPaid_Plan2();

        nextCurrentPremiumReallocationAmount_PlanA1 =
                (Math.pow(currentAverageDiseaseStatus_PlanA1, 2) - Math.pow(currentAverageDiseaseStatus_PlanB1,  2))/
                ((Math.pow(currentAverageDiseaseStatus_PlanB1,  2)/currentClaimsPaid_PlanA1) + (Math.pow(currentAverageDiseaseStatus_PlanA1, 2)/currentClaimsPaid_PlanB1));

        nextCurrentPremiumReallocationAmount_PlanA2 =
                (Math.pow(currentAverageDiseaseStatus_PlanA2, 2) - Math.pow(currentAverageDiseaseStatus_PlanB2,  2))/
                ((Math.pow(currentAverageDiseaseStatus_PlanB2,  2)/currentClaimsPaid_PlanA2) + (Math.pow(currentAverageDiseaseStatus_PlanA2, 2)/currentClaimsPaid_PlanB2));

        nextCurrentPremiumReallocationAmount_PlanB1 = - nextCurrentPremiumReallocationAmount_PlanA1;

        nextCurrentPremiumReallocationAmount_PlanB2 = - nextCurrentPremiumReallocationAmount_PlanA2;

    }//end r1_ComputePremiumReallocation()
//------------------------------------------------------------------------------

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


//==============================================================================
// 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="nextCurrentPremiumReallocationAmount_PlanA1", displayName="A1. Next period reallocation amount - Plan A1")
    public double getNextCurrentPremiumReallocationAmount_PlanA1()
    {
        return nextCurrentPremiumReallocationAmount_PlanA1;
    }

    @Parameter (usageName="currentPremiumReallocationAmount_PlanA1", displayName="A2. Current reallocation amount - Plan A1")
    public double getCurrentPremiumReallocationAmount_PlanA1()
    {
        return currentPremiumReallocationAmount_PlanA1;
    }

    @Parameter (usageName="nextCurrentPremiumReallocationAmount_PlanA2", displayName="A3. Next period reallocation amount - Plan A2")
    public double getNextCurrentPremiumReallocationAmount_PlanA2()
    {
        return nextCurrentPremiumReallocationAmount_PlanA2;
    }

    @Parameter (usageName="currentPremiumReallocationAmount_PlanA2", displayName="A4. Current reallocation amount - Plan A2")
    public double getCurrentPremiumReallocationAmount_PlanA2()
    {
        return currentPremiumReallocationAmount_PlanA2;
    }

    @Parameter (usageName="nextCurrentPremiumReallocationAmount_PlanB1", displayName="A5. Next period reallocation amount - Plan B1")
    public double getNextCurrentPremiumReallocationAmount_PlanB1()
    {
        return nextCurrentPremiumReallocationAmount_PlanB1;
    }

    @Parameter (usageName="currentPremiumReallocationAmount_PlanB1", displayName="A6. Current reallocation amount - Plan B1")
    public double getCurrentPremiumReallocationAmount_PlanB1()
    {
        return currentPremiumReallocationAmount_PlanB1;
    }

    @Parameter (usageName="nextCurrentPremiumReallocationAmount_PlanB2", displayName="A7. Next period reallocation amount - Plan B2")
    public double getNextCurrentPremiumReallocationAmount_PlanB2()
    {
        return nextCurrentPremiumReallocationAmount_PlanB2;
    }

    @Parameter (usageName="currentPremiumReallocationAmount_PlanB2", displayName="A8. Current reallocation amount - Plan B2")
    public double getCurrentPremiumReallocationAmount_PlanB2()
    {
        return currentPremiumReallocationAmount_PlanB2;
    }

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


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

    public double analysisGetCurrentPremiumReallocationAmount_CompanyA()
    {
        return currentPremiumReallocationAmount_PlanA1 + currentPremiumReallocationAmount_PlanA2;
    }

    public double analysisGetCurrentPremiumReallocationAmount_CompanyB()
    {
        return currentPremiumReallocationAmount_PlanB1 + currentPremiumReallocationAmount_PlanB2;
    }

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


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


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

}//end RiskAdjustmentAgency class