
#ifndef RD_SPIKINGCHANNEL_H
#define RD_SPIKINGCHANNEL_H

#include <basespikingchannel.h>
#include <radialscheme.h>

//And here comes class rdSpikingChannel : it is a layer of spiking cells that circularly parse the visual field. This is the object created (at least) whenever the retina has a radial density scheme RadialScheme.

//Spatial distribution of units :

//One channel's sampling scheme is defined by its foveal radial (one dimensional) density d0, and the chosen RadialScheme for the retina.
//Rmax is the total radius of this channel of units.
//All theoretical positions can be modified according to a uniform law noise, with amplitude equal to "noise_pos/1d-density"


class rdSpikingChannel: public BaseSpikingChannel

{
protected :

  int diameter;                      //size parameter (diameter of the array)
  double foveaDensity;                        //sampling density in the fovea.


  //tools to retrieve "position<-->identificator"  of units :
  int nb_circles;          //number of circles in the channel, INCLUDING central point considered as the first circle.
  int* summed_units;       //summed_units[n]  = number of units in the channel in the n first circles (0 if n=0, 1 if n=1) (n<nb_circles+1)
  double* angular_offset;  //angular_offset[n] is the angular_offset of circle n.


  //Noise indicators :
  double noisePos;
  bool randomAngularOffset;

public :

  XML_IZE_MACRO;

  //Functions to handle SAMPLING :

  double get_r(int circle_index)  {return (RadialScheme::instance())? RadialScheme::instance()->findRadius(circle_index/foveaDensity) : circle_index/foveaDensity ; }

  //Cell density:
  double cellDensity(double r){return (RadialScheme::instance())? foveaDensity * RadialScheme::instance()->density(r) : foveaDensity;}

  int get_nb_units(double r)
  {
    if (r==0) return 1;
    else
      return  (int)floor(2*Pi*cellDensity(r)*r);
  }


  //Indexing functions :

  int index(int n, int K)
  {                    //warning ! you must have 0<=n<nb_circles and 0<=K<summed_units[n+1]-summed_units[n]
    return summed_units[n]+K;
  }

  int get_n(int ind)
  {
    int n=0;
    while(summed_units[n]<ind+1)
      n++;
    return n-1;
  }

  int get_K(int ind)
  {
    int n=get_n(ind);
    return ind-summed_units[n];
  }


  //Constructors/Destructor :

  rdSpikingChannel(double stepp=1.0);
  virtual ~rdSpikingChannel(void);

  //Channel parameter definition functions :

  void set_diameter(int f);
  void set_foveaDensity(double f);
  void set_channel(int diam, double d_fov);

  void set_noisePos(double f);
  void set_randomAngularOffset(double f);

  void allocateValues();
};

#endif

