#ifndef __FILE_EMMUSR_H_SEEN__
#define __FILE_EMMUSR_H_SEEN__

/*-----------------------------------------------------------------------------

Copyright (C) 2009, 2011

A. Ronald Gallant
Post Office Box 659
Chapel Hill NC 27514-0659
USA   

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

-----------------------------------------------------------------------------*/

#include "libsnp.h"
#include "libsmm.h"
#include "emm_base.h"
#include "snp.h"

#define USR_OBJFUN_TYPE_IMPLEMENTED

namespace emm {
    
  class gmm_objfun;
  class var_usrmod;

  typedef gmm_objfun objfun_type;
  typedef var_usrmod usrmod_type;

  class gmm_objfun : public libsmm::objfun_base {
  private:
    scl::realmat m;
    scl::realmat W;
    INTEGER d;
    INTEGER n;
    INTEGER L;
    INTEGER Lhac;
  public:
    gmm_objfun (const scl::realmat& data,
      INTEGER num_mod_parms, INTEGER num_mod_funcs,
      const std::vector<std::string>& mod_pfvec,
      const std::vector<std::string>& mod_alvec,
      const std::vector<std::string>& obj_pfvec,
      const std::vector<std::string>& obj_alvec,
      std::ostream& detail);
    gmm_objfun() { }
    void set_data(const scl::realmat& dat);
    REAL operator() (const scl::realmat& rho, const scl::realmat& sim,
      const scl::realmat& stats) const;
    objfun_base* new_objfun();
    void delete_objfun(objfun_base* objfun_ptr) { delete objfun_ptr; }
  };
 
  const INT_32BIT fixed_seed = 100542;

  class var_usrmod : public libsmm::usrmod_base {
  private:
    scl::realmat b;
    scl::realmat B;
    scl::realmat R;
    INTEGER n_stats;
    INTEGER n_parms;
    INTEGER n_datum;
    INT_32BIT bseed;
    scl::realmat statistics;
    INTEGER n_obser;
    INTEGER sim_size;
    INTEGER drop;
    bool make_sim(INT_32BIT& seed, scl::realmat& sim);
  public:
    var_usrmod (const scl::realmat& dat, INTEGER len_mod_parm, 
      INTEGER len_mod_func, const std::vector<std::string>& mod_pfvec,
      const std::vector<std::string>& mod_alvec, std::ostream& detail);
    INTEGER len_rho() {return n_parms;}
    INTEGER len_stats() {return n_stats;}
    bool gen_sim(scl::realmat& sim, scl::realmat& stats);
    bool gen_bootstrap(std::vector<scl::realmat>& bs);
    void get_rho(scl::realmat& parm) {
      parm[1] = b[1];
      parm[2] = b[2];
      parm[3] = B[1];
      parm[4] = B[2];
      parm[5] = B[3];
      parm[6] = B[4];
      parm[7] = R[1];
      parm[8] = R[3];
      parm[9] = R[4];
    }
    void set_rho(const scl::realmat& parm) {
      b[1] = parm[1];
      b[2] = parm[2];
      B[1] = parm[3];
      B[2] = parm[4];
      B[3] = parm[5];
      B[4] = parm[6];
      R[1] = parm[7];
      R[2] = 0.0;
      R[3] = parm[8];
      R[4] = parm[9];
    }
    bool support(const scl::realmat& rho);
    scl::den_val prior(const scl::realmat& rho, const scl::realmat& stats);
  };
  
}
#endif
