#ifndef __FILE_SNPUSR_H_SEEN__
#define __FILE_SNPUSR_H_SEEN__

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

Copyright (C) 2004, 2006, 2009, 2014.

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 "libscl.h"
#include "snp_base.h"
#include "libsnp.h"
#include "snp.h"

namespace snp {
  
  class datread;                      // These are the classes defined here.
  class resmusig;
  class plot;
  class simulate;
  class leverage;
  class quadrature;
  class rhostats;
  class impulse;
  
  typedef datread   datread_type;    // The type names are used in snp.cpp.
  typedef resmusig  residual_type;   // Change the class reference to 
  typedef resmusig  mean_type;       // substitute user written classes. 
  typedef resmusig  variance_type;   // Leave the distribution code intact.
  typedef plot      plot_type;       // Hopefully the constructor call in
  typedef simulate  simulate_type;   // snp.cpp is general enough that 
                                     // snp.cpp changes will be unnecessary.

  /*
  typedef leverage user_type;
  typedef quadrature user_type;
  typedef impulse user_type;
  typedef rhostats user_type;
  */

  typedef rhostats user_type;
    
  class datread : public datread_base {
  private:
    datparms dpm;
  public:
    datread();
    void initialize(datparms dp);
    bool read_data(scl::realmat& data);
  };
  
  class resmusig : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    std::ostream& detail;
    const trnfrm* tr;
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
  public:
    resmusig(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename) { return true; }
    bool calculate();
    bool finalize();
  };
  
  class simulate : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    std::ostream& detail;
    const trnfrm* tr;
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
  public:
    simulate(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename) { return true; }
    bool calculate();
    bool finalize();
  };
  
  class plot : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    std::ostream& detail;
    const trnfrm* tr;
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
  public:
    plot(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename) { return true; }
    bool calculate();
    bool finalize();
  };
  
  class leverage : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    std::ostream& detail;
    const trnfrm* tr;
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
  public:
    leverage(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename) { return true; }
    bool calculate();
    bool finalize();
  };
  
  class quadrature : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    std::ostream& detail;
    const trnfrm* tr;
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
  public:
    quadrature(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename) { return true; }
    bool calculate();
    bool finalize();
  };

  class rhostats : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    libsnp::afunc af_mask;
    libsnp::ufunc uf_mask;
    libsnp::rfunc rf_mask;
    std::ostream& detail;
    const trnfrm* tr;
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
    std::string filename;
  public:
    rhostats(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename);
    bool calculate();
    bool finalize();
  };

  class impulse : public ancillary_base {
  private:
    optparms opm;
    datparms dpm;
    tranparms tpm;
    libsnp::snpden f;
    libsnp::afunc af;
    libsnp::ufunc uf;
    libsnp::rfunc rf;
    std::ostream& detail;
    const trnfrm* tr;
    const INTEGER N;       // Number of Monte Carlo repetitions
    const scl::realmat* X;
    const scl::realmat* Y;
    std::ostream* os;
    std::string filename;
  public:
    impulse(optparms op, datparms dp, tranparms tp, libsnp::snpden fn, 
         libsnp::afunc afn, libsnp::ufunc ufn, libsnp::rfunc rfn,
         libsnp::afunc afm, libsnp::ufunc ufm, libsnp::rfunc rfm, 
         std::ostream& dos, const trnfrm* trn);
    void set_XY(const scl::realmat* x, const scl::realmat* y);
    bool initialize(std::ostream* out_stream);
    bool initialize(std::string out_filename);
    bool calculate();
    bool finalize();
  };
  
}

#endif
