//==============================================================================
// 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 statements
//------------------------------------------------------------------------------
import java.util.ArrayList;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;

import implementation.Schedule;
import implementation.SimulationUserPanel;
import repast.simphony.context.Context;
import repast.simphony.engine.environment.RunEnvironment;
import repast.simphony.parameter.Parameters;
import repast.simphony.random.RandomHelper;
import repast.simphony.space.continuous.ContinuousSpace;
import repast.simphony.space.gis.Geography;
import resources.AgentID;
import resources.Constants;
import resources.Constants.AgentType;
import resources.Constants.GoalDescription;
import resources.Constants.PlanPresentationOrder;
import resources.Constants.PlanTag;
import resources.InsurancePlan;


//==============================================================================
// This class implements the simulation's Environment. The Environment is the
// container for the model’s agents. It creates the simulation’s agents
// and maintains a list of them. It also obtains and validates user-provided
// parameters, and schedules agent behaviors.
//==============================================================================

public class Environment
{
//==============================================================================
// Attribute variables
// These variables describe the agent at a current point in time.
// They are available to other classes through "getter" methods.
//------------------------------------------------------------------------------    

// None

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


//==============================================================================
// Parameter variables
// These variables are available to other classes through "getter" methods.
// They are the parameters entered by the user through the Repast GUI.
// The identifier after the variable name refers to the identifier on the
// GUI parameter screen.
//------------------------------------------------------------------------------
    private static double initialTreatmentCostAlpha_CompanyA; //A1
	private static double initialTreatmentCostAlpha_CompanyB; //A2
    private static double initialPremium_PlanA1; //B1
    private static double initialPremium_PlanA2; //B2
    private static double copaymentPercentage_PlanA2; //B3
    private static double initialPremium_PlanB1; //B4
    private static double initialPremium_PlanB2; //B5
    private static double copaymentPercentage_PlanB2; //B6
    private static GoalDescription primaryGoal_CompanyA; //C1
    private static GoalDescription primaryGoal_CompanyB; //C2
    private static PlanPresentationOrder exchange_PlanPresentationOrder; //D1
    private static int exchange_InitialAdvertisingIntensity; //D2
    private static double exchange_AdvertisingExpensePercentage; //D3
    private static double exchange_UninsuredDecreaseTarget; //D4
    private static double penaltyTaxAgency_InitialPenaltyTaxRate; //E1
    private static double penaltyTaxAgency_MaximumPenaltyTaxRate; //E2
    private static double penaltyTaxAgency_UninsuredDecreaseTarget; //E3
    private static double premiumRateLimitAgency_ProfitPercentageMaximum; //F1
    private static double randomSeed; //G1

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


//==============================================================================
// Memory variables
// These variables include information that changes over time.
//------------------------------------------------------------------------------
    private static int runNumber = 0;
    private static ArrayList<Person> personList = new ArrayList<Person>();
    private static ArrayList<InsurancePlan> insurancePlanList = new ArrayList<InsurancePlan>();
    private static ArrayList<HealthInsuranceCompany> healthInsuranceCompanyList = new ArrayList<HealthInsuranceCompany>();
    private static ArrayList<ProviderNetwork> providerNetworkList = new ArrayList<ProviderNetwork>();
    private static ArrayList<PenaltyTaxAgency> penaltyTaxAgencyList = new ArrayList<PenaltyTaxAgency>();
    private static ArrayList<Exchange> exchangeList = new ArrayList<Exchange>();
    private static ArrayList<PremiumRateLimitAgency> premiumRateLimitAgencyList = new ArrayList<PremiumRateLimitAgency>();
    private static ArrayList<RiskAdjustmentAgency> riskAdjustmentAgencyList = new ArrayList<RiskAdjustmentAgency>();

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


//==============================================================================
// Other variables
// These are other variables used in the class.
//------------------------------------------------------------------------------
    private static ContinuousSpace<Object> communitySpace;
    private static Geography<Object> geography;
    private Context<Object> simulationContext;
    static double xCoordinate;
    static double yCoordinate; 
    
//==============================================================================

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

    @SuppressWarnings("unused")
    public Environment(ContinuousSpace<Object> pCommunitySpace, Geography<Object> geography2, Context<Object> pContext)
    {
        // Increment and print out the static run number.
        // Note that this static variable is not initialized.
        runNumber++;
        System.out.println("Run number: " + runNumber); //Useful for batch runs
        System.out.println("======================================");

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//    System.out.println("Environment constructor at " +
//        RunEnvironment.getInstance().getCurrentSchedule().getTickCount());
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        simulationContext = pContext;
        communitySpace = pCommunitySpace;
        geography = geography2;

        //======================================================================
        // Get the input parameters from the "Parameters" panel of the Repast GUI.
        //----------------------------------------------------------------------
        i1_getInputParameters();

        //----------------------------------------------------------------------
        // Override parameters.
        // This section of the constructor is used to override user-entered
        // parameters. It is turned on by the parameter "B1. Override parameters"
        // on the "Simulation" tab of the User Panel.
        // Note: Sometimes the "parameter sweep" feature
        // cannot properly set up the required parameters.
        // Nevertheless, even in these cases, the "parameter sweep" feature
        // can be used to execute the required number of batch runs.
        // Alternatively, the program can write out a custom file (see the
        // "WriteOutput()" method in the Schedule class).
        //----------------------------------------------------------------------
        if (SimulationUserPanel.isParameterOverride())
        {
            p1_OverrideParameters();

        }//end if

        //----------------------------------------------------------------------
        // Create the Person agents, add them to the simulation's "Context",
        // and add them to the "Person list".
        //----------------------------------------------------------------------
        if (personList != null) personList.clear();

        for (int i = 0; i < SimulationUserPanel.getNumberOfPersonAgents(); i++)
        {
            p2_CreatePerson(simulationContext, i);

        }//end for

        //----------------------------------------------------------------------
        // Create the InsurancePlan agents, add them to the simulation's "Context",
        // and add them to the "InsurancePlan list".
        //----------------------------------------------------------------------
        if (insurancePlanList != null) insurancePlanList.clear();
        
        for (int k = 0; k < Constants.NUMBER_OF_HEALTH_INSURANCE_PLANS; k++)
        {
            p3_CreateInsurancePlan(simulationContext, k);

        }//end for

        //----------------------------------------------------------------------
        // Create the Health Insurance Company agents, add them to the
        // simulation's "Context", and add them to the "Health Insurance Company
        // list".
        //----------------------------------------------------------------------
        if (healthInsuranceCompanyList != null) healthInsuranceCompanyList.clear();

        for (int j = 0; j < Constants.NUMBER_OF_HEALTH_INSURANCE_COMPANIES; j++)
        {
            AgentID healthInsuranceCompanyID = new AgentID(AgentType.HealthInsuranceCompany, j);
            HealthInsuranceCompany healthInsuranceCompany = new HealthInsuranceCompany(pContext, healthInsuranceCompanyID);
            pContext.add(healthInsuranceCompany);
            
            if (j == 0) healthInsuranceCompany.setAgentName("Health Insurance Company A");
            else healthInsuranceCompany.setAgentName("Health Insurance Company B");

            double xLocation1 = 0.0;
            double yLocation1 = 21.0 - 13.0 * j;
            healthInsuranceCompany.setAgentXLocation(xLocation1);
            healthInsuranceCompany.setAgentYLocation(yLocation1);
            communitySpace.moveTo(healthInsuranceCompany, xLocation1, yLocation1);

            GeometryFactory geometryFactory = new GeometryFactory();
            // For Repast, GIS coordinates are (degrees longitude, degrees latitude)
            Coordinate coordinate = new Coordinate(-84.1 + (double)j*3.0, 41.4 + (double)j * 0.5);
            Point geometry = geometryFactory.createPoint(coordinate);

            geography.move(healthInsuranceCompany, geometry);

         // Add each new Health Insurance Company agent to the "Health Insurance Company list".
         healthInsuranceCompanyList.add(healthInsuranceCompany);

        }//end for

        //----------------------------------------------------------------------
        // Create the Provider Network agents, add them to the
        // simulation's "Context", and add them to the "Provider Network list".
        //----------------------------------------------------------------------
        if (providerNetworkList != null) providerNetworkList.clear();

        for (int m = 0; m < Constants.NUMBER_OF_HEALTH_INSURANCE_COMPANIES; m++)
        {
            AgentID providerNetworkID = new AgentID(AgentType.ProviderNetwork, m);
            ProviderNetwork providerNetwork = new ProviderNetwork(pContext, providerNetworkID);
            pContext.add(providerNetwork);

            if (m == 0) providerNetwork.setAgentName("Network A");
            else providerNetwork.setAgentName("Network B");

            double xLocation2 = 0.0;
            double yLocation2 = 21.0 - 13.0 * m;
            providerNetwork.setAgentXLocation(xLocation2);
            providerNetwork.setAgentYLocation(yLocation2);
            communitySpace.moveTo(providerNetwork, xLocation2, yLocation2);

         // Add each new Provider Network agent to the "Provider Network list".
         providerNetworkList.add(providerNetwork);

        }//end for

        //----------------------------------------------------------------------
        // Create the Exchange agent and add it to the simulation's "Context".
        //----------------------------------------------------------------------
        if (exchangeList != null) exchangeList.clear();

        AgentID exchangeID = new AgentID(AgentType.Exchange, 0);
        Exchange exchange = new Exchange(pCommunitySpace, pContext, exchangeID);
        pContext.add(exchange);
        
        exchange.setAgentName("Exchange");
        
        double xLocation3 = 0.0;
        double yLocation3 = 50.0;
        exchange.setAgentXLocation(xLocation3);
        exchange.setAgentYLocation(yLocation3);
        communitySpace.moveTo(exchange, xLocation3, yLocation3);

         // Add each new Provider Network agent to the "Provider Network list".
         exchangeList.add(exchange);

        //----------------------------------------------------------------------
        // Create the RiskAdjustmentAgency agent and add it to the simulation's
        // "Context".
        //----------------------------------------------------------------------
        if (riskAdjustmentAgencyList != null) riskAdjustmentAgencyList.clear();

        AgentID riskAdjustmentAgencyID = new AgentID(AgentType.RiskAdjustmentAgency, 0);
        RiskAdjustmentAgency riskAdjustmentAgency = new RiskAdjustmentAgency(pContext, riskAdjustmentAgencyID);
        pContext.add(riskAdjustmentAgency);

        riskAdjustmentAgency.setAgentName("Risk Adjustment Agency");

        double xLocation4 = 0.0;
        double yLocation4 = 97.0;
        riskAdjustmentAgency.setAgentXLocation(xLocation4);
        riskAdjustmentAgency.setAgentYLocation(yLocation4);
        communitySpace.moveTo(riskAdjustmentAgency, xLocation4, yLocation4);


         // Add each new Provider Network agent to the "Provider Network list".
         riskAdjustmentAgencyList.add(riskAdjustmentAgency);

        //----------------------------------------------------------------------
        // Create the PremiumRateLimitAgency agent and add it to the simulation's
        // "Context".
        //----------------------------------------------------------------------
        if (premiumRateLimitAgencyList != null) premiumRateLimitAgencyList.clear();

        AgentID premiumRateLimitAgencyID = new AgentID(AgentType.PremiumRateLimitAgency, 0);
        PremiumRateLimitAgency premiumRateLimitAgency = new PremiumRateLimitAgency(pContext, premiumRateLimitAgencyID);
        pContext.add(premiumRateLimitAgency);

        premiumRateLimitAgency.setAgentName("Premium Rate Limit Agency");

        double xLocation5 = 0.0;
        double yLocation5 = 87.0;
        premiumRateLimitAgency.setAgentXLocation(xLocation5);
        premiumRateLimitAgency.setAgentYLocation(yLocation5);
        communitySpace.moveTo(premiumRateLimitAgency, xLocation5, yLocation5);

         // Add each new Provider Network agent to the "Provider Network list".
         premiumRateLimitAgencyList.add(premiumRateLimitAgency);

        //----------------------------------------------------------------------
        // Create the PenaltyTaxAgency agent and add it to the simulation's
        // "Context".
        //----------------------------------------------------------------------
        if (penaltyTaxAgencyList != null) penaltyTaxAgencyList.clear();

        AgentID penaltyTaxAgencyID = new AgentID(AgentType.PenaltyTaxAgency, 0);
        PenaltyTaxAgency penaltyTaxAgency = new PenaltyTaxAgency(pContext, penaltyTaxAgencyID);
        pContext.add(penaltyTaxAgency);

        penaltyTaxAgency.setAgentName("Penalty Tax Agency");

        double xLocation6 = 0.0;
        double yLocation6 = 77.0;
        penaltyTaxAgency.setAgentXLocation(xLocation6);
        penaltyTaxAgency.setAgentYLocation(yLocation6);
        communitySpace.moveTo(penaltyTaxAgency, xLocation6, yLocation6);

         // Add each new Provider Network agent to the "Provider Network list".
         penaltyTaxAgencyList.add(penaltyTaxAgency);

        //----------------------------------------------------------------------
        // Schedule agent behaviors (methods)
        // Note:  for logical consistency, the schedule is launched after
        // agents are constructed.
        //----------------------------------------------------------------------
        Schedule agentSchedule = new Schedule(simulationContext);

    }//end Environment()
//==============================================================================


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

    public void init_InitializeVariables_BOP()
    {

        // Intentionally blank, until needed.

    }//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#".
//==============================================================================

//==============================================================================
// Method:  i1_getInputParameters()
//------------------------------------------------------------------------------
    public void i1_getInputParameters()
    {

        Parameters parameters = RunEnvironment.getInstance().getParameters();

        initialTreatmentCostAlpha_CompanyA =
                (Double) parameters.getValue("initialTreatmentCostAlpha_CompanyA"); //A1
        initialTreatmentCostAlpha_CompanyB =
                (Double) parameters.getValue("initialTreatmentCostAlpha_CompanyB"); //A2
        initialPremium_PlanA1 =
                (Double) parameters.getValue("initialPremium_PlanA1"); //B1
        initialPremium_PlanA2 =
                (Double)parameters.getValue("initialPremium_PlanA2"); //B2
        copaymentPercentage_PlanA2 =
                (Double) parameters.getValue("copaymentPercentage_PlanA2"); //B3
        initialPremium_PlanB1 =
                (Double) parameters.getValue("initialPremium_PlanB1"); //B4
        initialPremium_PlanB2 =
                (Double)parameters.getValue("initialPremium_PlanB2"); //B5
        copaymentPercentage_PlanB2 =
                (Double) parameters.getValue("copaymentPercentage_PlanB2"); //B6

        if (((String) parameters.getValue("primaryGoal_CompanyA")).equals("Maximize profit"))
                primaryGoal_CompanyA = GoalDescription.MaximizeProfit; //C1a
        if (((String) parameters.getValue("primaryGoal_CompanyA")).equals("Maximize market share"))
                primaryGoal_CompanyA = GoalDescription.MaximizeMarketShare; //C1b

        if (((String) parameters.getValue("primaryGoal_CompanyB")).equals("Maximize profit"))
                primaryGoal_CompanyB = GoalDescription.MaximizeProfit; //C2a
        if (((String) parameters.getValue("primaryGoal_CompanyB")).equals("Maximize market share"))
                primaryGoal_CompanyB = GoalDescription.MaximizeMarketShare; //C2b

        if (((String) parameters.getValue("exchange_PlanPresentationOrder")).equals("Random"))
                exchange_PlanPresentationOrder = PlanPresentationOrder.Random; //D1a
        if (((String) parameters.getValue("exchange_PlanPresentationOrder")).equals("Low to high premium"))
                exchange_PlanPresentationOrder = PlanPresentationOrder.LowToHighPremium; //D1b
        if (((String) parameters.getValue("exchange_PlanPresentationOrder")).equals("High to low premium"))
                exchange_PlanPresentationOrder = PlanPresentationOrder.HighToLowPremium; //D1c

        exchange_InitialAdvertisingIntensity =
                (Integer) parameters.getValue("exchange_InitialAdvertisingIntensity"); //D2
        exchange_AdvertisingExpensePercentage =
                (Double) parameters.getValue("exchange_AdvertisingExpensePercentage"); //D3
        exchange_UninsuredDecreaseTarget =
                (Double) parameters.getValue("exchange_UninsuredDecreaseTarget"); //D4
        penaltyTaxAgency_InitialPenaltyTaxRate =
                (Double) parameters.getValue("penaltyTaxAgency_InitialPenaltyTaxRate"); //E1
        penaltyTaxAgency_MaximumPenaltyTaxRate =
                (Double) parameters.getValue("penaltyTaxAgency_MaximumPenaltyTaxRate"); //E2
        penaltyTaxAgency_UninsuredDecreaseTarget =
                (Double) parameters.getValue("penaltyTaxAgency_UninsuredDecreaseTarget"); //E3
        premiumRateLimitAgency_ProfitPercentageMaximum =
                (Double) parameters.getValue("premiumRateLimitAgency_ProfitPercentageMaximum"); //F1
        randomSeed =
                (Integer) parameters.getValue("randomSeed"); //G1

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Test 
// This block tests the user-entered parameter values.
// To run the test, remove comments from the code below.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//    System.out.println("Environment i1_getInputParameters() at " +
//            RunEnvironment.getInstance().getCurrentSchedule().getTickCount());
//
//    System.out.println("A1. initialTreatmentCostAlpha_CompanyA:  " +
//            getInitialTreatmentCostAlpha_CompanyA()); //A1
//    System.out.println("A2. initialTreatmentCostAlpha_CompanyB:  " +
//            getInitialTreatmentCostAlpha_CompanyB()); //A2
//    System.out.println("B1. initialPremium_PlanA1  " +
//            getInitialPremium_PlanA1()); //B1
//    System.out.println("B2. initialPremium_PlanA2:  " +
//            getInitialPremium_PlanA2()); //B2
//    System.out.println("B3. copaymentPercentage_PlanA2:  " +
//            getCopaymentPercentage_PlanA2()); //B3
//    System.out.println("B4. initialPremium_PlanB1:  " +
//            getInitialPremium_PlanB1()); //B4
//    System.out.println("B5. initialPremium_PlanB2:  " +
//            getInitialPremium_PlanB2()); //B5
//    System.out.println("B6. copaymentPercentage_PlanB2:  " +
//            getCopaymentPercentage_PlanB2()); //B6
//    System.out.println("C1. primaryGoal_CompanyA:  " +
//            getPrimaryGoal_CompanyA()); //C1
//    System.out.println("C2. primaryGoal_CompanyB:  " +
//            getPrimaryGoal_CompanyB()); //C2
//    System.out.println("D1. exchange_PlanPresentationOrder:  " +
//            getExchange_PlanPresentationOrder()); //D1
//    System.out.println("D2. exchange_InitialAdvertisingIntensity:  " +
//            getExchange_InitialAdvertisingIntensity()); //D2
//    System.out.println("D3. exchange_AdvertisingExpensePercentage:  " +
//            getExchange_AdvertisingExpensePercentage()); //D3
//    System.out.println("D4. exchange_UninsuredDecreaseTarget:  " +
//            getExchange_UninsuredDecreaseTarget()); //D4
//    System.out.println("E1. penaltyTaxAgency_InitialPenaltyTaxRate:  " +
//            getPenaltyTaxAgency_InitialPenaltyTaxLevel()); //E1
//    System.out.println("E2. penaltyTaxAgency_MaximumPenaltyTaxRate:  " +
//            getPenaltyTaxAgency_MaximumPenaltyTaxRate()); //E2
//    System.out.println("E3. penaltyTaxAgency_UninsuredDecreaseTarget:  " +
//            getPenaltyTaxAgency_UninsuredDecreaseTarget()); //E3
//    System.out.println("F1. premiumRateLimitAgency_ProfitPercentageMaximum:  " +
//            getPremiumRateLimitAgency_ProfitPercentageMaximum()); //F1
//    System.out.println("G1. randomNumberSeed:  " +
//            getRandomSeed()); //G1
//
//    System.out.println("Scenario A1. maximumSimulationPeriods:  " +
//            SimulationUserPanel.getMaximumSimulationPeriods()); //Simulation: A1   
//    System.out.println("Scenario A2. parameterOverride:  " +
//            SimulationUserPanel.isParameterOverride()); //Simulation: A2   
//
//    System.out.println("Person A1. personLabels:  " +
//            SimulationUserPanel.isPersonLabels()); //Person: A1
//    System.out.println("Person B1. numberOfPersonAgents:  " +
//            SimulationUserPanel.getNumberOfPersonAgents()); //Person: B1
//    System.out.println("Person C1. geographicLocationDistributionType:  " +
//            SimulationUserPanel.getGeographicLocationDistributionType()); //Person: C1
//    System.out.println("Person C2. geographicLocationNormalDistributionMean:  " +
//            SimulationUserPanel.getGeographicLocationNormalDistributionMean()); //Person: C2
//    System.out.println("Person C3. geographicLocationNormalDistributionSD:  " +
//            SimulationUserPanel.getGeographicLocationNormalDistributionSD()); //Person: C3
//    System.out.println("Person C4. neighborhoodRadius:  " +
//            SimulationUserPanel.getNeighborhoodRadius()); //Person: C4
//    System.out.println("Person D1. maximumIncome:  " +
//            SimulationUserPanel.getMaximumIncome()); //Person: D1
//    System.out.println("Person D2. incomeDistributionType:  " +
//            SimulationUserPanel.getIncomeDistributionType()); //Person: D2
//    System.out.println("Person D3. incomeLogNormalDistributionMean:  " +
//            SimulationUserPanel.getIncomeLogNormalDistributionMean()); //Person: D3
//    System.out.println("Person D4. incomeLogNormalDistributionSD:  " +
//            SimulationUserPanel.getIncomeLogNormalDistributionSD()); //Person: D4
//    System.out.println("Person E1. initialDiseaseDistributionType:  " +
//            SimulationUserPanel.getInitialDiseaseDistributionType()); //Person: E1
//    System.out.println("Person E2. initialDiseaseLogNormalDistributionMean:  " +
//            SimulationUserPanel.getInitialDiseaseLogNormalDistributionMean()); //Person: E2
//    System.out.println("Person E3. initialDiseaseLogNormalDistributionSD:  " +
//            SimulationUserPanel.getInitialDiseaseLogNormalDistributionSD()); //Person: E3
//    System.out.println("Person F1. incrementalDiseaseMaximum:  " +
//            SimulationUserPanel.getIncrementalDiseaseMaximum()); //Person: F1
//    System.out.println("Person F2. incrementalDiseaseDistributionType:  " +
//            SimulationUserPanel.getIncrementalDiseaseDistributionType()); //Person: F2
//    System.out.println("Person F3. incrementalDiseaseLogNormalDistributionMean:  " +
//            SimulationUserPanel.getIncrementalDiseaseLogNormalDistributionMean()); //Person: F3
//    System.out.println("Person F4. incrementalDiseaseLogNormalDistributionSD:  " +
//            SimulationUserPanel.getIncrementalDiseaseLogNormalDistributionSD()); //Person: F4
//    System.out.println("Person G1. healthImprovementPercentage:  " +
//            SimulationUserPanel.getHealthImprovementPercentage()); //Person: G1
//    System.out.println("Person G2. healthDeteriorationPercentage:  " +
//            SimulationUserPanel.getHealthDeteriorationPercentage()); //Person: G2
//    System.out.println("Person H1. decisionInertiaPercentage:  " +
//            SimulationUserPanel.getDecisionInertiaPercentage()); //Person: H1
//    System.out.println("Person H2. healthGravityThreshold:  " +
//            SimulationUserPanel.getHealthGravityThreshold()); //Person: H2
//    System.out.println("Person H3. advertisingImpactThreshold:  " +
//            SimulationUserPanel.getAdvertisingImpactThreshold()); //Person: H3
//
//    System.out.println("Health Insurance Company A1. lapseThreshold_CompanyA:  " +
//            SimulationUserPanel.getLapseThresholdCompanyA()); //Health Insurance Company: A1
//    System.out.println("Health Insurance Company A2. lapseThreshold_CompanyB:  " +
//            SimulationUserPanel.getLapseThreshold_CompanyB()); //Health Insurance Company: A2
//    System.out.println("Health Insurance Company B1. premiumDiscountFactor_CompanyA:  " +
//            SimulationUserPanel.getPremiumDiscountFactor_CompanyA()); //Health Insurance Company: B1
//    System.out.println("Health Insurance Company B2. premiumDiscountFactor_CompanyB:  " +
//            SimulationUserPanel.getPremiumDiscountFactor_CompanyB()); //Health Insurance Company: B2
//    System.out.println("Health Insurance Company C1. maximumOfferIncreasePercent_CompanyA:  " +
//            SimulationUserPanel.getMaximumOfferIncreasePercent_CompanyA()); //Health Insurance Company: C1
//    System.out.println("Health Insurance Company C2. maximumOfferIncreasePercent_CompanyB:  " +
//            SimulationUserPanel.getMaximumOfferIncreasePercent_CompanyB()); //Health Insurance Company: C2
//
//    System.out.println("Provider Network A1. minimumAlphaIncreasePercent_NetworkA:  " +
//            SimulationUserPanel.getMinimumAlphaIncreasePercent_NetworkA()); //Provider Network: A1
//    System.out.println("Provider Network A2. minimumAlphaIncreasePercent_NetworkB:  " +
//            SimulationUserPanel.getMinimumAlphaIncreasePercent_NetworkB()); //Provider Network: A2
//
//    System.out.println("--------------------------------------");
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    }//end i1_getInputParameters()
//------------------------------------------------------------------------------


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


//==============================================================================
// 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_OverrideParameters()
//------------------------------------------------------------------------------
  public void p1_OverrideParameters()
  {
       // Intentionally empty, until needed.
  
  }//end p1_OverrideParameters()
//==============================================================================

//==============================================================================
// Method:  p2_CreatePerson()
//------------------------------------------------------------------------------
    public static void p2_CreatePerson(Context<Object> pContext, int pIndex)
    {
         AgentID personID = new AgentID(AgentType.Person, pIndex);
         Person person = new Person(pContext, personID);          
         pContext.add(person);
         
         //------------------------------------------------------------------
         // If the Person distribution type is "Normal", distribute the Persons
         // according to a normal distribution over the Environment.
         // The distribution is limited to the size of the Environment.
         // Note:  a small distance is subtracted from SPACE_SIZE so that agents
         // with coordinates exceeding SPACE_SIZE are displayed.
         //------------------------------------------------------------------
         if (SimulationUserPanel.getGeographicLocationDistributionType().equals(Constants.NORMAL_DISTRIBUTION))
         {

             double distributionMean = SimulationUserPanel.getGeographicLocationNormalDistributionMean();
             RandomHelper.createNormal(distributionMean,
             		SimulationUserPanel.getGeographicLocationNormalDistributionSD());
             xCoordinate = Math.max(Math.min(RandomHelper.getNormal().nextDouble(),
                      Constants.COMMUNITY_SPACE_SIZE - Constants.SMALL_DISTANCE), 0);
             yCoordinate = Math.max(Math.min(RandomHelper.getNormal().nextDouble(),
                      Constants.COMMUNITY_SPACE_SIZE - Constants.SMALL_DISTANCE), 0);
             
             person.setAgentXLocation(xCoordinate);
             person.setAgentYLocation(yCoordinate);
             communitySpace.moveTo(person, xCoordinate, yCoordinate);

            GeometryFactory geometryFactory = new GeometryFactory();
            // For Repast, GIS coordinates are (degrees longitude, degrees latitude)
            // The distribution is centered on Columbus, Ohio.
            Coordinate coordinate = new Coordinate(-82.9989 + (xCoordinate - distributionMean)/35.0,
                    39.9611 + 0.2 + (yCoordinate - distributionMean)/35.0);
            Point geometry = geometryFactory.createPoint(coordinate);

            geography.move(person, geometry);
             
         }//end if
         
         // If the Person distribution type is "Random Uniform Distribution", distribute the Persons
         // randomly over the environment.
         else
         {
             xCoordinate =
                      RandomHelper.nextDoubleFromTo(0, Constants.COMMUNITY_SPACE_SIZE);
             yCoordinate =
                      RandomHelper.nextDoubleFromTo(0, Constants.COMMUNITY_SPACE_SIZE);
             
             person.setAgentXLocation(xCoordinate);
             person.setAgentYLocation(yCoordinate);
             communitySpace.moveTo(person, xCoordinate, yCoordinate);

         }//end else
         
         // Enter each new Person in the "Person list".
         personList.add(person);

//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Test 
// This outputs data to the console to test the method.
// To run the test, remove comments from the code below.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//  System.out.println("Environment p2_CreatePerson() at " +
//                     RunEnvironment.getInstance().getCurrentSchedule().getTickCount());
//  System.out.println("Size of Person list:  " + personList.size());
//  System.out.println("Person ID:  " + personList.get(pIndex).getPersonIDString());
//  System.out.println("Person X location:  " + personList.get(pIndex).getAgentXLocation());
//  System.out.println("Person Y location:  " + personList.get(pIndex).getAgentYLocation());
//  System.out.println("--------------------------------------");
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                        
    }//end p2_CreatePerson()
//==============================================================================

//==============================================================================
// Method:  p3_CreateInsurancePlan()
//------------------------------------------------------------------------------
    public static void p3_CreateInsurancePlan(Context<Object> pContext, int pIndex)
    {

        AgentID insurancePlanID = new AgentID(AgentType.InsurancePlan, pIndex);
        InsurancePlan insurancePlan = new InsurancePlan(pContext, insurancePlanID);
        switch (insurancePlan.getAgentID().getAgentNumber())
        {
            case 0: 
            {
                insurancePlan.setAgentName("Plan A1");
                insurancePlan.setPlanTag(PlanTag.PlanA1);
                break;
            }//end case

            case 1: 
            {
                insurancePlan.setAgentName("Plan A2");
                insurancePlan.setPlanTag(PlanTag.PlanA2);
                break;
            }//end case

            case 2: 
            {
                insurancePlan.setAgentName("Plan B1");
                insurancePlan.setPlanTag(PlanTag.PlanB1);
                break;
            }//end case

            case 3: 
            {
                insurancePlan.setAgentName("Plan B2");
                insurancePlan.setPlanTag(PlanTag.PlanB2);
                break;
            }//end case

            default:
            {
            // There should be no default
                System.out.println("Error:  Unexpected switch default in Environment p3_CreateInsurancePlan()");
            }//end case

        }//end switch

        pContext.add(insurancePlan);

        // Enter each new InsurancePlan in the "InsurancePlan list".
        insurancePlanList.add(insurancePlan);


//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Test 
// This outputs data to the console to test the method.
// To run the test, remove comments from the code below.
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//    System.out.println("Environment p2_CreateInsurancePlan() at " +
//                        RunEnvironment.getInstance().getCurrentSchedule().getTickCount());
//    System.out.println("Size of InsurancePlan list:  " + insurancePlanList.size());
//    System.out.println("InsurancePlan ID:  " + insurancePlanList.get(pIndex).getInsurancePlanIDString());
//    System.out.println("InsurancePlan X location:  " + insurancePlanList.get(pIndex).getAgentXLocation());
//    System.out.println("InsurancePlan Y location:  " + insurancePlanList.get(pIndex).getAgentYLocation());
//    System.out.println("--------------------------------------");
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
                          
    }//end p3_CreateInsurancePlan()

//------------------------------------------------------------------------------

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


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

// None

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


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

// None

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


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

// None

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


//==============================================================================
// Methods: getter and setter methods
//------------------------------------------------------------------------------
    public static int getRunNumber()
    {
        return runNumber;
    }

    //A1   
    public static double getInitialTreatmentCostAlpha_CompanyA()
	{
		return initialTreatmentCostAlpha_CompanyA;
	}

    //A2
    public static double getInitialTreatmentCostAlpha_CompanyB()
    {
        return initialTreatmentCostAlpha_CompanyB;
    }

    //B1
    public static double getInitialPremium_PlanA1()
    {
        return initialPremium_PlanA1;
    }

    //B2
    public static double getInitialPremium_PlanA2()
    {
        return initialPremium_PlanA2;
    }

    //B3
    public static double getCopaymentPercentage_PlanA2()
    {
        return copaymentPercentage_PlanA2;
    }
    
    //B4
    public static double getInitialPremium_PlanB1()
    {
        return initialPremium_PlanB1;
    }

    //B5
    public static double getInitialPremium_PlanB2()
    {
        return initialPremium_PlanB2;
    }

    //B6
    public static double getCopaymentPercentage_PlanB2()
    {
        return copaymentPercentage_PlanB2;
    }

    //C1
    public static GoalDescription getPrimaryGoal_CompanyA()
    {
        return primaryGoal_CompanyA;
    }

    //C2
    public static GoalDescription getPrimaryGoal_CompanyB()
    {
        return primaryGoal_CompanyB;
    }

    //D1
    public static PlanPresentationOrder getExchange_PlanPresentationOrder()
    {
        return exchange_PlanPresentationOrder;
    }

    //D2
    public static int getExchange_InitialAdvertisingIntensity()
    {
        return exchange_InitialAdvertisingIntensity;
    }

    //D3
    public static double getExchange_AdvertisingExpensePercentage()
    {
        return exchange_AdvertisingExpensePercentage;
    }

    //D4
    public static double getExchange_UninsuredDecreaseTarget()
    {
        return exchange_UninsuredDecreaseTarget;
    }

    //E1
    public static double getPenaltyTaxAgency_InitialPenaltyTaxRate()
    {
        return penaltyTaxAgency_InitialPenaltyTaxRate;
    }

    //E2
    public static double getPenaltyTaxAgency_MaximumPenaltyTaxLevel()
    {
        return penaltyTaxAgency_MaximumPenaltyTaxRate;
    }

    //E3
    public static double getPenaltyTaxAgency_UninsuredDecreaseTarget()
    {
        return penaltyTaxAgency_UninsuredDecreaseTarget;
    }

    //F1
    public static double getPremiumRateLimitAgency_ProfitPercentageMaximum()
    {
        return premiumRateLimitAgency_ProfitPercentageMaximum;
    }


    public static ArrayList<InsurancePlan> getInsurancePlanList()
    {
        return insurancePlanList;
    }

    public static void setInsurancePlanList(
            ArrayList<InsurancePlan> insurancePlanList)
    {
        Environment.insurancePlanList = insurancePlanList;
    }

    public static ArrayList<Person> getPersonList()
    {
        return personList;
    }

    //G1
    public static double getRandomSeed()
    {
        return randomSeed;
    }

    public static ArrayList<HealthInsuranceCompany> getHealthInsuranceCompanyList()
    {
        return healthInsuranceCompanyList;
    }

    public static ArrayList<ProviderNetwork> getProviderNetworkList()
    {
        return providerNetworkList;
    }

    public static ArrayList<PenaltyTaxAgency> getPenaltyTaxAgencyList()
    {
        return penaltyTaxAgencyList;
    }

    public static ArrayList<Exchange> getExchangeList()
    {
        return exchangeList;
    }

    public static ArrayList<PremiumRateLimitAgency> getPremiumRateLimitAgencyList()
    {
        return premiumRateLimitAgencyList;
    }

    public static ArrayList<RiskAdjustmentAgency> getRiskAdjustmentAgencyList()
    {
        return riskAdjustmentAgencyList;
    }
    
//==============================================================================        
        
     
}//end Environment class