#ifndef RETINA_H
#define RETINA_H

/* BeginDocumentation
 * Name: Retina
 *
 * Description: the class Retina implements a vector of modules, manages their connections
 * and feed them with new input data every simulation step.
 *
 * Author: Pablo Martinez CaƱada. University of Granada. CITIC-UGR. Spain.
 * <pablomc@ugr.es>
 *
 * SeeAlso: module, GratingGenerator, fixationalMovGrating, impulse, whiteNoise
 */


#include "module.h"
#include "LinearFilter.h"
#include "SingleCompartment.h"
#include "GaussFilter.h"
#include "GratingGenerator.h"
#include "fixationalMovGrating.h"
#include "whiteNoise.h"
#include "impulse.h"
#include "SpikingOutput.h"
#include "SequenceOutput.h"
#include "StreamingInput.h"

using namespace cimg_library;
using namespace std;

class Retina{
protected:
    // Image size
    int sizeX, sizeY;
    // simulation step time length and ppd
    double step;
    double pixelsPerDegree;

    // Retina output and accumulator of intermediate images
    CImg <double> *output;
    CImg <double> *accumulator;
    // retina input channels (for color conversion)
    CImg<double> *RGBred, *RGBgreen, *RGBblue, *ch1, *ch2, *ch3, *rods, *X_mat, *Y_mat, *Z_mat;
    // vector of retina modules
    vector <module*> modules;
    // Type of input
    int inputType;

    // Inputs
    GratingGenerator *g;
    fixationalMovGrating *fg;
    whiteNoise *WN;
    impulse *imp;

    // total (end) simulation time and current simulation time
    int totalSimTime, simTime;
    // Current and total number of trials
    double CurrentTrial,totalNumberTrials;

    // Display comments
    bool verbose;

public:
    // Constructor, copy, destructor.
    Retina(int x=1,int y=1,double temporal_step=1.0);
    Retina(const Retina& copy);
    ~Retina(void);

    void reset(int x=1,int y=1,double temporal_step=1.0);

    // Allocate values and set protected parameters
    bool allocateValues();
    bool setSizeX(int x);
    bool setSizeY(int y);
    bool set_step(double temporal_step);
    int getSizeX();
    int getSizeY();
    double getStep();
    bool setVerbosity(bool verbose_flag);
    bool setSimCurrentTrial(double r);
    bool setSimTotalTrials(double r);
    bool setTotalSimTime(int t);
    double getSimCurrentTrial();
    double getSimTotalTrials();
    int getTotalSimTime();

    // set and get pixelsPerDegree
    bool setPixelsPerDegree(double ppd);
    double getPixelsPerDegree();
    // New input and update of equations
    CImg<double> *feedInput(int step);
    void update();

    // New module
    bool addModule(module* m, string ID);
    // Get module
    module* getModule(int ID);
    // get number of modules
    int getNumberModules();
    // Connect modules
    bool connect(vector <string> from, const char *to, vector <int> operations,const char *type_synapse);

    // Grating generator
    bool generateGrating(int type,double step,double lengthB,double length,double length2,int X,int Y,double freq,double T,double Lum,double Cont,double phi,double phi_t,double theta,double red, double green, double blue,double red_phi, double green_phi,double blue_phi);
    CImg<double> *updateGrating(double t);
    // Grating for fixational Movements
    bool generateFixationalMovGrating(int X,int Y,double radius,double jitter,double period,double step,double luminance,double contrast,double orientation,double red_weight,double green_weigh, double blue_weight, int type1, int type2, int ts);
    CImg<double> *updateFixGrating(double t);
    // White noise
    bool generateWhiteNoise(double mean, double contrast1,double contrast2, double period, double switchT,int X, int Y);
    CImg<double> *updateNoise(double t);
    whiteNoise* getWhiteNoise();
    // Impulse
    bool generateImpulse(double start, double stop, double amplitude, double offset, int X, int Y);
    CImg<double> *updateImpulse(double t);
    // Use streaming video or sequence as retina input
    // A valid (non-dummy) Input module must be inserted in the retina to use these inputs
    // We need this method to distingish the other retina input types from the others implemented as modules
    // Returns true on success.
    bool setModuleInput();
    // get number of images
    int getNumberImages();
};

#endif // RETINA_H