// $Id: force_interface.cpp,v 1.64 2018/01/03 21:33:04 mkkuhner Exp $

/*
Copyright 2002-2005 Mary K. Kuhner, Peter Beerli, and Joseph Felsenstein

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

*/

/* Authors: Peter Beerli, Mary Kuhner, Jon Yamato and Joseph Felsenstein */


#include <cassert>
#include <algorithm>    // for std::min()

#include "force_interface.h"
#include "defaults.h"
#include "force.h"
#include "ui_constants.h"
#include "ui_interface.h"
#include "ui_strings.h"
#include "ui_vars.h"

using std::string;

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

bool uiForceLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(id.GetForceType());
}

uiForceLegal::uiForceLegal()
    : GetBool(uistr::forceLegal)
{
}

uiForceLegal::~uiForceLegal()
{
}

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

bool uiForceOnOff::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(id.GetForceType());
}

void uiForceOnOff::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,id.GetForceType());
}

uiForceOnOff::uiForceOnOff()
    : SetGetBool(uistr::forceOnOff)
{
}

uiForceOnOff::~uiForceOnOff()
{
}

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

long uiMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(id.GetForceType());
}

void uiMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,id.GetForceType());
}

uiMaxEvents::uiMaxEvents()
    : SetGetLong(uistr::maxEvents)
{
}

uiMaxEvents::~uiMaxEvents()
{
}

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

uiParameter::uiParameter(const string& whichForceClass)
    : SetGetDouble(whichForceClass)
{
}

uiParameter::~uiParameter()
{
}

string uiParameter::Description(UIVars& vars, UIId id)
{
    if (id.GetIndex1() == uiconst::GLOBAL_ID)
    {
        return SetGetDouble::Description(vars, id);
    }
    return vars.GetParamNameWithConstraint(id.GetForceType(), id.GetIndex1());
}

string uiParameter::Min(UIVars& vars, UIId id)
{
    force_type ftype = id.GetForceType();
    long pindex = id.GetIndex1();
    if (vars.chains.GetDoBayesianAnalysis())
    {
        if (vars.forces.GetParamstatus(ftype, pindex).Status() != pstat_constant)
        {
            return ToString(vars.forces.GetPrior(ftype, pindex).GetLowerBound());
        }
        //LS NOTE:  More a note than a debug, but:  if pindex is GLOBAL_ID, this
        // means that the user is setting all start values at once, using one of
        // the 'Single <force> starting estimate for all data' menu options.
        // So, what this routine will do is report back the range for the default
        // prior for this force.  This may be different from the actual priors
        // for particular parameters, either larger or smaller.  Since 'Min' and
        // 'Max' are only suggestions, the actual setting code in ui_vars_forces
        // will simply check the desired value against that parameter's prior (be
        // it the default or unique), and will warn the user appropriately.
        //
        // The other option here is to have GetPrior(ftype, GLOBAL_ID) return
        // a prior that is either the intersection or the union of the individual
        // priors, each of which have their own foibles.  That seems a bit complex
        // for no clear benefit (given the current warning system), so I think
        // our current system is as good as we're going to get any time soon.
    }
    switch (ftype)
    {
        case force_COAL:
            return ToString(defaults::minTheta);
            break;
        case force_MIG:
            return ToString(defaults::minMigRate);
            break;
        case force_DIVMIG:
            return ToString(defaults::minDivMigRate);
            break;
        case force_DIVERGENCE:
            return ToString(defaults::minEpoch);
            break;
        case force_DISEASE:
            return ToString(defaults::minDiseaseRate);
            break;
        case force_REC:
            return ToString(defaults::minRecRate);
            break;
        case force_EXPGROWSTICK:
        case force_GROW:
            return ToString(defaults::minGrowRate);
            break;
        case force_LOGSELECTSTICK:
        case force_LOGISTICSELECTION:
            return ToString(defaults::minLSelectCoeff);
            break;
        case force_REGION_GAMMA:
            return ToString(defaults::minGammaOverRegions);
            break;
        case force_NONE:
            assert(false);
            return ToString(FLAGDOUBLE);
            break;
    }
    assert(false); //Missing force type.
    return ToString(FLAGDOUBLE);
}

string uiParameter::Max(UIVars& vars, UIId id)
{
    force_type ftype = id.GetForceType();
    long pindex = id.GetIndex1();
    if (vars.chains.GetDoBayesianAnalysis())
    {
        //LS NOTE:  (see Min, above)
        if (vars.forces.GetParamstatus(ftype, pindex).Status() != pstat_constant)
        {
            return ToString(vars.forces.GetPrior(ftype, pindex).GetUpperBound());
        }
    }
    switch (ftype)
    {
        case force_COAL:
            return ToString(defaults::maxTheta);
            break;
        case force_MIG:
            return ToString(defaults::maxMigRate);
            break;
        case force_DIVMIG:
            return ToString(defaults::maxDivMigRate);
            break;
        case force_DIVERGENCE:
            return ToString(defaults::maxEpoch);
            break;
        case force_DISEASE:
            return ToString(defaults::maxDiseaseRate);
            break;
        case force_REC:
            return ToString(defaults::maxRecRate);
            break;
        case force_EXPGROWSTICK:
        case force_GROW:
            return ToString(defaults::maxGrowRate);
            break;
        case force_LOGSELECTSTICK:
        case force_LOGISTICSELECTION:
            return ToString(defaults::maxLSelectCoeff);
            break;
        case force_REGION_GAMMA:
            return ToString(defaults::maxGammaOverRegions);
            break;
        case force_NONE:
            assert(false);
            return ToString(FLAGDOUBLE);
            break;
    }
    assert(false); //Missing force type.
    return ToString(FLAGDOUBLE);
}

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

uiCoalescence::uiCoalescence()
    : SetGetBoolEnabled(uistr::coalescence)
{
}

uiCoalescence::~uiCoalescence()
{
}

bool uiCoalescence::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_COAL);
}

void uiCoalescence::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_COAL);
}

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

uiCoalescenceLegal::uiCoalescenceLegal()
    : GetBool(uistr::coalescenceLegal)
{
}

uiCoalescenceLegal::~uiCoalescenceLegal()
{
}

bool uiCoalescenceLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_COAL);
}

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

long uiCoalescenceMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_COAL);
}

void uiCoalescenceMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_COAL);
}

uiCoalescenceMaxEvents::uiCoalescenceMaxEvents()
    : SetGetLong(uistr::coalescenceMaxEvents)
{
}

uiCoalescenceMaxEvents::~uiCoalescenceMaxEvents()
{
}

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

void uiFstTheta::Set(UIVars& vars, UIId id, noval val)
{
    vars.forces.SetAllThetaStartValuesFST();
}

uiFstTheta::uiFstTheta()
    : SetGetNoval(uistr::fstSetTheta)
{
}

uiFstTheta::~uiFstTheta()
{
}

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

uiUserTheta::uiUserTheta()
    : uiParameter(uistr::userSetTheta)
{
}

uiUserTheta::~uiUserTheta()
{
}

void uiUserTheta::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetThetaStartValue(val,id.GetIndex1());
}

double uiUserTheta::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_COAL,id.GetIndex1());
}

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

void uiWattersonTheta::Set(UIVars& vars, UIId id, noval val)
{
    vars.forces.SetAllThetaStartValuesWatterson();
}

uiWattersonTheta::uiWattersonTheta()
    : SetGetNoval(uistr::wattersonSetTheta)
{
}

uiWattersonTheta::~uiWattersonTheta()
{
}

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

uiGlobalTheta::uiGlobalTheta()
    : uiParameter(uistr::globalTheta)
{
}

uiGlobalTheta::~uiGlobalTheta()
{
}

void uiGlobalTheta::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetAllThetaStartValues(val);
}

double uiGlobalTheta::Get(UIVars& vars, UIId id)
{
    assert(false);
    throw implementation_error("shouldn't get the global theta value, just set");
}

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

uiGrowth::uiGrowth()
    : SetGetBoolEnabled(uistr::growth)
{
}

uiGrowth::~uiGrowth()
{
}

bool uiGrowth::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_GROW);
}

void uiGrowth::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_GROW);
}

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

uiGrowthScheme::uiGrowthScheme()
    : SetGetGrowthScheme(uistr::growthScheme)
{
}

uiGrowthScheme::~uiGrowthScheme()
{
}

growth_scheme uiGrowthScheme::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetGrowthScheme();
}

void uiGrowthScheme::Set(UIVars& vars, UIId id, growth_scheme val)
{
    vars.forces.SetGrowthScheme(val);
}

string uiGrowthScheme::NextToggleValue(UIVars& vars, UIId id)
{
    switch(Get(vars,id))
    {
        case growth_EXP:
            return ToString(growth_STAIRSTEP);
            break;
        case growth_STAIRSTEP:
            // this is unsupported, present for toggle demo purposes
            return ToString(growth_EXP);
            break;
    }
    throw implementation_error("uiGrowthScheme::NextToggleValue bad switch case");
}

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

uiGrowthType::uiGrowthType()
    : SetGetGrowthType(uistr::growthType)
{
}

uiGrowthType::~uiGrowthType()
{
}

growth_type uiGrowthType::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetGrowthType();
}

void uiGrowthType::Set(UIVars& vars, UIId id, growth_type val)
{
    vars.forces.SetGrowthType(val);
}

string uiGrowthType::NextToggleValue(UIVars& vars, UIId id)
{
    switch(Get(vars,id))
    {
        case growth_CURVE:
            return ToString(growth_STICKEXP);
            break;
        case growth_STICK:
            // not sure we're supporting this for now--disabled
            // assert in debug, but fall through to recover for release
            assert(false);
        case growth_STICKEXP:
            return ToString(growth_CURVE);
            break;
    }
    throw implementation_error("uiGrowthType::NextToggleValue bad switch case");
}

string uiGrowthType::MakePrintString(UIVars& vars, growth_type val)
{
    switch(val)
    {
        case growth_CURVE:
            return "Curve";
            break;
        case growth_STICK:
            // not sure we're supporting this for now--disabled
            // assert in debug, but fall through to recover for release
            assert(false);
        case growth_STICKEXP:
            return "Stick";
            break;
    }
    throw implementation_error("uiGrowthType::MakePrintString bad switch case");
}

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

uiGrowthLegal::uiGrowthLegal()
    : GetBool(uistr::growthLegal)
{
}

uiGrowthLegal::~uiGrowthLegal()
{
}

bool uiGrowthLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_GROW);
}

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

void uiGlobalGrowth::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetAllGrowthStartValues(val);
}

double uiGlobalGrowth::Get(UIVars& vars, UIId id)
{
    assert(false);
    throw implementation_error("shouldn't get the global growth value, just set");
}

uiGlobalGrowth::uiGlobalGrowth()
    : uiParameter(uistr::globalGrowth)
{
}

uiGlobalGrowth::~uiGlobalGrowth()
{
}

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

void uiGrowthUser::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetGrowthStartValue(val,id.GetIndex1());
}

double uiGrowthUser::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_GROW,id.GetIndex1());
}

uiGrowthUser::uiGrowthUser()
    : uiParameter(uistr::growthByID)
{
}

uiGrowthUser::~uiGrowthUser()
{
}

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

long uiGrowthMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_GROW);
}

void uiGrowthMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_GROW);
}

uiGrowthMaxEvents::uiGrowthMaxEvents()
    : SetGetLong(uistr::growthMaxEvents)
{
}

uiGrowthMaxEvents::~uiGrowthMaxEvents()
{
}

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

uiLogisticSelection::uiLogisticSelection()
    : SetGetBoolEnabled(uistr::logisticSelection)
{
}

uiLogisticSelection::~uiLogisticSelection()
{
}

bool uiLogisticSelection::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_LOGISTICSELECTION);
}

void uiLogisticSelection::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_LOGISTICSELECTION);
}

uiLogisticSelectionLegal::uiLogisticSelectionLegal()
    : GetBool(uistr::logisticSelectionLegal)
{
}

uiLogisticSelectionLegal::~uiLogisticSelectionLegal()
{
}

bool uiLogisticSelectionLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_LOGISTICSELECTION);
}

void uiGlobalLogisticSelectionCoefficient::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetLogisticSelectionCoefficientStartValue(val);
}

double uiGlobalLogisticSelectionCoefficient::Get(UIVars& vars, UIId id)
{
    assert(false);
    throw implementation_error("shouldn't get the global logistic selection value, just set");
}

uiGlobalLogisticSelectionCoefficient::uiGlobalLogisticSelectionCoefficient()
    : uiParameter(uistr::globalLogisticSelectionCoefficient)
{
}

uiGlobalLogisticSelectionCoefficient::~uiGlobalLogisticSelectionCoefficient()
{
}

void uiLogisticSelectionCoefficientUser::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetLogisticSelectionCoefficientStartValue(val);
}

double uiLogisticSelectionCoefficientUser::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_LOGISTICSELECTION,0);
}

uiLogisticSelectionCoefficientUser::uiLogisticSelectionCoefficientUser()
    : uiParameter(uistr::logisticSelectionCoefficient)
{
}

uiLogisticSelectionCoefficientUser::~uiLogisticSelectionCoefficientUser()
{
}

long uiLogisticSelectionMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_LOGISTICSELECTION);
}

void uiLogisticSelectionMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_LOGISTICSELECTION);
}

uiLogisticSelectionMaxEvents::uiLogisticSelectionMaxEvents()
    : SetGetLong(uistr::logisticSelectionMaxEvents)
{
}

uiLogisticSelectionMaxEvents::~uiLogisticSelectionMaxEvents()
{
}

uiLogisticSelectionType::uiLogisticSelectionType()
    : SetGetSelectionType(uistr::selectType)
{
}

uiLogisticSelectionType::~uiLogisticSelectionType()
{
}

selection_type uiLogisticSelectionType::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetSelectionType();
}

void uiLogisticSelectionType::Set(UIVars& vars, UIId id, selection_type val)
{
    vars.forces.SetSelectionType(val);
}

string uiLogisticSelectionType::NextToggleValue(UIVars& vars, UIId id)
{
    switch(Get(vars,id))
    {
        case selection_DETERMINISTIC:
            return ToString(selection_DETERMINISTIC);
            break;
        case selection_STOCHASTIC:
            return ToString(selection_STOCHASTIC);
            break;
    }
    throw implementation_error("uiLogisticSelectionType::NextToggleValue bad switch case");
}

string uiLogisticSelectionType::MakePrintString(UIVars& vars, selection_type val)
{
    switch(val)
    {
        case selection_DETERMINISTIC:
            return "Deterministic";
            break;
        case selection_STOCHASTIC:
            return "Stochastic";
            break;
    }
    throw implementation_error("uiLogisticSelectionType::MakePrintString bad switch case");
}

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

bool uiMigration::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_MIG);
}

void uiMigration::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_MIG);
}

uiMigration::uiMigration()
    : SetGetBoolEnabled(uistr::migration)
{
}

uiMigration::~uiMigration()
{
}

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

uiMigrationLegal::uiMigrationLegal()
    : GetBool(uistr::migrationLegal)
{
}

uiMigrationLegal::~uiMigrationLegal()
{
}

bool uiMigrationLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_MIG);
}

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

void uiMigrationUser::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetMigrationStartValue(val,id.GetIndex1());
}

double uiMigrationUser::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_MIG,id.GetIndex1());
}

uiMigrationUser::uiMigrationUser()
    : uiParameter(uistr::migrationUser)
{
}

uiMigrationUser::~uiMigrationUser()
{
}

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

string uiMigrationInto::Get(UIVars& vars, UIId id)
{
    string row = "";
    long toPop = id.GetIndex1();
    long npops = vars.datapackplus.GetNPartitionsByForceType(force_MIG);
    long rowsdisplayed = std::min(npops,uiconst::migColumns);
    long rowindex;
    for(rowindex = 0; rowindex < rowsdisplayed; rowindex++)
    {
        row += " ";
        long fromPop = rowindex;
        if(fromPop == toPop)
        {
            row += " - ";
        }
        else
        {
            long colId = fromPop + npops * toPop;
            double migRate =
                vars.forces.GetStartValue(force_MIG,colId);
            row += ToString(migRate);
        }
    }
    if(npops > uiconst::migColumns)
    {
        row += " ...";
    }
    return row;
}

uiMigrationInto::uiMigrationInto()
    : GetString(uistr::migrationInto)
{
}

uiMigrationInto::~uiMigrationInto()
{
}

string uiMigrationInto::Description(UIVars& vars, UIId id)
{

    string returnVal(UIKey());
    returnVal += vars.datapackplus.GetForcePartitionName(force_MIG,id.GetIndex1());
    return returnVal;
}

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

void uiMigrationFst::Set(UIVars& vars, UIId id, noval val)
{
    vars.forces.SetAllMigrationStartValuesFST();
}

uiMigrationFst::uiMigrationFst()
    : SetGetNoval(uistr::fstSetMigration)
{
}

uiMigrationFst::~uiMigrationFst()
{
}

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

double uiMigrationGlobal::Get(UIVars& vars, UIId id)
{
    assert(false);
    throw implementation_error("shouldn't get the global migration value, just set");
}

void uiMigrationGlobal::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetAllMigrationStartValues(val);
}

uiMigrationGlobal::uiMigrationGlobal()
    : uiParameter(uistr::globalMigration)
{
}

uiMigrationGlobal::~uiMigrationGlobal()
{
}

long uiMigrationMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_MIG);
}

void uiMigrationMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_MIG);
}

uiMigrationMaxEvents::uiMigrationMaxEvents()
    : SetGetLong(uistr::migrationMaxEvents)
{
}

uiMigrationMaxEvents::~uiMigrationMaxEvents()
{
}

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

bool uiDivMigration::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_DIVMIG);
}

void uiDivMigration::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_DIVMIG);
}

uiDivMigration::uiDivMigration()
    : SetGetBoolEnabled(uistr::divmigration)
{
}

uiDivMigration::~uiDivMigration()
{
}

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

uiDivMigrationLegal::uiDivMigrationLegal()
    : GetBool(uistr::divmigrationLegal)
{
}

uiDivMigrationLegal::~uiDivMigrationLegal()
{
}

bool uiDivMigrationLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_DIVMIG);
}

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

void uiDivMigrationUser::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetDivMigrationStartValue(val,id.GetIndex1());
}

double uiDivMigrationUser::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_DIVMIG,id.GetIndex1());
}

uiDivMigrationUser::uiDivMigrationUser()
    : uiParameter(uistr::divmigrationUser)
{
}

uiDivMigrationUser::~uiDivMigrationUser()
{
}

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

string uiDivMigrationInto::Get(UIVars& vars, UIId id)
{
    string row = "";
    long toPop = id.GetIndex1();
    long npops = vars.datapackplus.GetNPartitionsByForceType(force_DIVMIG);
    long rowsdisplayed = std::min(npops,uiconst::migColumns);
    long rowindex;
    for(rowindex = 0; rowindex < rowsdisplayed; rowindex++)
    {
        row += " ";
        long fromPop = rowindex;
        if(fromPop == toPop)
        {
            row += " - ";
        }
        else
        {
            long colId = fromPop + npops * toPop;
            double migRate =
                vars.forces.GetStartValue(force_DIVMIG,colId);
            row += ToString(migRate);
        }
    }
    if(npops > uiconst::migColumns)
    {
        row += " ...";
    }
    return row;
}

uiDivMigrationInto::uiDivMigrationInto()
    : GetString(uistr::divmigrationInto)
{
}

uiDivMigrationInto::~uiDivMigrationInto()
{
}

string uiDivMigrationInto::Description(UIVars& vars, UIId id)
{

    string returnVal(UIKey());
    returnVal += vars.datapackplus.GetForcePartitionName(force_DIVMIG,id.GetIndex1());
    return returnVal;
}

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

#if 0  // MREMOVE destroying this class as DIVMIG can't do FST
void uiDivMigrationFst::Set(UIVars& vars, UIId id, noval val)
{
    vars.forces.SetAllMigrationStartValuesFST();
}

uiDivMigrationFst::uiDivMigrationFst()
    : SetGetNoval(uistr::fstSetDivMigration)
{
}

uiDivMigrationFst::~uiDivMigrationFst()
{
}
#endif

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

double uiDivMigrationGlobal::Get(UIVars& vars, UIId id)
{
    assert(false);
    throw implementation_error("shouldn't get the global migration value, just set");
}

void uiDivMigrationGlobal::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetAllDivMigrationStartValues(val);
}

uiDivMigrationGlobal::uiDivMigrationGlobal()
    : uiParameter(uistr::globalDivMigration)
{
}

uiDivMigrationGlobal::~uiDivMigrationGlobal()
{
}

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

long uiDivMigrationMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_DIVMIG);
}

void uiDivMigrationMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_DIVMIG);
}

uiDivMigrationMaxEvents::uiDivMigrationMaxEvents()
    : SetGetLong(uistr::divmigrationMaxEvents)
{
}

uiDivMigrationMaxEvents::~uiDivMigrationMaxEvents()
{
}

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

bool uiDivergence::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_DIVERGENCE);
}

void uiDivergence::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_DIVERGENCE);
}

uiDivergence::uiDivergence()
    : SetGetBoolEnabled(uistr::divergence)
{
}

uiDivergence::~uiDivergence()
{
}

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

string uiDivergenceEpochAncestor::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetEpochAncestorName(id.GetIndex1());
}

uiDivergenceEpochAncestor::uiDivergenceEpochAncestor()
    : GetString(uistr::divergenceEpochAncestor)
{
}

uiDivergenceEpochAncestor::~uiDivergenceEpochAncestor()
{
}

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

string uiDivergenceEpochDescendents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetEpochDescendentNames(id.GetIndex1());
}

uiDivergenceEpochDescendents::uiDivergenceEpochDescendents()
    : GetString(uistr::divergenceEpochDescendents)
{
}

uiDivergenceEpochDescendents::~uiDivergenceEpochDescendents()
{
}

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

uiDivergenceLegal::uiDivergenceLegal()
    : GetBool(uistr::divergenceLegal)
{
}

uiDivergenceLegal::~uiDivergenceLegal()
{
}

bool uiDivergenceLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_DIVERGENCE);
}

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

long uiDivergenceEpochCount::Get(UIVars& vars, UIId id)
{
    return vars.datapackplus.GetNPartitionsByForceType(force_DIVERGENCE);
}

uiDivergenceEpochCount::uiDivergenceEpochCount()
    : GetLong(uistr::divergenceEpochCount)
{
}

uiDivergenceEpochCount::~uiDivergenceEpochCount()
{
}

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

string uiDivergenceEpochName::Get(UIVars& vars, UIId id)
{
    return vars.datapackplus.GetForcePartitionName(force_DIVERGENCE,id.GetIndex1());
}

uiDivergenceEpochName::uiDivergenceEpochName()
    : GetString(uistr::divergenceEpochName)
{
}

uiDivergenceEpochName::~uiDivergenceEpochName()
{
}

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

double uiDivergenceEpochBoundaryTime::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_DIVERGENCE,id.GetIndex1());
}

void uiDivergenceEpochBoundaryTime::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetDivergenceEpochStartTime(val,id.GetIndex1());
}

uiDivergenceEpochBoundaryTime::uiDivergenceEpochBoundaryTime()
    : uiParameter(uistr::divergenceEpochBoundaryTime)
{
}

uiDivergenceEpochBoundaryTime::~uiDivergenceEpochBoundaryTime()
{
}

string uiDivergenceEpochBoundaryTime::Description(UIVars& vars, UIId id)
{
    //string returnVal = vars.datapackplus.GetAncestorName(id.GetIndex1());
    string returnVal = uistr::divergenceEpoch;
    returnVal += " ";
    returnVal += ToString(id.GetIndex1() + 1);
    returnVal += " ";
    returnVal += UIKey();

    //string txtstr(UIKey());
    //returnVal += txtstr;
    return returnVal;
}

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

bool uiRecombine::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_REC);
}

void uiRecombine::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_REC);
}

uiRecombine::uiRecombine()
    : SetGetBoolEnabled(uistr::recombination)
{
}

uiRecombine::~uiRecombine()
{
}

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

uiRecombineLegal::uiRecombineLegal()
    : GetBool(uistr::recombinationLegal)
{
}

uiRecombineLegal::~uiRecombineLegal()
{
}

bool uiRecombineLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_REC);
}

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

double uiRecombinationRate::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_REC,0);
}

void uiRecombinationRate::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetRecombinationStartValue(val);
}

uiRecombinationRate::uiRecombinationRate()
    : uiParameter(uistr::recombinationRate)
{
}

uiRecombinationRate::~uiRecombinationRate()
{
}

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

long uiRecombinationMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_REC);
}

void uiRecombinationMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_REC);
}

uiRecombinationMaxEvents::uiRecombinationMaxEvents()
    : SetGetLong(uistr::recombinationMaxEvents)
{
}

uiRecombinationMaxEvents::~uiRecombinationMaxEvents()
{
}

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

bool uiRegionGamma::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_REGION_GAMMA);
}

void uiRegionGamma::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_REGION_GAMMA);
}

uiRegionGamma::uiRegionGamma()
    : SetGetBoolEnabled(uistr::regionGamma)
{
}

uiRegionGamma::~uiRegionGamma()
{
}

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

uiRegionGammaLegal::uiRegionGammaLegal()
    : GetBool(uistr::regionGammaLegal)
{
}

uiRegionGammaLegal::~uiRegionGammaLegal()
{
}

bool uiRegionGammaLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_REGION_GAMMA);
}

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

double uiRegionGammaShape::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_REGION_GAMMA,0);
}

void uiRegionGammaShape::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetRegionGammaStartValue(val);
}

uiRegionGammaShape::uiRegionGammaShape()
    : uiParameter(uistr::regionGammaShape)
{
}

uiRegionGammaShape::~uiRegionGammaShape()
{
}

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

uiDisease::uiDisease()
    : SetGetBoolEnabled(uistr::disease)
{
}

uiDisease::~uiDisease()
{
}

bool uiDisease::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceOnOff(force_DISEASE);
}

void uiDisease::Set(UIVars& vars, UIId id, bool val)
{
    vars.forces.SetForceOnOff(val,force_DISEASE);
}

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

uiDiseaseLegal::uiDiseaseLegal()
    : GetBool(uistr::diseaseLegal)
{
}

uiDiseaseLegal::~uiDiseaseLegal()
{
}

bool uiDiseaseLegal::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetForceLegal(force_DISEASE);
}

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

long uiDiseaseMaxEvents::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetMaxEvents(force_DISEASE);
}

void uiDiseaseMaxEvents::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetMaxEvents(val,force_DISEASE);
}

uiDiseaseMaxEvents::uiDiseaseMaxEvents()
    : SetGetLong(uistr::diseaseMaxEvents)
{
}

uiDiseaseMaxEvents::~uiDiseaseMaxEvents()
{
}

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

double uiDiseaseGlobal::Get(UIVars& vars, UIId id)
{
    assert(false);
    throw implementation_error("shouldn't get the global disease value, just set");
}

void uiDiseaseGlobal::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetAllDiseaseStartValues(val);
}

uiDiseaseGlobal::uiDiseaseGlobal()
    : uiParameter(uistr::globalDisease)
{
}

uiDiseaseGlobal::~uiDiseaseGlobal()
{
}

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

void uiDiseaseByID::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetDiseaseStartValue(val,id.GetIndex1());
}

double uiDiseaseByID::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(force_DISEASE,id.GetIndex1());
}

uiDiseaseByID::uiDiseaseByID()
    : uiParameter(uistr::diseaseByID)
{
}

uiDiseaseByID::~uiDiseaseByID()
{
}

// EWFIX.P5 REFACTOR -- use UIId to index these instead of having per-force versions

string uiDiseaseInto::Get(UIVars& vars, UIId id)
{
    string row = "";
    long toPop = id.GetIndex1();
    long nstati = vars.datapackplus.GetNPartitionsByForceType(force_DISEASE);
    long rowsdisplayed = std::min(nstati,uiconst::diseaseColumns);
    long rowindex;
    for(rowindex = 0; rowindex < rowsdisplayed; rowindex++)
    {
        row += " ";
        long fromPop = rowindex;
        if(fromPop == toPop)
        {
            row += " - ";
        }
        else
        {
            long colId = fromPop + nstati * toPop;
            double disRate = vars.forces.GetStartValue(force_DISEASE,colId);
            row += ToString(disRate);
        }
    }
    if(nstati > uiconst::diseaseColumns)
    {
        row += " ...";
    }
    return row;
}

uiDiseaseInto::uiDiseaseInto()
    : GetString(uistr::diseaseInto)
{
}

uiDiseaseInto::~uiDiseaseInto()
{
}

string uiDiseaseInto::Description(UIVars& vars, UIId id)
{
    string returnVal(UIKey());
    returnVal += vars.datapackplus.GetForcePartitionName(force_DISEASE,id.GetIndex1());
    return returnVal;
}

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

long uiDiseaseLocation::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetDiseaseLocation();
}

void uiDiseaseLocation::Set(UIVars& vars, UIId id, long val)
{
    vars.forces.SetDiseaseLocation(val);
}

uiDiseaseLocation::uiDiseaseLocation()
    : SetGetLong(uistr::diseaseLocation)
{
}

uiDiseaseLocation::~uiDiseaseLocation()
{
}

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

//Honestly, this needs to be the default instead of all that uiUser<force>, above.

double
uiStartValue::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartValue(id.GetForceType(),id.GetIndex1());
}

void
uiStartValue::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetUserStartValue(val,id.GetForceType(),id.GetIndex1());
}

uiStartValue::uiStartValue()
    : SetGetDouble(uistr::startValue)
{
}

uiStartValue::~uiStartValue()
{
}

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

method_type
uiStartValueMethod::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetStartMethod(id.GetForceType(),id.GetIndex1());
}

void
uiStartValueMethod::Set(UIVars& vars, UIId id, method_type mtype)
{
    if(mtype != method_USER)
    {
        // method_USER methods should already be set with
        // uiStartValues object before we get here
        vars.forces.SetStartMethod(mtype,id.GetForceType(),id.GetIndex1());
    }
}

uiStartValueMethod::uiStartValueMethod()
    : SetGetMethodType(uistr::startValueMethod)
{
}

uiStartValueMethod::~uiStartValueMethod()
{
}

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

double
uiTrueValue::Get(UIVars& vars, UIId id)
{
    return vars.forces.GetTrueValue(id.GetForceType(),id.GetIndex1());
}

void
uiTrueValue::Set(UIVars& vars, UIId id, double val)
{
    vars.forces.SetTrueValue(val,id.GetForceType(),id.GetIndex1());
}

uiTrueValue::uiTrueValue()
    : SetGetDouble(uistr::trueValue)
{
}

uiTrueValue::~uiTrueValue()
{
}

//____________________________________________________________________________________
