/*
 *       File name:  libcn/hosted-neurons.hh
 *         Project:  cnrun
 *          Author:  Andrei Zavada <johnhommer@gmail.com>
 *                   building on original work by Thomas Nowotny <tnowotny@ucsd.edu>
 * Initial version:  2008-10-11
 *
 *         Purpose:  hosted neuron classes (those having their
 *                   state vars on parent model's integration vectors)
 *
 *         License:  GPL-2+
 */

#ifndef CNRUN_LIBCN_HOSTEDNEURONS_H_
#define CNRUN_LIBCN_HOSTEDNEURONS_H_

#if HAVE_CONFIG_H && !defined(VERSION)
#  include "config.h"
#endif

#include <gsl/gsl_math.h>

#include "forward-decls.hh"
#include "base-neuron.hh"
#include "hosted-attr.hh"

namespace cnrun {

enum class TIncludeOption { is_last, is_notlast, };

class C_HostedNeuron
  : public C_BaseNeuron, public C_HostedAttributes {

        DELETE_DEFAULT_METHODS (C_HostedNeuron)

    protected:
        C_HostedNeuron (TUnitType intype, const string& inlabel,
                        double x, double y, double z,
                        CModel*, int s_mask,
                        TIncludeOption include_option);
    public:
        void reset_vars();
        double &var_value( size_t);
        const double &get_var_value( size_t) const;
};





class C_HostedConductanceBasedNeuron
  : public C_HostedNeuron {

        DELETE_DEFAULT_METHODS (C_HostedConductanceBasedNeuron)

    protected:
        C_HostedConductanceBasedNeuron (TUnitType intype, const string& inlabel,
                                        double inx, double iny, double inz,
                                        CModel* inM, int s_mask,
                                        TIncludeOption include_option)
              : C_HostedNeuron (intype, inlabel, inx, iny, inz, inM, s_mask, include_option)
                {}

    public:
        double  E() const; // needs access to parent model var vector, defined in model.h
        double  E( vector<double> &b) const  { return b[idx+0]; }
        double& dE( vector<double> &b)       { return b[idx+0]; }

        size_t n_spikes_in_last_dt() const;

        void do_detect_spike_or_whatever();
};





// for completeness' sake -- no descendants yet
class C_HostedRateBasedNeuron
  : public C_HostedNeuron {

        DELETE_DEFAULT_METHODS (C_HostedRateBasedNeuron)

    protected:
        C_HostedRateBasedNeuron (TUnitType intype, const string& inlabel,
                                 double inx, double iny, double inz,
                                 CModel* inM, int s_mask,
                                 TIncludeOption include_option)
              : C_HostedNeuron (intype, inlabel, inx, iny, inz, inM, s_mask, include_option)
                {}

    public:
        size_t n_spikes_in_last_dt() const;
};










// Hodgkin-Huxley classic

class CNeuronHH_d
  : public C_HostedConductanceBasedNeuron {

        DELETE_DEFAULT_METHODS (CNeuronHH_d)

    public:
        CNeuronHH_d (const string& inlabel,
                     double x, double y, double z,
                     CModel *inM, int s_mask = 0,
                     TIncludeOption include_option = TIncludeOption::is_last)
              : C_HostedConductanceBasedNeuron (NT_HH_D, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

      // parameters (since gcc 4.4, accessible from within member functions defined outside class definition, gee!)
        enum {
                gNa, ENa, gK,  EK, gl, El, Cmem,
                alpha_m_a,        alpha_m_b,        alpha_m_c,        beta_m_a,        beta_m_b,        beta_m_c,
                alpha_h_a,        alpha_h_b,        alpha_h_c,        beta_h_a,        beta_h_b,        beta_h_c,
                alpha_n_a,        alpha_n_b,        alpha_n_c,        beta_n_a,        beta_n_b,        beta_n_c,
                Idc,
        };

      // current state
      // these wrappers mainly for code legibility in derivative(); otherwise, not used
      // for reporting, CModel accesses vars as V[idx+n]
        double   m( vector<double>& b) const { return b[idx+1]; }
        double   h( vector<double>& b) const { return b[idx+2]; }
        double   n( vector<double>& b) const { return b[idx+3]; }
        double& dm( vector<double>& b)       { return b[idx+1]; }
        double& dh( vector<double>& b)       { return b[idx+2]; }
        double& dn( vector<double>& b)       { return b[idx+3]; }

        void derivative( vector<double>&, vector<double>&) __attribute__ ((hot));
};







class CNeuronHH2_d
  : public C_HostedConductanceBasedNeuron {

        DELETE_DEFAULT_METHODS (CNeuronHH2_d)

    public:
        CNeuronHH2_d (const string& inlabel,
                      double x, double y, double z,
                      CModel *inM, int s_mask = 0,
                      TIncludeOption include_option = TIncludeOption::is_last)
              : C_HostedConductanceBasedNeuron( NT_HH2_D, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

        double   m( vector<double>& b) const { return b[idx+1]; }
        double   h( vector<double>& b) const { return b[idx+2]; }
        double   n( vector<double>& b) const { return b[idx+3]; }
        double& dm( vector<double>& b)       { return b[idx+1]; }
        double& dh( vector<double>& b)       { return b[idx+2]; }
        double& dn( vector<double>& b)       { return b[idx+3]; }

        void derivative( vector<double>&, vector<double>&);
};



//#ifdef CN_WANT_MORE_NEURONS

// Entorhinal cortex stellate cell

class CNeuronEC_d
  : public C_HostedConductanceBasedNeuron {

        DELETE_DEFAULT_METHODS (CNeuronEC_d)

    public:
        CNeuronEC_d( const string& inlabel,
                     double x, double y, double z,
                     CModel *inM, int s_mask = 0,
                     TIncludeOption include_option = TIncludeOption::is_last)
              : C_HostedConductanceBasedNeuron (NT_EC_D, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

        double    m   ( vector<double>& b) const { return b[idx+1]; }
        double    h   ( vector<double>& b) const { return b[idx+2]; }
        double    n   ( vector<double>& b) const { return b[idx+3]; }
        double    Ih1 ( vector<double>& b) const { return b[idx+4]; }
        double    Ih2 ( vector<double>& b) const { return b[idx+5]; }
        double&   dm  ( vector<double>& b)       { return b[idx+1]; }
        double&   dh  ( vector<double>& b)       { return b[idx+2]; }
        double&   dn  ( vector<double>& b)       { return b[idx+3]; }
        double& dIh1  ( vector<double>& b)       { return b[idx+4]; }
        double& dIh2  ( vector<double>& b)       { return b[idx+5]; }


        void derivative( vector<double>&, vector<double>&);
};






class CNeuronECA_d
  : public C_HostedConductanceBasedNeuron {

        DELETE_DEFAULT_METHODS (CNeuronECA_d)

    public:
        CNeuronECA_d( const string& inlabel,
                      double x, double y, double z,
                      CModel *inM, int s_mask = 0,
                      TIncludeOption include_option = TIncludeOption::is_last)
              : C_HostedConductanceBasedNeuron( NT_ECA_D, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

        double      m( vector<double>& b) const { return b[idx+1]; }
        double      h( vector<double>& b) const { return b[idx+2]; }
        double      n( vector<double>& b) const { return b[idx+3]; }
        double   mNap( vector<double>& b) const { return b[idx+4]; }
        double    Ih1( vector<double>& b) const { return b[idx+5]; }
        double    Ih2( vector<double>& b) const { return b[idx+6]; }

        double&    dm( vector<double>& b)       { return b[idx+1]; }
        double&    dh( vector<double>& b)       { return b[idx+2]; }
        double&    dn( vector<double>& b)       { return b[idx+3]; }
        double& dmNap( vector<double>& b)       { return b[idx+4]; }
        double&  dIh1( vector<double>& b)       { return b[idx+5]; }
        double&  dIh2( vector<double>& b)       { return b[idx+6]; }

        void derivative( vector<double>&, vector<double>&);
};

//#endif  // CN_WANT_MORE_NEURONS








//#ifdef CN_WANT_MORE_NEURONS

class COscillatorColpitts
  : public C_HostedConductanceBasedNeuron {

        DELETE_DEFAULT_METHODS (COscillatorColpitts)

    public:
        COscillatorColpitts( const string& inlabel,
                             double x, double y, double z,
                             CModel *inM, int s_mask = 0,
                             TIncludeOption include_option = TIncludeOption::is_last)
              : C_HostedConductanceBasedNeuron (NT_COLPITTS, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

        double   x0( vector<double>& b) const { return b[idx+0]; }  // there's no E() for this one
        double   x1( vector<double>& b) const { return b[idx+1]; }
        double   x2( vector<double>& b) const { return b[idx+2]; }
        double& dx0( vector<double>& b)       { return b[idx+0]; }
        double& dx1( vector<double>& b)       { return b[idx+1]; }
        double& dx2( vector<double>& b)       { return b[idx+2]; }

        virtual void derivative( vector<double>&, vector<double>&);
};







/*
// ne marche pas

class COscillatorLV
  : public C_HostedConductanceBasedNeuron {

    public:
        double   fr( vector<double>& b) const        { return b[idx+1]; }
        double& dfr( vector<double>& b)                { return b[idx+1]; }

        COscillatorLV( const char *inlabel,
                       double x, double y, double z,
                       CModel *inM, int s_mask = 0,
                       CModel::TIncludeOption include_option = true)
              : C_HostedConductanceBasedNeuron( NT_LV, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

        enum TParametersOscilLV {
                rho
        };
        void derivative( vector<double>& x, vector<double>& dx)
                {
                        dE(dx) = fr(x) * (1.0 - P[rho] * fr(x)) - Isyn(x);
                }
};


*/




class COscillatorVdPol
  : public C_HostedConductanceBasedNeuron {

        DELETE_DEFAULT_METHODS (COscillatorVdPol)

     public:
        COscillatorVdPol (const string& inlabel,
                          double x, double y, double z,
                          CModel *inM, int s_mask = 0,
                          TIncludeOption include_option = TIncludeOption::is_last)
              : C_HostedConductanceBasedNeuron (NT_VDPOL, inlabel, x, y, z,
                                                inM, s_mask, include_option)
                {}

        double   amp( vector<double>& b) const  { return b[idx+0]; }
        double    _x( vector<double>& b) const  { return b[idx+1]; }
        double& damp( vector<double>& b)        { return b[idx+0]; }
        double&  d_x( vector<double>& b)        { return b[idx+1]; }

        enum TParametersOscilVdPol {
                eta, omega2
        };
        void derivative( vector<double> &x, vector<double> &dx)
                {
                        damp(dx) = _x(x);
                        d_x(dx) = (P[eta] - gsl_pow_2( amp(x))) * _x(x) - P[omega2] * amp(x) + Isyn(x);
                }
};

//#endif  // CN_WANT_MORE_NEURONS

}

#endif

// Local Variables:
// Mode: c++
// indent-tabs-mode: nil
// tab-width: 8
// c-basic-offset: 8
// End:
