// $Id: datatype.h,v 1.30 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 */


/*********************************************************************
 This class is the key control class for polymorphism based on
 the type of the input data (SNP, DNA, microsatellite, etc.)  It is
 subclassed along datatype lines.

 Each DataType should have a short tag (related to XML file reading)
 and a textual name for its type.  It should have expertise to
 Proofread() raw input data and factory functions to create a
 datatype-appropriate DLCell and DLCalculator.

 A free factory function, CreateDataType, can be used to create a DataType
 object corresponding to a tag.  Whenever a new DataType subclass
 is added this function must be updated.

 DataType written by Jim Sloan, revised by Mary Kuhner

 added quickcalculator support Jon Yamato 2001/09/12:
    CalcNVarMarkers(), CalcNPairDiffs(), CalcFw(), CalcFb()
 deleted DataTranslator helper class Mary Kuhner 2002/01/02
    (this functionality now in DataModel)
 added m_source and supporting code Jim McGill 2010/03/16
******************************************************************/

#ifndef DATATYPE_H
#define DATATYPE_H

#include <vector>
#include <string>
#include <map>
#include <stdlib.h>
#include "types.h"
#include "constants.h"
#include "vectorx.h"
#include "locuscell.h"

class Tree;
class Locus;
class DLCalculator;
class TipData;

enum data_type {dtype_DNA, dtype_SNP, dtype_msat, dtype_kallele };
std::string ToString(data_type dtype);

//------------------------------------------------------------------------------------
// The DataType base class

class DataType
{
  private:
    DataType(const DataType&);      // undefined
    DataType& operator=(DataType&);  // undefined

  protected:
    string m_name;        // the full name used in report file writing
    string m_xmltag;      // the xml tag associated with the type

    virtual long GetPairwiseMarkers(const Locus& locus) const;
    double DifferenceWithinPop(StringVec2d::const_iterator group1,
                               StringVec2d::const_iterator done) const;
    double DifferenceBetweenPops(StringVec2d::const_iterator group1,
                                 StringVec2d::const_iterator done1,
                                 StringVec2d::const_iterator group2,
                                 StringVec2d::const_iterator done2) const;

  public:
    DataType() {};
    virtual        ~DataType() {};
    string GetName() const                       { return m_name; };
    string GetXMLTag() const                     { return m_xmltag; };

    virtual data_type GetType() const = 0; //RTTI
    virtual bool   Proofread(const string& raw, StringVec1d& clean,
                             string& baddata) const = 0;
    DoubleVec1d CalcFw(const Locus& locus) const;
    DoubleVec1d CalcFb(const Locus& locus) const;
    DoubleVec1d CalcXFw(const Locus& locus,const StringVec3d& data) const;
    DoubleVec1d CalcXFb(const Locus& locus,const StringVec3d& data) const;
    virtual long   CalcNVarMarkers(const StringVec2d& data) const;
    virtual wakestats CalcNPairDiffs(const StringVec2d& data) const;
    virtual bool   IsEquivalent(const string& data1, const string& data2) const;
    virtual bool   IsNucleotideData() const { return false; };

    // user pretty printing
    virtual string GetDelimiter() const { return string(""); };

    // Factory functions
    virtual LocusCell CreateDLCell(const Locus& locus) const   = 0;
    virtual LocusCell CreateInitializedDLCell(const Locus& locus,
                                              const StringVec1d& tipdata) const = 0;
    virtual DLCalc_ptr CreateDLCalculator(const Locus& locus) const = 0;
    virtual model_type    DefaultModelType() = 0;

};

//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
// Nucleotide sequence type

class NucleotideType : public DataType
{
  public:
    NucleotideType() : DataType() {};
    virtual      ~NucleotideType() {};
    virtual data_type GetType() const = 0; //RTTI
    virtual bool Proofread(const string& raw, StringVec1d& clean,
                           string& baddata) const;
    virtual bool IsEquivalent(const string& data1, const string& data2) const;
    virtual bool IsNucleotideData() const { return true; };

    virtual model_type      DefaultModelType();
};

//------------------------------------------------------------------------------------
// DNA sequence type

class DNASeqType : public NucleotideType
{
  public:
    DNASeqType();
    virtual      ~DNASeqType() {};
    virtual data_type GetType() const {return dtype_DNA;}; //RTTI

    // Factory functions
    virtual LocusCell CreateDLCell(const Locus& locus) const;
    virtual LocusCell CreateInitializedDLCell(const Locus& locus,
                                              const StringVec1d& tipdata) const;
    virtual DLCalc_ptr CreateDLCalculator(const Locus& locus) const;
};

//------------------------------------------------------------------------------------
// SNP data type

class SNPDataType : public NucleotideType
{
  protected:
    virtual long GetPairwiseMarkers(const Locus& locus) const;

  public:
    SNPDataType();
    virtual ~SNPDataType() {};
    virtual data_type GetType() const {return dtype_SNP;}; //RTTI

    // Factory functions
    virtual LocusCell CreateDLCell(const Locus& locus) const;
    virtual LocusCell CreateInitializedDLCell(const Locus& locus,
                                              const StringVec1d& tipdata) const;
    virtual DLCalc_ptr CreateDLCalculator(const Locus& locus) const;

};

//------------------------------------------------------------------------------------
// Allele type

class AlleleType : public DataType
{
  public:
    AlleleType() : DataType() {};
    virtual        ~AlleleType() {};

    virtual data_type GetType() const = 0; //RTTI
    virtual string GetDelimiter() const { return string(" "); };
    virtual LocusCell CreateDLCell(const Locus& locus) const;
    virtual LocusCell CreateInitializedDLCell(const Locus& locus,
                                              const StringVec1d& tipdata) const;
};

//------------------------------------------------------------------------------------
// Microsatellite type

class MSType : public AlleleType
{
  public:
    MSType();
    virtual      ~MSType() {};
    virtual data_type GetType() const {return dtype_msat;}; //RTTI

    virtual bool Proofread(const string& content, StringVec1d& data,
                           string& baddata) const;

    // Factory functions
    virtual DLCalc_ptr CreateDLCalculator(const Locus& locus) const;
    virtual model_type    DefaultModelType();

};

//------------------------------------------------------------------------------------
// K-Allele type (for disease status)

class KAlleleType : public AlleleType
{
  public:
    KAlleleType();
    virtual  ~KAlleleType() {};
    virtual data_type GetType() const {return dtype_kallele;}; //RTTI

    virtual bool Proofread(const string& content, StringVec1d& data,
                           string& baddata) const;

    // Factory functions
    virtual DLCalc_ptr CreateDLCalculator(const Locus& locus) const;
    virtual model_type    DefaultModelType();
};

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

// Free function, a polymorphic creator for DataTypes.
// If you add a new DataType subclass you must update this
// function.

DataType* CreateDataType(const string tag);

bool ModelTypeAcceptsDataType(model_type,data_type);
model_type DefaultModelForDataType(data_type);

#endif // DATATYPE_H

//____________________________________________________________________________________
