/*  Multimodal Image Segmentation Tool (MIST)  */
/*  Eelke Visser  */

/*  Copyright (c) 2016 University of Oxford  */

/*  CCOPYRIGHT  */

#ifndef GIBBSSHAPEMODEL_H
#define GIBBSSHAPEMODEL_H

#include "shapemodel.h"

class GibbsShapeModel : public ShapeModel
{
public:
    GibbsShapeModel(const Shape &shape, const std::vector<std::string> &modalitynames, int profilepoints, double profilespacing,
                    bool usenormalisationmasks);

    void Reseed(std::mt19937::result_type seed);

    void UseGibbs(bool use);
    void SetGibbsIterations(int iterations);
    void SetGibbsBurnIn(int burnin);

protected:
    bool m_useGibbs = false;
    int m_gibbsIters = 1;
    int m_gibbsBurnIn = 0;

    double GenerateSample(const std::vector<double> &logprobs);

    virtual NEWMAT::ColumnVector FitImplementation(const std::unordered_map<std::string, std::vector<NEWMAT::ColumnVector> > &data,
                                                   NEWMAT::ColumnVector &cilower, NEWMAT::ColumnVector &ciupper, double cilevel);

    virtual std::vector<double> GetConditionalContinuous(const NEWMAT::ColumnVector &x, int vert) const = 0;

    virtual std::vector<double> GetConditional(const std::vector<int> &deltas, int vert) const;

    NEWMAT::ColumnVector DoGibbs(const std::unordered_map<std::string, std::vector<NEWMAT::ColumnVector> > &data,
                      NEWMAT::ColumnVector &cilower, NEWMAT::ColumnVector &ciupper, double cilevel);

private:
    std::mt19937 m_randomEngine;

    friend class boost::serialization::access;

    template<class Archive>
    void serialize(Archive &ar, const unsigned int version);
};

template<class Archive>
void GibbsShapeModel::serialize(Archive &ar, const unsigned int version)
{
    BOOST_LOG_TRIVIAL(debug) << "(De)serialising GibbsShapeModel";

    ar & boost::serialization::base_object<ShapeModel>(*this);

    ar & m_useGibbs;
    ar & m_gibbsIters;
    ar & m_gibbsBurnIn;
}

#endif // GIBBSSHAPEMODEL_H
