/*************************************************************************
 *    CompuCell - A software framework for multimodel simulations of     *
 * biocomplexity problems Copyright (C) 2003 University of Notre Dame,   *
 *                             Indiana                                   *
 *                                                                       *
 * This program is free software; IF YOU AGREE TO CITE USE OF CompuCell  *
 *  IN ALL RELATED RESEARCH PUBLICATIONS according to the terms of the   *
 *  CompuCell GNU General Public License RIDER you can redistribute it   *
 * and/or modify it under the terms of the GNU General Public License as *
 *  published by the Free Software Foundation; either version 2 of the   *
 *         License, or (at your option) any later version.               *
 *                                                                       *
 * This program is distributed in the hope that it will be useful, but   *
 *      WITHOUT ANY WARRANTY; without even the implied warranty of       *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    *
 *             General Public License for more details.                  *
 *                                                                       *
 *  You should have received a copy of the GNU General Public License    *
 *     along with this program; if not, write to the Free Software       *
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        *
 *************************************************************************/

#ifndef CHEMOTAXISENERGY_H
#define CHEMOTAXISENERGY_H

#include <CompuCell3D/Potts3D/EnergyFunction.h>

#include <XMLCereal/XMLSerializable.h>
#include <CompuCell3D/Potts3D/Cell.h>
//#include <BasicUtils/BasicClassGroup.h>

#include <string>
#include <vector>

namespace CompuCell3D {
  template <class T>
  class Field3D;
  template <class T>
  class Field3DImpl;

  class Potts3D;
  class Simulator; 

  class ChemotaxisEnergy : public EnergyFunction, public XMLSerializable {
    //Field3DImpl<float> *field;
    
    

    Potts3D *potts;
    Simulator *sim;

    //double lambda;

    //std::string chemicalFieldSource;
    //bool chemotax;
    //bool gotChemicalField;

   std::vector<Field3DImpl<float> *> fieldVec;
   std::vector<float> lambdaVec;
   std::vector<std::string> chemicalFieldSourceVec;
   std::vector<std::string> chemicalFieldNameVec;
   std::vector<bool> nonChemotactingFlagVec;
   std::vector<bool> flexFlagVec;
   std::vector<std::vector<std::string> > nonChemotactingTypeNameVecVec;
   
   std::vector<std::vector<unsigned char> > nonChemotactingTypeIdVecVec;

   std::vector<std::vector<std::pair<std::string, float> > > flexChemotaxisDataVecTmp;
   std::vector<std::vector<float> > flexChemotaxisDataVec;
   bool okToChemotact(unsigned int fieldIdx,unsigned char cellType);
   
    
  public:
//     ChemotaxisEnergy(Potts3D *potts,
// 		   const double threshold, const double lambda) :
//       field(0), potts(potts), lambda(lambda),gotChemicalField(false) {}

    ChemotaxisEnergy(Potts3D *potts) :potts(potts) {}


    virtual ~ChemotaxisEnergy() {}

    void setSimulatorPtr(Simulator * _sim){sim=_sim;}
    
    //double getConcentration(const Point3D &pt);

    float getLambda(int i);
    
    void initializeField();      

    
    Field3D<float>* getField(int i);
    //void setField(int i,Field3DImpl<float>* _field ) { fieldVec[i]=_field;}
    

    


    virtual double localEnergy(const Point3D &pt);
    virtual double changeEnergy(const Point3D &pt, const CellG *newCell,
                                const CellG *oldCell);

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


    void initNonChemotactingTypeId();
    void initFlexChemotaxisData();
  };

  inline float ChemotaxisEnergy::getLambda(int i){return lambdaVec[i];}
  inline Field3D<float>* ChemotaxisEnergy::getField(int i){
   if(i<fieldVec.size())
      return fieldVec[i];
   else
      return 0;
  }
  
};

#endif
