#ifndef COMPUCELL3DDIFFUSIONSOLVERBIOFILMFE_H
#define COMPUCELL3DDIFFUSIONSOLVERBIOFILMFE_H


#include <CompuCell3D/Steppable.h>
#include <CompuCell3D/Diffusable.h>
#include <CompuCell3D/Potts3D/Cell.h>
#include <CompuCell3D/Field3D/Dim3D.h>
#include <string>
#include <vector>
#include <iostream>


template <typename Y> class BasicClassAccessor;

namespace CompuCell3D {

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


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


class DiffusionSolverBiofilmFE : public Diffusable<float>
{
private:

   Potts3D *potts;
   Simulator *simPtr;

   BasicClassAccessor<Concentration> * concentrationAccessorPtr;
   
   unsigned int currentStep;
   float diffConst;
   float secrConst;
   float decConst;
   float ambientConcentration;
   float insideInitialConcentration;
   int insideRadius;
   
   Field3D<CellG *> *cellFieldG;
   Dim3D blobDim;
      
   //Field3DImpl<float> *concentrationField;
   Field3DImpl<float> *scratchField;

   std::vector<unsigned char> typesToAvoid;
   bool avoidType(unsigned char type);
   bool avoidMedium; ///medium is treaed as a special case (since it has pointer 0)
   std::string concentrationFieldName;


      
   CellInventory *cellInventoryPtr;
   
   void (DiffusionSolverBiofilmFE::*secretePtr)(void);///ptr to member method - chemical secretion
   void secrete();
   void secreteInCM();
   void (DiffusionSolverBiofilmFE::*diffusePtr)(void);///ptr to member method - Forward Euler diffusion solver
   void diffuse();
   void scratch2Concentration(Field3DImpl<float> *concentrationField, Field3DImpl<float> *scratchField);
   void DiffusionSolverBiofilmFE::outputField( std::ostream & _out,Field3DImpl<float> *_concentrationField);

   void updateBoundaryConditions();
   void updateCumulativeConcentration();/// once concentration field has changed we will need to update cumulative concentration in every cell
   
   float distance(Point3D a, Point3D b) ;
public:
    DiffusionSolverBiofilmFE();

    virtual ~DiffusionSolverBiofilmFE();
    
    //Field3DImpl<float> * getConcentrationField(){return concentrationField;};
    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

    
};

};

#endif
