#ifndef COMPUCELL3DREACTIONDIFFUSIONSOLVERFE_SAVHOG_H
#define COMPUCELL3DREACTIONDIFFUSIONSOLVERFE_SAVHOG_H


#include <CompuCell3D/Steppable.h>
#include <CompuCell3D/Potts3D/Cell.h>
#include <CompuCell3D/DiffusableVector.h>

#include <string>
#include <vector>

#include <iostream>


namespace CompuCell3D {

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

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

class ReactionDiffusionSolverFE_SavHog :public DiffusableVector<float>
{
protected:

   Potts3D *potts;
   Simulator *simPtr;
   
   unsigned int currentStep;
   unsigned int maxDiffusionZ;
   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;
   Point3D minDiffusionBoxCorner, maxDiffusionBoxCorner;
   bool imposeDiffusionBox;
   bool insideDiffusionBox(Point3D & pt);
   
   CellInventory *cellInventoryPtr;
   
   void (ReactionDiffusionSolverFE_SavHog::*diffusePtr)(void);///ptr to member method - Forward Euler diffusion solver
   void diffuse();
   void scrarch2Concentration(Field3DImpl<float> *concentrationField, Field3DImpl<float> *scratchField);
   void ReactionDiffusionSolverFE_SavHog::outputField( std::ostream & _out,Field3DImpl<float> *_concentrationField);
   unsigned int numberOfFields;
   Dim3D fieldDim;
   ///Savill Hogeweg model parameters
   float C1,C2,C3;
   float c1,c2;
   float a;
   float eps1,eps2,eps3;
   float k;
   float b;
   float f(float c);
   float eps(float c);


      

   void initializeConcentration();   
public:
    ReactionDiffusionSolverFE_SavHog();

    virtual ~ReactionDiffusionSolverFE_SavHog();
    
   
    virtual void init(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

    
};

inline float ReactionDiffusionSolverFE_SavHog::f(float c)
{
   if(c<c1)
      return C1*c;
   else if (c<c2)
      return -C2*c+a;
   else
      return C3*(c-1);
}



inline float ReactionDiffusionSolverFE_SavHog::eps(float c){
   if(c<c1)
      return eps1;
   else if (c<c2)
      return eps2;
   else
      return eps3;

}


inline bool ReactionDiffusionSolverFE_SavHog::insideDiffusionBox(Point3D & pt){
   return (
      pt.x>=minDiffusionBoxCorner.x && pt.x<=maxDiffusionBoxCorner.x &&
      pt.y>=minDiffusionBoxCorner.y && pt.y<=maxDiffusionBoxCorner.y &&
      pt.z>=minDiffusionBoxCorner.z && pt.z<=maxDiffusionBoxCorner.z
   );

}


};

#endif
