// $Id: locus.h,v 1.53 2018/01/03 21:32:57 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 */


/***************************************************************
 The Locus class contains data information for one locus.

 The LocusVec is a managed container of Locus objects which knows
 that some represent "fixed" and others represent "floating" loci.

 NB  This code distinguishes between "markers" and "sites".  A marker
 is a site for which we have data.  In SNP data, for example, every base
 pair is a site, but only the SNPs are markers.  Data likelihoods are
 calculated on markers; recombination probabilities are calculated on
 sites (links, actually).  Please keep these straight!

 Locus written by Mary Kuhner 2002/07/24
 2004/09/15 Moved TipData class to its own file--Mary
 2004/09/15 Merged in functionality of class LocusLike--Mary
 2004/10/05 Added managed container class LocusVec--Mary
****************************************************************/

#ifndef LOCUS_H
#define LOCUS_H

#include <cassert>                      // May be needed for inline definitions.
#include <map>
#include <string>
#include <vector>

#include "types.h"
#include "vectorx.h"
#include "dlmodel.h"
#include "dlcalc.h"
#include "locuscell.h"
#include "phenotypes.h"
#include "tipdata.h"
#include "ui_vars_traitmodels.h"

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

class Individual;

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

class Locus
{
    typedef std::map<force_type,std::string> tipidtype;

  private:
    long            m_index;            // position in vector
    string          m_name;
    long            m_nmarkers;
    long            m_nsites;
    long            m_regionalmapposition; // numbered from start of region
    long            m_globalmapposition; // numbered in user's coordinate system
    long            m_offset;
    bool            m_movable;          // If possible, this should move to phase-1 only.
    mloc_type       m_type;             // And this should be phase-2.
    bool            m_defaultlocations; // phase-1
    LongVec1d       m_positions;        // dim: markers
    DataType_ptr    m_pDatatype;
    DataModel_ptr   m_pDatamodel;
    vector<TipData> m_tipdata;          // dim: tips (LS DEBUG:  phase 1)

    LocusCell       m_protoCell;
    DLCalc_ptr      m_pDLCalculator;
    vector<LocusCell> m_tipcells;       // dim: tips  (LS DEBUG:  phase 2)
    rangeset        m_allowedrange;
    rangeset        m_variablerange;    // LS DEBUG SIM:  probably don't need later.
    rangeset        m_unknownrange;     // LS DEBUG SIM:  probably don't need later.

    DoubleVec1d     m_map;
    DoubleVec1d     m_rawmap;

    // For simulation purposes.
    bool            m_simulate;
    long            m_truesite;
    std::map<long,DoubleVec1d> m_variability;
    Phenotypes      m_phenotypes;       //Phase 2 (during phase 1, it lives elsewhere)

    // Helper function for CalcNVariableMarkers().
    long            CalcNVariableMarkers(tipidtype xpart) const;

  public:

    // Construction/destruction.
    // We accept dtor, copy ctor and op=, though with some doubts about the latter two.
    // Apparently this class is copied only to put it into a vector and the original is discarded,
    // so sharing datatype and datamodel is not a problem.
    Locus(long ind, bool movable, string name);

    // Getters.
    long          GetIndex()          const { return m_index; };
    string        GetName()           const;
    long          GetNmarkers()       const { return m_nmarkers; };
    long          GetNsites()         const;
    long     GetGlobalMapPosition()   const { return m_globalmapposition; };
    long     GetRegionalMapPosition() const { return m_regionalmapposition; };
    long          GetOffset()         const;
    LongVec1d     GetMarkerLocations()     const { return m_positions; };
    LongVec1d     GetUserMarkerLocations() const;
    data_type     GetDataType()       const { return m_pDatatype->GetType(); };
    DataType_ptr  GetDataTypePtr()    const { return m_pDatatype; };
    DataModel_ptr GetDataModel()      const { return m_pDatamodel; };
    double        GetMuRate()         const { return m_pDatamodel->GetRelMuRate(); };
    DLCalc_ptr    GetDLCalc()         const { return m_pDLCalculator; };
    LocusCell     GetProtoCell()      const { return m_protoCell; };
    vector<LocusCell> GetTipCells()   const { return m_tipcells; };
    vector<TipData>& GetTipData()           { return m_tipdata; };
    const vector<TipData>& GetTipData() const { return m_tipdata; };
    vector<TipData> GetPopulationTipData(const std::string& popname) const;
    StringVec2d   GetCrossPartitionGeneticData(tipidtype xpart) const;
    StringVec3d   GetPartitionGeneticData(force_type partname) const;
    StringVec1d   GetMarkerDataWithLabels(const std::vector<Individual>&) const;// dim: ntips
    long          GetNTips()          const { return m_tipdata.size(); };
    long          GetNTips(tipidtype xpart) const;
    rangeset      GetAllowedRange() const {return m_allowedrange;};
    DoubleVec1d   GetMappingInfo() const {return m_map;};
    DoubleVec1d   GetRawMappingInfo() const {return m_rawmap;};
    bool          GetShouldSimulate() const {return m_simulate;};

    // Helper for F84 Model base freqs setting, called by Region::CountNBases().
    DoubleVec1d   CountNNucleotides() const;

    bool          MultiSampleIndividuals() const;
    bool          SiteInLocus(long site) const;
    long          SiteToMarker(long site) const;
    std::pair<long, long> GetSiteSpan() const;
    std::pair<long, long> GetGlobalScaleSiteSpan() const;
    bool          IsMovable() const;    //Phase 1
    bool          IsMoving() const;     //Phase 2
    bool          IsUsingDefaultLocations() const {return m_defaultlocations;};
    mloc_type     GetAnalysisType() const {return m_type;};
    double        GetPerBaseErrorRate() const;

    // Setters.
    void SetIndex(long index) {assert(m_movable); m_index = index;};
    void SetName(string newname)           { m_name = newname; };
    void SetNmarkers(long val);         // throws!
    void SetNsites(long val)               { m_nsites = val; };
    void SetGlobalMapPosition(long site);
    void SetRegionalMapPosition(long site);
    void SetOffset(long val);
    void SetPositions(const LongVec1d& pos);
    void SetPositions();                // set to default
    void SetDataType(DataType_ptr dt);
    void SetDataModelOnce(DataModel_ptr dm);
    void SetTipData(const TipData& td)     { m_tipdata.push_back(td); };
    void SetEmptyTipData(vector<TipData> td);
    void SetTrueSite(long site)     { m_truesite = site; };
    void SetAllowedRange(rangeset rs, long regoffset);
    void SetMappingInfo(DoubleVec1d map) {m_map = map;};
    void SetRawMappingInfo(DoubleVec1d rawmap) {m_rawmap = rawmap;};
    void SetAnalysisType(mloc_type type);
    void SetShouldSimulate(bool sim) {m_simulate = sim;};

    void SetVariableRange(rangeset rs);
    void SetPhenotypes(Phenotypes p) {m_phenotypes = p;};

    // Workers.
    void            Setup(const vector<Individual>& individuals);
    LongVec1d       CalcNVariableMarkers() const; // dim: xparts
    double          CalculateDataLikelihood(Tree& tree, bool moving) const;
    void            AddUniqueNamesTo(std::set<string>& popnames) const;

    // Helper function for Region::RemovePartitionFromLoci.
    void            RemovePartitionFromTipDatas(force_type forcename);

    // Validators.
    bool            IsValidLocus(string& errorString) const;
    StringVec1d     ReportMappingInfo(long regoffset, bool isshort=false) const;
    bool            IsDuplicateTipName(const string& newname) const;

    // XML.
    StringVec1d MakeTraitXML(long nspaces, long regoffset) const;

    // Simulation.
    void SetNewMapPositionIfMoving();
    void SimulateData(Tree& tree, long nsites);
    void CopyDataFrom(Locus& original, Tree& tree);
    void MakePhenotypesFor(IndVec& individuals);
    void SaveState(DoubleVec1d& state, long marker, string label);
    void RandomizeHalf(Tree& tree, bool swath);
    void ClearVariability() {m_variability.clear();};

    // Helper functions for simulations.
    bool            IsNighInvariant() const;
    bool            IsNighInvariant(long marker) const;
    bool            IsCompletelyInvariant(long marker) const;
    long            ChooseVariableSiteFrom(rangeset rset);
    rangeset        GetVariableRange();
    rangeset        CalculateVariableRange() const;
    rangeset        CalculateCompleteVariableRange() const;
    rangeset        GetVariableAndUnknownRange() const;
    long            GetVariabilityOfUnknownRange() const;
    long            GetVariabilityOfKnownRange() const;
    rangeset        GetKnownRange() const;
    void            ClearUnknownRange() {m_unknownrange.clear();};
    StringVec1d     CreateDataModelReport(string regionname) const;
    void            WriteMapping(string regname, long regoffset) const;

#if 0  // LS DEBUG SIM  Hard-coded information output
    rangeset        GetUnknownRange() const {return m_unknownrange;};
#endif

    // Debugging functions.
    void            PrintVariability();
    void            PrintOnesAndZeroesForVariableSites();

    // For XML reporting.
    std::set<std::pair<double, long int> >  MakeOrderedSites(long int regoffset) const;
    rangeset        GetTopSites (std::set<std::pair<double, long int> > orderedsites, double percLimit) const;
    rangeset        GetBestSites(std::set<std::pair<double, long int> > orderedsites) const;
};

#endif // LOCUS_H

//____________________________________________________________________________________
