// $Id: Converter_PopulationDS.h,v 1.15 2018/01/03 21:32:56 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: Patrick Colacurcio, Peter Beerli, Mary Kuhner, Jon Yamato 
/* Authors: Patrick Colacurcio, Peter Beerli, Mary Kuhner, Jon Yamato 
and Joseph Felsenstein */


// PopulationDS is a representation of the data on any one population.
// Each population owns a name, and a number of IndividualDS'.
// Validation is done whenever a new Individual is added.  Population makes sure that
// Individual Sequences are always the same length.
// If they're different lengths, an InvalidSequenceLengthError is tossed.

// One may construct from an individual, or individual and name.
// TODO, decide whether to allow to construct from a vector of individuals.

// The vector<IndividualDS>getIndividuals() method returns a vector of Individuals.
// The method string getName() returns the population name as a string.  (may be "")
// This method returns the sequence as a string..
// The method addNewIndividual() is present in a couple of forms.
// addNewIndividual(const IndividualDS& individual)
// addnewIndividual(const string& name, const Sequence& seq)
// addnewIndividual(const Sequence& seq)  #probably won't do this right away.

#ifndef CONVERTER_POPULATION_H
#define CONVERTER_POPULATION_H

#include <list>
#include <vector>
#include "Converter_DataSourceIf.h"
#include "Converter_IndividualDS.h"

using std::string;
using std::list;
using std::vector;

class PopulationDS : public DataSourceIf
{
  private:
    string m_popName;
    list<IndividualDS> m_individuals;
    int m_sequenceLength;      //  This is a convenience.  Every sequence length in a population
    //  be the same
    string m_comment;          //  A comment for the XML

    void validateNewIndividual(IndividualDS& individual);     // does the actual validation
    string getUniqueName() const;   // Returns a Unique name for an individual in this population

  public:
    //  Note.  Constructors may throw ConverterBaseError's
    PopulationDS(const string& popName,
                 const string& individualName,
                 const string& sequence);
    PopulationDS(const string& popName,
                 const IndividualDS& individual);
    PopulationDS(const string& popName);
    //  PopulationDS() : m_popName("default"), m_sequenceLength(0) {};

    virtual ~PopulationDS();

    // Use the Default Copy Constructor.  Will this be a bug?

    //  get an iterator to the beginning of the individual list.
    list<IndividualDS>::const_iterator getFirstIndividual() const;

    //  get an iterator to the end of the individual list.
    list<IndividualDS>::const_iterator getLastIndividual() const;

    //  return a copy of all our individuals
    list<IndividualDS> GetAllIndividuals() const {return m_individuals;};

    //  get the size of the individuals list
    int getNumberOfIndividuals() const;

    //  get the total number of OTUs present in all the individuals
    long GetNumberOfOTUs() const;

    //  get all the sequence names in the population
    vector<string> GetAllSeqNames() const;

    //  get the name of the population
    string getName() const;

    //  Allow setting of the population name
    //  TODO: Consider making this private and a friend of RegionDS
    void setName(const string& popName);

    //  Allow the user to set a comment for this population.
    //  This will be reflected in the output of the XML.
    void setComment(const string& comment);

    //  Allow setting of the FIRST sequence Length.
    //  So, if this population already has a non-zero sequence length, this function does NOTHING.
    void setFirstSequenceLength(const int sequenceLength);

    //  get the length of the sequences within.  If there are no sequences, this is zero.
    int getSequenceLength() const;

    //  add an individual (this may throw an InvalidSequenceLengthError)
    //  Also note, that DuplicateIndividuals (individuals with non-unique names, will not be added.
    void addIndividual (IndividualDS individual);

    //  add an individual (this may throw an InvalidSequenceLengthError, or a DuplicateIndividualError)
    //  Also note, that DuplicateIndividuals (individuals with non-unique names, will not be added.
    void addIndividual (const string& name, const Sequence& seq);

    // add a list of individuals, DuplicateIndividuals and Individuals
    // with the wrong sequence length won't be added.  On encountering
    // wrong sequence lengths, an InvalidSequenceLengthError will be
    // thrown.
    void AddIndividuals(list<IndividualDS> individuals);

    //  returns true if a given individual exists, false otherwise
    bool doesIndividualNameExist(const string& name) const;

    // extract the given sequence from the given individual, destroying
    // the individual if there are no more sequences in it; and returning
    // the sequence
    Sequence PopSequence(const string& seqname,
                         list<IndividualDS>::iterator individual);

    // given a container of sequence names, return a container of pairs
    // consisting of one of the given sequence names along with which
    // individual contains that sequence.  Return an empty container if
    // any of the sequence names couldn't be found
    vector< std::pair<string, list<IndividualDS>::iterator> > FindAllSequences(const vector<string>& seqnames);

    // destroy the individuals
    void EraseIndividuals();

    // Am I a ghost population?
    bool IsGhost() const;

    // Do I contain any non-contiguous data?
    bool HasNonContiguousData() const;

    // Do I contain any SNPs?
    bool HasSNPs() const;

    string getXML(unsigned int numTabs) const;   //  From DataSourceIf
};

#endif // CONVERTER_POPULATION_H

//____________________________________________________________________________________
