#ifndef COMPUCELL3DFLEXIBLEDIFFUSIONSOLVERFE_H
#define COMPUCELL3DFLEXIBLEDIFFUSIONSOLVERFE_H


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

#include <CompuCell3D/DiffSecrData.h>

#include <string>

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


namespace CompuCell3D {

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

class DiffusionData;
class SecretionDataFlex;

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

class FlexibleDiffusionSolverFE :public DiffusableVector<float>
{
  public :
   typedef void (FlexibleDiffusionSolverFE::*diffSecrFcnPtr_t)(void);
   typedef void (FlexibleDiffusionSolverFE::*secrSingleFieldFcnPtr_t)(unsigned int);
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;
   
   std::vector<DiffusionData> diffDataVec;
   std::vector<SecretionDataFlex> secrDataVec;
   
   
   CellInventory *cellInventoryPtr;
   
   void (FlexibleDiffusionSolverFE::*diffusePtr)(void);///ptr to member method - Forward Euler diffusion solver
   void (FlexibleDiffusionSolverFE::*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(Field3DImpl<float> *concentrationField, Field3DImpl<float> *scratchField);
   void FlexibleDiffusionSolverFE::outputField( std::ostream & _out,Field3DImpl<float> *_concentrationField);
   void readConcentrationField(std::string fileName,Field3DImpl<float> *concentrationField);
   unsigned int numberOfFields;
   Dim3D fieldDim;

   void initializeConcentration();   
public:
    FlexibleDiffusionSolverFE();

    virtual ~FlexibleDiffusionSolverFE();
    
   
    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 SecretionDataFlex:public SecretionData{
   public:
      std::vector<FlexibleDiffusionSolverFE::secrSingleFieldFcnPtr_t> secretionFcnPtrVec;
};

// class SecretionOnContactData{
//    public:
//       std::map<unsigned char, float> contactCellMap;
// 
// };
// 
// class SecretionData: public XMLSerializable{
//       Automaton * automaton;
//    public:
//       SecretionData():
//       active(false)
//       {}
//       void setAutomaton(Automaton * _automaton){automaton=_automaton;}
//       bool active;
//       std::set<std::string> secrTypesNameSet;
//       std::vector<FlexibleDiffusionSolverFE::secrSingleFieldFcnPtr_t> secretionFcnPtrVec;
// 
//       //std::string secretionName;
// 
//       std::map<unsigned char,float> typeIdSecrConstMap;
//       std::map<unsigned char,SecretionOnContactData> typeIdSecrOnContactDataMap;
// 
//       //XMLSerializable interface
//       virtual void readXML(XMLPullParser &in);
//       virtual void writeXML(XMLSerializer &out){}
// 
// 
// };
// 
// 
// 
// 
// class DiffusionData : public XMLSerializable {
//       Automaton * automaton;
//    public:
//       DiffusionData():
//       active(false),
//       diffConst(0.0),
//       decayConst(0.0),
//       deltaX(1.0),
//       deltaT(1.0)
//       {}
// 
//       void setAutomaton(Automaton * _automaton){automaton=_automaton;}
//       bool active;
//       float diffConst;
//       float decayConst;
//       float deltaX;
//       float deltaT;
//       float dt_dx2;
//       std::string diffusionName;
//       //XMLSerializable interface
//       virtual void readXML(XMLPullParser &in);
//       virtual void writeXML(XMLSerializer &out){}
// 
// 
//       std::string fieldName;
//       std::string concentrationFileName;
//       //std::vector<std::string> avoidTypeVec;
//       std::set<unsigned char> avoidTypeIdSet;
//       //std::vector<std::string> secreteTypeVec;
// 
//       friend std::ostream & operator<<(std::ostream & out,CompuCell3D::DiffusionData & diffData);
// };
// 
// inline std::ostream & operator<<(std::ostream & out,CompuCell3D::DiffusionData & diffData){
//    using namespace std;
// 
//    out<<"DiffusionConstant: "<<diffData.diffConst<<endl;
//    out<<"DecayConstant: "<<diffData.decayConst<<endl;
//    out<<"DeltaX: "<<diffData.deltaX<<endl;
//    out<<"DeltaT: "<<diffData.deltaT<<endl;
//    out<<"fieldName: "<<diffData.fieldName<<endl;
// 
//    return out;
// }
// 


};



#endif
