// $Id: registry.h,v 1.38 2018/01/03 21:32:54 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 */


#ifndef REGISTRY_H
#define REGISTRY_H

#include <deque>
#include <stdlib.h>

#include "local_build.h"

#include "constants.h"
#include "defaults.h"
#include "chainparam.h"
#include "userparam.h"
#include "datapack.h"
#include "forcesummary.h"
#include "random.h"
#include "errhandling.h"
#include "regiongammainfo.h"

/***************************************************************
 The Registry has two functions:

 (1)  It holds (most of) the Singleton objects of the program
 and provides access to them.

 (2)  It holds prototypes of objects which must be created in
 a specific way for each run.  For example, it holds a
 prototypical Tree.  Once the program knows what kind of Tree will
 be wanted, a prototype is put in the Registry and all further
 Tree creation is done by Clone() of the prototype.

 The Registry is itself a Singleton.  The single instance is
 global (it's in lamarc.cpp) and it's extern everywhere (via
 constants.h).

 Written by Mary Kuhner
*******************************************************************/

class Analyzer;
class BayesAnalyzer_1D;
class DataModel;
class Locus;
class Maximizer;
class RegionPostLike;
class GammaRegionPostLike;
class ReplicatePostLike;
class RunReport;
class SinglePostLike;
class Tree;
class TreeSummary;
class UIInterface;
class UIVarsDataModels;
class UIVarsDataPackPlus;
class UIRegId;
class CellManager;

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

class Registry
{
  public:
    Registry();
    ~Registry();

    // Initialization -- to foil static global initialization bug
    void Init();

    // Getters
    const Tree& GetProtoTree()                  const;
    const TreeSummary& GetProtoTreeSummary()    const;
    const ChainParameters& GetChainParameters() const {return *chainparams;};
    const UserParameters& GetUserParameters()   const {return *userparams;};
    const DataPack& GetDataPack()               const {return datapack;};
    const ForceSummary& GetForceSummary()       const {return *forcesummary;};
    long GetCurrentReclocOffset()               const;

    ChainParameters& GetChainParameters()       {return *chainparams;};
    UserParameters& GetUserParameters()         {return *userparams;};
    DataPack& GetDataPack()                     {return datapack;};
    ForceSummary& GetForceSummary()             {return *forcesummary;};
    Random& GetRandom()                         {return *random;};
    RunReport& GetRunReport();
    const RunReport& GetRunReport()             const;
    Maximizer& GetMaximizer();
    Maximizer * GetMaximizerPtr();
    BayesAnalyzer_1D& GetBayesAnalyzer_1D();
    BayesAnalyzer_1D * GetBayesAnalyzer_1DPtr();
    SinglePostLike& GetSinglePostLike();
    ReplicatePostLike& GetReplicatePostLike();
    RegionPostLike& GetRegionPostLike();
    const RegionGammaInfo* GetRegionGammaInfo() const {return pRegionGammaForceInfo;}; // NULL is allowed
    RegionGammaInfo* GetRegionGammaInfo() {return pRegionGammaForceInfo;}; // NULL is allowed
    Analyzer& GetAnalyzer();
    CellManager& GetCellManager()               {return *cellmanager; };
    bool GetConvertOutputToEliminateZeroes()    {return m_convert_output_to_eliminate_zeroes;};
    bool GetARGfound()                          {return m_ARGfound;}

    // Setters
    void Register(Tree* tree);
    void Register(TreeSummary* treesum);
    void Register(RunReport* report);
    void Register(Maximizer* maxim);
    void Register(BayesAnalyzer_1D* bayesan);
    void Register(SinglePostLike* singlel);
    void Register(ReplicatePostLike* replicate);
    void Register(RegionPostLike* region);
    void Register(GammaRegionPostLike* gammaRegion);
    void Register(RegionGammaInfo* regionGammaForceInfo);
    void Register(Analyzer * thisanalyzer);
    void SetCurrentRegionIndex(long regionIndex);
    void SetConvertOutputToEliminateZeroes(bool conv) {m_convert_output_to_eliminate_zeroes = conv;};
    void SetARGfound(bool val) {m_ARGfound = val;};

    // build structures from UI data
    void FinalizeDataPack(UIInterface&);
    void InstallChainParameters(UIInterface&);
    void InstallDataModels(UIInterface&);
    void InstallForcesAllOverThePlace(UIInterface&);
    void InstallUserParameters(UIInterface&);

#ifdef LAMARC_QA_SINGLE_DENOVOS
    void AddDenovoTreeRejectCount(long);
    long GetDenovoTreeRejectCount();
    void AddDenovoMaxRejectCount(long);
    long GetDenovoMaxRejectCount();
    long GetDenovoCount();
    void SetDenovoCount(long);
    void SetMigsToPrint(std::deque<bool> mtp) {m_migsToPrint = mtp;};
    std::deque<bool> GetMigsToPrint() { return m_migsToPrint;};
#endif // LAMARC_QA_SINGLE_DENOVOS

  protected:

    DataModel * CreateDataModel(UIVarsDataModels &, const Locus&,
                                const UIVarsDataPackPlus&, UIRegId);

  private:
    Registry(const Registry&);       // not defined
    Registry& operator=(const Registry&);  // not defined

    // the prototypes
    Tree* protoTree;
    TreeSummary* protoTreeSummary;

    // the singletons
    ChainParameters *chainparams;
    UserParameters *userparams;
    DataPack datapack;
    ForceSummary *forcesummary;
    Random *random;
    CellManager *cellmanager;  // we deliberately don't delete this!

    // the runtime reporter
    RunReport* runreport;

    // the posterior-likelihood drivers
    Maximizer* maximizer;
    SinglePostLike* PLsingle;
    ReplicatePostLike* PLreplicate;
    RegionPostLike* PLregion;
    GammaRegionPostLike* PLgammaRegion;

    // the pseudo-hack
    RegionGammaInfo* pRegionGammaForceInfo;

    BayesAnalyzer_1D* bayesanalyzer;

    // the profile and plot driver
    Analyzer *analyzer;

    // this is dreadful, but we need it to make GetCurrentReclocOffset work
    long m_currRegion;

    // another dreadful - we need to know in phase2 that an ARG tree was found in the input XML
    bool m_ARGfound;

    //Whether the user wants zeroes in the output
    bool m_convert_output_to_eliminate_zeroes;

#ifdef LAMARC_QA_SINGLE_DENOVOS
    long m_denovoTreeRejectCount;
    long m_denovoMaxRejectCount;
    bool m_lastDenovoGood;
    long m_defaultBranchCount;
    long m_denovoCount;
    std::deque<bool> m_migsToPrint;
#endif // LAMARC_QA_SINGLE_DENOVOS

    // error handling
    void ThrowBadPrototype() const;
};

#endif // REGISTRY_H

//____________________________________________________________________________________
