// $Id: gc_data.cpp,v 1.39 2018/01/03 21:32:59 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: Mary Kuhner, Jon Yamato, and Joseph Felsenstein */


#include <cassert>

#include "cnv_strings.h"
#include "gc_cmdfile_err.h"
#include "gc_data.h"
#include "gc_strings.h"
#include "gc_strings_mig.h"
#include "gc_types.h"
#include "constants.h"
#include "wx/dynarray.h"
#include "wx/log.h"

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

const size_t gcdata::defaultHapCount    = 2;

const long gcdata::noLengthSet          = -1;
const long gcdata::noMarkerCountSet     = -1;
const long gcdata::noMapPositionSet     = -1;
const long gcdata::noOffsetSet          = -1;
const long gcdata::noStyle              =  0;
const long gcdata::defaultMapPosition   =  0;
const long gcdata::defaultOffset        =  0;

const GCFileFormat  gcdata::defaultFileFormat   =   format_NONE_SET;

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

const wxArrayString gcdata::specificDataTypeChoices()
{
    static wxArrayString dataTypes;
    if(dataTypes.GetCount() < 1)
    {
        dataTypes.Add(gcstr::unknown);
        dataTypes.Add(gcstr::dna);
        dataTypes.Add(gcstr::snp);
        dataTypes.Add(gcstr::microsat);
        dataTypes.Add(gcstr::kallele);
    }
    return dataTypes;
}

const wxArrayString gcdata::fileFormatChoices()
{
    static wxArrayString fileTypes;
    if(fileTypes.GetCount() < 1)
    {
        fileTypes.Add(gcstr::unknown);
        fileTypes.Add(gcstr::migrate);
        fileTypes.Add(gcstr::phylip);
    }
    return fileTypes;
}

const wxArrayString gcdata::interleavingChoices()
{
    static wxArrayString interleavingChoices;
    if(interleavingChoices.GetCount() < 1)
    {
        interleavingChoices.Add(gcstr::unknown);
        interleavingChoices.Add(gcstr::sequential);
        interleavingChoices.Add(gcstr::interleaved);
    }
    return interleavingChoices;
}

const wxArrayString gcdata::genericLocusChoices()
{
    static wxArrayString locusChoices;
    if(locusChoices.GetCount() < 1)
    {
        locusChoices.Add(gcstr::locusSelect);
        locusChoices.Add(gcstr::locusCreate);
    }
    return locusChoices;
}

const wxArrayString gcdata::genericRegionChoices()
{
    static wxArrayString regionChoices;
    if(regionChoices.GetCount() < 1)
    {
        regionChoices.Add(gcstr::regionSelect);
        regionChoices.Add(gcstr::regionCreate);
    }
    return regionChoices;
}

const wxArrayString gcdata::genericPopulationChoices()
{
    static wxArrayString populationChoices;
    if(populationChoices.GetCount() < 1)
    {
        populationChoices.Add(gcstr::populationSelect);
        populationChoices.Add(gcstr::populationCreate);
    }
    return populationChoices;
}

const wxArrayString gcdata::migrationConstraints()
{
    static wxArrayString migrationChoices;
    if(migrationChoices.GetCount() < 1)
    {
        migrationChoices.Add(gcstr_mig::migconstraintInvalid);
        migrationChoices.Add(gcstr_mig::migconstraintConstant);
        migrationChoices.Add(gcstr_mig::migconstraintSymmetric);
        migrationChoices.Add(gcstr_mig::migconstraintUnconstained);
    }
    return migrationChoices;
}

const wxArrayString gcdata::migrationMethods()
{
    static wxArrayString migrationMethods;
    if(migrationMethods.GetCount() < 1)
    {
        migrationMethods.Add(gcstr_mig::migmethodUser);
        migrationMethods.Add(gcstr_mig::migmethodFST);
    }
    return migrationMethods;
}

const wxArrayString gcdata::migrationProfiles()
{
    static wxArrayString migrationProfiles;
    if(migrationProfiles.GetCount() < 1)
    {
        migrationProfiles.Add(gcstr_mig::migprofileNone);
        migrationProfiles.Add(gcstr_mig::migprofileFixed);
        migrationProfiles.Add(gcstr_mig::migprofilePercentile);
    }
    return migrationProfiles;
}

const wxArrayString
gcdata::integerList()
{
    static wxArrayString digits;
    if(digits.GetCount() < 1)
    {
        digits.Add("-");
        digits.Add("0");
        digits.Add("1");
        digits.Add("2");
        digits.Add("3");
        digits.Add("4");
        digits.Add("5");
        digits.Add("6");
        digits.Add("7");
        digits.Add("8");
        digits.Add("9");
    }
    return digits;
}
const wxArrayString
gcdata::integerListWithSpaces()
{
    static wxArrayString digits;
    if(digits.GetCount() < 1)
    {
        digits.Add(" ");
        digits.Add("-");
        digits.Add("0");
        digits.Add("1");
        digits.Add("2");
        digits.Add("3");
        digits.Add("4");
        digits.Add("5");
        digits.Add("6");
        digits.Add("7");
        digits.Add("8");
        digits.Add("9");
    }
    return digits;
}

const wxArrayString
gcdata::nonNegativeIntegerList()
{
    static wxArrayString digits;
    if(digits.GetCount() < 1)
    {
        digits.Add("0");
        digits.Add("1");
        digits.Add("2");
        digits.Add("3");
        digits.Add("4");
        digits.Add("5");
        digits.Add("6");
        digits.Add("7");
        digits.Add("8");
        digits.Add("9");
    }
    return digits;
}

const wxArrayString
gcdata::positiveFloatChars()
{
    static wxArrayString digits;
    if(digits.GetCount() < 1)
    {
        digits.Add("0");
        digits.Add("1");
        digits.Add("2");
        digits.Add("3");
        digits.Add("4");
        digits.Add("5");
        digits.Add("6");
        digits.Add("7");
        digits.Add("8");
        digits.Add("9");
        digits.Add(".");
    }
    return digits;
}

const gcGeneralDataType
gcdata::allDataTypes()
{
    static gcGeneralDataType dtype;
    if(dtype.empty())
    {
        dtype.insert(sdatatype_DNA);
        dtype.insert(sdatatype_SNP);
        dtype.insert(sdatatype_MICROSAT);
        dtype.insert(sdatatype_KALLELE);
    }
    return dtype;
}

const gcGeneralDataType
gcdata::allelicDataTypes()
{
    static gcGeneralDataType dtype;
    if(dtype.empty())
    {
        dtype.insert(sdatatype_MICROSAT);
        dtype.insert(sdatatype_KALLELE);
    }
    return dtype;
}

const gcGeneralDataType
gcdata::nucDataTypes()
{
    static gcGeneralDataType dtype;
    if(dtype.empty())
    {
        dtype.insert(sdatatype_DNA);
        dtype.insert(sdatatype_SNP);
    }
    return dtype;
}

wxString
gcdata::getPloidyString(size_t ploidy)
{
    if(ploidy == 1) return gcstr::ploidy_1;
    if(ploidy == 2) return gcstr::ploidy_2;
    if(ploidy == 3) return gcstr::ploidy_3;
    if(ploidy == 4) return gcstr::ploidy_4;
    return wxString::Format(gcstr::ploidy,(int)ploidy);
}

bool
ProduceBoolFromProximityOrBarf(wxString string)
{
    if (string.CmpNoCase(gcstr::linkageYes) == 0) return true;
    if (string.CmpNoCase(gcstr::linkageNo) == 0) return false;

    throw gc_bad_proximity(string);
}

bool
ProduceBoolFromYesNoOrBarf(wxString string)
{
    if (string.CmpNoCase(gcstr::yes) == 0) return true;
    if (string.CmpNoCase(gcstr::no)  == 0) return false;

    throw gc_bad_yes_no(string);
}

gcGeneralDataType
ProduceGeneralDataTypeOrBarf(wxString string, bool allowUnknown)
{
    gcGeneralDataType dataTypes;

    if(allowUnknown)
    {
        if (string.CmpNoCase(gcstr::unknown) == 0)
        {
            return dataTypes;
        }
    }

    if (string.CmpNoCase(gcstr::nuc) == 0)
    {
        dataTypes.insert(sdatatype_DNA);
        dataTypes.insert(sdatatype_SNP);
        return dataTypes;
    }

    if (string.CmpNoCase(gcstr::allelic) == 0)
    {
        dataTypes.insert(sdatatype_MICROSAT);
        dataTypes.insert(sdatatype_KALLELE);
        return dataTypes;
    }

    throw gc_bad_general_data_type(string);
    return dataTypes;
}

gcSpecificDataType
ProduceSpecificDataTypeOrBarf(wxString string, bool allowUnknown)
{
    if(allowUnknown)
    {
        if (string.CmpNoCase(gcstr::unknown) == 0)  return sdatatype_NONE_SET;
    }
    if (string.CmpNoCase(gcstr::dna) == 0)      return sdatatype_DNA;
    if (string.CmpNoCase(gcstr::snp) == 0)      return sdatatype_SNP;
    if (string.CmpNoCase(gcstr::kallele) == 0)  return sdatatype_KALLELE;
    if (string.CmpNoCase(gcstr::microsat) == 0) return sdatatype_MICROSAT;

    throw gc_bad_specific_data_type(string);
    return sdatatype_NONE_SET;
}

GCFileFormat
ProduceGCFileFormatOrBarf(wxString string, bool allowUnknown)
{
    if(allowUnknown)
    {
        if (string.CmpNoCase(gcstr::unknown) == 0)  return format_NONE_SET;
    }
    if (string.CmpNoCase(gcstr::migrate) == 0)  return format_MIGRATE;
    if (string.CmpNoCase(gcstr::phylip) == 0)   return format_PHYLIP;

    throw gc_bad_file_format(string);
    return format_NONE_SET;

}

GCInterleaving
ProduceGCInterleavingOrBarf(wxString string, bool allowUnknown)
{
    if(allowUnknown)
    {
        if (string.CmpNoCase(gcstr::unknown) == 0)      return interleaving_NONE_SET;
    }
    if (string.CmpNoCase(gcstr::interleaved) == 0)  return interleaving_INTERLEAVED;
    if (string.CmpNoCase(gcstr::sequential) == 0)   return interleaving_SEQUENTIAL;
    //EWFIX.FROMLUCIAN:  do we need moot any more?
    if (string.CmpNoCase(gcstr::moot) == 0)         return interleaving_MOOT;

    throw gc_bad_interleaving(string);
    return interleaving_NONE_SET;
}

migration_method
ProduceMigMethodOrBarf(wxString string)
{
    if (string.CmpNoCase(gcstr_mig::migmethodUser) == 0)  return migmethod_USER;
    if (string.CmpNoCase(gcstr_mig::migmethodFST) == 0)   return migmethod_FST;
    return migmethod_USER;
}

migration_profile
ProduceMigProfileOrBarf(wxString string)
{
    if (string.CmpNoCase(gcstr_mig::migprofileNone) == 0)  return migprofile_NONE;
    if (string.CmpNoCase(gcstr_mig::migprofileFixed) == 0)  return migprofile_FIXED;
    if (string.CmpNoCase(gcstr_mig::migprofilePercentile) == 0)  return migprofile_PERCENTILE;
    return     migprofile_NONE;
}

migration_constraint
ProduceMigConstraintOrBarf(wxString string)
{
    if (string.CmpNoCase(gcstr_mig::migconstraintInvalid) == 0)  return migconstraint_INVALID;
    if (string.CmpNoCase(gcstr_mig::migconstraintConstant) == 0)   return migconstraint_CONSTANT;
    if (string.CmpNoCase(gcstr_mig::migconstraintSymmetric) == 0)   return migconstraint_SYMMETRIC;
    if (string.CmpNoCase(gcstr_mig::migconstraintUnconstained) == 0)   return migconstraint_UNCONSTRAINED;
    return migconstraint_UNCONSTRAINED;
}

wxString
ToWxString(bool booleanValue)
{
    if(booleanValue) return gcstr::trueVal;
    return gcstr::falseVal;
}

wxString
ToWxStringLinked(bool booleanValue)
{
    if(booleanValue) return gcstr::linkageYes;
    return gcstr::linkageNo;
}

wxString
ToWxString(gcGeneralDataType dtype)
{
    wxString retStr = "";
    for(gcGeneralDataType::const_iterator i = dtype.begin(); i != dtype.end(); i++)
    {
        if(i != dtype.begin() && dtype.size() > 1)
        {
            retStr += "/";  // EWFIX.STRINGS
        }
        retStr += ToWxString((gcSpecificDataType)(*i));
    }

    if (retStr.IsEmpty())
    {
        retStr = ToWxString(sdatatype_NONE_SET);
    }

    return retStr;
}

wxString
ToWxString(gcSpecificDataType type)
{
    switch(type)
    {
        case sdatatype_NONE_SET:
            return gcstr::unknown;
            break;
        case sdatatype_DNA:
            return gcstr::dna;
            break;
        case sdatatype_SNP:
            return gcstr::snp;
            break;
        case sdatatype_MICROSAT:
            return gcstr::microsat;
            break;
        case sdatatype_KALLELE:
            return gcstr::kallele;
            break;
    }
    assert(false);
    return wxT("");
}

wxString
ToWxString(GCFileFormat format)
{
    switch(format)
    {
        case format_NONE_SET:
            return gcstr::unknown;
            break;
        case format_MIGRATE:
            return gcstr::migrate;
            break;
        case format_PHYLIP:
            return gcstr::phylip;
            break;
    }
    assert(false);
    return wxT("");
}

wxString
ToWxString(GCInterleaving interleaving)
{
    switch(interleaving)
    {
        case interleaving_NONE_SET:
            return gcstr::unknown;
            break;
        case interleaving_SEQUENTIAL:
            return gcstr::sequential;
            break;
        case interleaving_INTERLEAVED:
            return gcstr::interleaved;
            break;
        case interleaving_MOOT:
            return gcstr::moot;
            break;
    }
    assert(false);
    return wxT("");
}

wxString
ToWxString(gcPhaseSource ps)
{
    switch(ps)
    {
        case phaseSource_NONE_SET:
            return gcstr::unknown;
            break;
        case phaseSource_PHASE_FILE:
            return gcstr::phaseFile;
            break;
        case phaseSource_MULTI_PHASE_SAMPLE:
            return gcstr::multiPhaseSample;
            break;
        case phaseSource_FILE_ADJACENCY:
            return gcstr::fileSetting;
            break;
        case phaseSource_COUNT:
            assert(false);
            return gcstr::unknown;
            break;
    }
    assert(false);
    return wxT("");
}

wxString
ToWxString(loc_match lm)
{
    switch(lm)
    {
        case locmatch_DEFAULT:
            return cnvstr::ATTR_VAL_DEFAULT;
            break;
        case locmatch_SINGLE:
            return cnvstr::ATTR_VAL_SINGLE;
            break;
        case locmatch_LINKED:
            return cnvstr::ATTR_VAL_LINKED;
            break;
        case locmatch_VECTOR:
            return cnvstr::ATTR_VAL_BYLIST;
            break;
    }
    assert(false);
    return gcstr::unknown;
}

wxString
ToWxString(pop_match lm)
{
    switch(lm)
    {
        case popmatch_DEFAULT:
            return cnvstr::ATTR_VAL_DEFAULT;
            break;
        case popmatch_NAME:
            return cnvstr::ATTR_VAL_BYNAME;
            break;
        case popmatch_SINGLE:
            return cnvstr::ATTR_VAL_SINGLE;
            break;
        case popmatch_VECTOR:
            return cnvstr::ATTR_VAL_BYLIST;
            break;
    }
    assert(false);
    return gcstr::unknown;
}

wxString
ToWxString(migration_method mm)
{
    switch(mm)
    {
        case migmethod_USER:
            return gcstr_mig::migmethodUser;
            break;
        case migmethod_FST:
            return gcstr_mig::migmethodFST;
            break;
    }
    assert(false);
    return gcstr::unknown;
}

wxString
ToWxString(migration_profile mp)
{
    switch(mp)
    {
        case migprofile_NONE:
            return gcstr_mig::migprofileNone;
            break;
        case migprofile_FIXED:
            return gcstr_mig::migprofileFixed;
            break;
        case migprofile_PERCENTILE:
            return gcstr_mig::migprofilePercentile;
            break;
    }
    assert(false);
    return gcstr::unknown;
}

wxString
ToWxString(migration_constraint mc)
{
    switch(mc)
    {
        case migconstraint_INVALID:
            return gcstr_mig::migconstraintInvalid;
            break;
        case migconstraint_CONSTANT:
            return gcstr_mig::migconstraintConstant;
            break;
        case migconstraint_SYMMETRIC:
            return gcstr_mig::migconstraintSymmetric;
            break;
        case migconstraint_UNCONSTRAINED:
            return gcstr_mig::migconstraintUnconstained;
            break;
    }
    assert(false);
    return gcstr::unknown;
}


//____________________________________________________________________________________
