#ifndef __COGAPS_GAPS_RUNNER_H__
#define __COGAPS_GAPS_RUNNER_H__

#include "Archive.h"
#include "GapsStatistics.h"
#include "GibbsSampler.h"

#include "data_structures/Matrix.h"
#include "data_structures/Vector.h"

#include <Rcpp.h>

// boost time helpers
#include <boost/date_time/posix_time/posix_time.hpp>
namespace bpt = boost::posix_time;
#define bpt_now() bpt::microsec_clock::local_time()

enum GapsPhase
{
    GAPS_BURN=0,
    GAPS_COOL=1,
    GAPS_SAMP=2
};

// Manages all data and parameters for running CoGAPS; contains the high-level
// algorithm logic
class GapsRunner
{
private:
#ifdef GAPS_INTERNAL_TESTS
public:
#endif

    Vector mChiSqEquil;
    Vector mNumAAtomsEquil;
    Vector mNumPAtomsEquil;

    Vector mChiSqSample;
    Vector mNumAAtomsSample;
    Vector mNumPAtomsSample;

    unsigned mIterA;
    unsigned mIterP;
    
    unsigned mEquilIter;
    unsigned mCoolIter;
    unsigned mSampleIter;

    //unsigned mNumPatterns;
    unsigned mNumOutputs;
    bool mPrintMessages;

    unsigned mCurrentIter;
    GapsPhase mPhase;
    uint32_t mSeed;

    bpt::ptime mLastCheckpoint;
    int64_t mCheckpointInterval;
    std::string mCheckpointFile;

    unsigned mNumUpdatesA;
    unsigned mNumUpdatesP;
    
    AmplitudeGibbsSampler mASampler;
    PatternGibbsSampler mPSampler;
    GapsStatistics mStatistics;

    unsigned mNumCores;

    bpt::ptime mStartTime;

    char mFixedMatrix;

    unsigned mNumPumpSamples;

    void createCheckpoint();
    void makeCheckpointIfNeeded();
    void displayStatus(const std::string &type, unsigned nIterTotal);
    void storeSamplerInfo(Vector &atomsA, Vector &atomsP, Vector &chi2);
    void updateSampler();
    void runBurnPhase();
    void runCoolPhase();
    void runSampPhase();
    double estPercentComplete();

public:

    // construct from parameters
    GapsRunner(const Rcpp::NumericMatrix &D, const Rcpp::NumericMatrix &S,
        unsigned nFactor, unsigned nEquil, unsigned nCool, unsigned nSample,
        unsigned nOutputs, float alphaA, float alphaP,
        float maxGibbsMassA, float maxGibbsMassP, uint32_t seed, bool messages,
        bool singleCellRNASeq, unsigned cptInterval, const std::string &cptFile,
        char whichMatrixFixed, const Rcpp::NumericMatrix &FP, unsigned nCores,
        PumpThreshold pumpThreshold, unsigned nPumpSamples);
    
    // construct from checkpoint file
    GapsRunner(const Rcpp::NumericMatrix &D, const Rcpp::NumericMatrix &S,
        unsigned nFactor, unsigned nEquil, unsigned nSample,
        const std::string &cptFile);

    // run all phases of algorithm
    Rcpp::List run();
};

#endif // __COGAPS_GAPS_RUNNER_H__