#ifndef __EMCLUSTER_H__
#define __EMCLUSTER_H__

#include <vector>
#include <iostream>
#include "matrix.h"
#include "kmeans.h"
#include "gaussianmodel.h"
#include "timer.h"

///em gaussian mixture clustering
class emcluster
{
 public: 
  emcluster();
  ~emcluster();
  ///delete the data
  int del();
  ///load a copy of the data
  /**
   * @param d array of data points d[data#][dimention#]
   * @param size number of data points
   * @param nparams number of parameters for every data point
   * @param sample sampling step
   */
  int loaddata(double **d, int size, int nparams, int sample);

  /// load a copy of the data
  /**
   * @param d array of data points d[data#][dimention#]
   * @param nparams number of parameters for every data point
   * @param sample sampling step
   */
  int loaddata( std::vector< double* > &d, int nparams, int sample );

  /// load a copy of the data
  /**
   * @param d array of data of size size
   * @param size number of data points
   */
  int loaddata( double *d, int size );

  ///train the em model using Bayesian Inference Criterion (BIC)
  /**
   * \param kmin min number of classes inclusive
   * \param kmax max number of classes inclusive
   * \return number of classes used
   * This will guess the number of paramters
   */
  int bicrun(int kmin, int kmax);

  ///runs the em
  /**
   * @param z number of models to use
   * @return log likelyhood for this run
   */
  long double run(int z);
  ///return vector of models
  std::vector< gaussianmodel* > getmodels();
  ///prints the models out ot stdout
  int printmodels();

  double getpi(int i)
    {
      return pi[i];
    }
  long double prob( double *d );

 private:

  int estep();
  int mstep();
  long double loglikely();
  ///delete the models
  int delmodels();
  ///randomly initialize z models
  int initmodels( int z, matrix &mt );
  ///resets the model to all zeros
  int zeromodel(gaussianmodel &m);

  double *pi;
  matrix *data;            ///< data points
  double **gamma;          ///< gamma function
  gaussianmodel *models;   ///< array of models
  int params;
  int datapts;
  int nmodels;
};

#endif
