#ifndef COMPUCELL3DADVECTIONDIFFUSIONSOLVERFE_H
#define COMPUCELL3DADVECTIONDIFFUSIONSOLVERFE_H


#include <CompuCell3D/Steppable.h>
#include <CompuCell3D/Potts3D/Cell.h>
#include <CompuCell3D/DiffusableGraph.h>
#include <CompuCell3D/DiffSecrData.h>

#include <string>

#include <vector>
#include <set>
#include <map>
#include <iostream>


template<typename T>
class BasicClassAccessor;


namespace CompuCell3D {

/**
@author m
*/
//forward declarations
class Potts3D;
class Simulator;
class Cell;
class CellInventory;
class Automaton;

class DiffusionData;
class SecretionDataFlexAD;

template <typename Y> class Field3D;
template <typename Y> class Field3DImpl;

class NeighborTracker;


class AdvectionDiffusionSolverFE :public DiffusableGraph<float>
{
  public :
   typedef void (AdvectionDiffusionSolverFE::*diffSecrFcnPtr_t)(void);
   typedef void (AdvectionDiffusionSolverFE::*secrSingleFieldFcnPtr_t)(unsigned int);
protected:

   Potts3D *potts;
   Simulator *simPtr;
   
   unsigned int currentStep;
   unsigned int maxDiffusionZ;
   float averageRadius;
/*   float diffConst;
   float decayConst;
   float deltaX;//spacing
   float deltaT;//time interval
   float dt_dx2; //ratio delta_t/delta_x^2 */
   Field3D<CellG *> *cellFieldG;
   Automaton *automaton;
   
   std::vector<DiffusionData> diffDataVec;
   std::vector<SecretionDataFlexAD> secrDataVec;
   
   
   CellInventory *cellInventoryPtr;
   
   void (AdvectionDiffusionSolverFE::*diffusePtr)(void);///ptr to member method - Forward Euler diffusion solver
   void (AdvectionDiffusionSolverFE::*secretePtr)(void);///ptr to member method - Forward Euler diffusion solver
   void diffuse();
   void diffuseSingleField(unsigned int idx);
   void secrete();
   //void secreteOnContact();
   void secreteSingleField(unsigned int idx);
   void secreteOnContactSingleField(unsigned int idx);
    void scrarch2Concentration( std::map<CellG *, float> * scratchField, std::map<CellG *, float> *concentrationField);
    
    void cellMap2Field(std::map<CellG *, float> *concentrationMapField , Field3DImpl<float> *concentrationField);
    void field2CellMap(Field3DImpl<float> *concentrationField , std::map<CellG *, float> *concentrationMapField );
    
//     void outputField( std::ostream & _out,Field3DImpl<float> *_concentrationField);
   void readConcentrationField(std::string fileName,Field3DImpl<float> *concentrationField);
   unsigned int numberOfFields;
   Dim3D fieldDim;

   void initializeConcentration();

   double computeAverageCellRadius();

   
   void update();
   void updateLocalCellInventory(unsigned int idx);
   BasicClassAccessor<NeighborTracker> * neighborTrackerAccessorPtr;
   
public:
    AdvectionDiffusionSolverFE();

    virtual ~AdvectionDiffusionSolverFE();
    
   
    virtual void init(Simulator *simulator);
    virtual void extraInit(Simulator *simulator);
    
    // Begin Steppable interface
    virtual void start();
    virtual void step(const unsigned int _currentStep);
    virtual void finish() {}
    // End Steppable interface

    // Begin XMLSerializable interface
    virtual void readXML(XMLPullParser &in);
    virtual void writeXML(XMLSerializer &out){};
    // End XMLSerializable interface

    
};

class SecretionDataFlexAD:public SecretionData{
   public:
      std::vector<AdvectionDiffusionSolverFE::secrSingleFieldFcnPtr_t> secretionFcnPtrVec;
};


};



#endif
