/*************************************************************************
 *    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.        *
 *************************************************************************/

#include "ChemotaxisDictyEnergy.h"

#include <CompuCell3D/Field3D/Dim3D.h>
#include <CompuCell3D/ClassRegistry.h>
#include <CompuCell3D/Simulator.h>
#include <CompuCell3D/DiffusableVector.h>
#include <CompuCell3D/Field3D/Field3D.h>
#include <CompuCell3D/Field3D/Field3DIO.h>
#include <CompuCell3D/Potts3D/Cell.h>
#include <CompuCell3D/DiffusionSolverBiofilmFE.h>
#include <CompuCell3D/plugins/SimpleClock/SimpleClock.h>
using namespace CompuCell3D;

#include <XMLCereal/XMLPullParser.h>
#include <XMLCereal/XMLSerializer.h>

#include <BasicUtils/BasicString.h>
#include <BasicUtils/BasicException.h>


#include <fstream>
#include <string>
using namespace std;

double ChemotaxisDictyEnergy::getConcentration(const Point3D &pt) {
  ASSERT_OR_THROW("No chemical field has been initialized!", field);
  return field->get(pt);
}


double ChemotaxisDictyEnergy::localEnergy(const Point3D &pt) {
  ASSERT_OR_THROW("No chemical field has been initialized!", field);
  return 0;
}

void ChemotaxisDictyEnergy::initializeField(){

  
   if(!gotChemicalField){///this is only temporary solution will have to come up with something better
      ClassRegistry *classRegistry=sim->getClassRegistry();
      Steppable * steppable=classRegistry->getStepper(chemicalFieldSource);
      //if(chemicalFieldSource=="DiffusionSolverBiofilmFE"){
         field=((DiffusableVector<float> *) steppable)->getConcentrationField(chemicalFieldName);
         gotChemicalField=true;
      //}
  
  ASSERT_OR_THROW("No chemical field has been loaded!", field);
  
  }
}

double ChemotaxisDictyEnergy::changeEnergy(const Point3D &pt,
                                  const CellG *newCell,
                                  const CellG *oldCell) {
                                           
/*  if(!gotChemicalField){///this is only temporary solution will have to come up with something better
      ClassRegistry *classRegistry=sim->getClassRegistry();
      Steppable * steppable=classRegistry->getStepper(chemicalFieldSource);
      //if(chemicalFieldSource=="DiffusionSolverBiofilmFE"){
         field=((DiffusableVector<float> *) steppable)->getConcentrationField(chemicalFieldName);
         gotChemicalField=true;
      //}
  cerr<<"initializing concentration field "<<field<<endl;
  
  ASSERT_OR_THROW("No chemical field has been loaded!", field);      
  } */
 
  
//   if (oldCell) { /// assuming lambda >0,  the bigger the concentration the harder it will be to flip the spin at this pt - this is pseudo-energy
//     float concentration = field->get(pt);
//     return concentration*lambda;
//   }

 //float concentration = field->get(pt);
 //float energy=field->get(pt)*lambda;
// cells want to keep the highest concentration and move towards regions of highest concentrations
//   if (newCell) {
//     
//    return energy;
//   } else{
//    return -energy;
//   }


//    //Rolover condition for linear y concentration and periondic y boundary conditions
//    energy=fabs(energy);
//    if((potts->getFlipNeighbor().y-pt.y)==0){
//       energy=0.0;
//    }else{
//       if(pt.y==0 && potts->getFlipNeighbor().y==54){
//       //if(pt.y==0 && potts->getFlipNeighbor().y==54){
//          //cerr<<"pt="<<pt<<" potts->getFlipNeighbor()="<<potts->getFlipNeighbor()<<endl;
//          energy=-lambda;
// 
//          //cerr<<"energy="<<energy<<endl;
// 
//       }else{
//          energy=(potts->getFlipNeighbor().y-pt.y)*energy;
// 
// 
//          //cerr<<"energy="<<energy<<endl;
//       }
// 
//    }


   if(!gotChemicalField)
      return 0.0;

   if(newCell && !simpleClockAccessorPtr->get(newCell->extraAttribPtr)->flag){
      ///flag must be non-zero and clock must be counting down in order for chemotaxis to work
      return 0.0;
   }
   //cerr<<"Chemotacting"<<endl;
//    if(newCell){
//       cerr<<"Chemotacting ";
//       cerr<<simpleClockAccessorPtr->get(newCell->extraAttribPtr)->clock<<endl;
//    }

   
///cells move up the concentration gradient
float concentration=field->get(pt);
float neighborConcentration=field->get(potts->getFlipNeighbor());
float energy = (neighborConcentration - concentration)*lambda;
unsigned char type;


   /// new cell has to be different than medium i.e. only non-medium cells can chemotact
   ///e.g. in chemotaxis only non-medium cell can move a pixel that either belonged to other cell or to medium
   ///but situation where medium moves to a new pixel is not considered a chemotaxis
   if(newCell){
/*         type=newCell->type;
         for(unsigned int i=0;i<nonChemotacticTypeVector.size();++i){
            if(type==nonChemotacticTypeVector[i])
               return 0.0;
         }*/
/*      if(energy!=0.0){
         cerr<<"pt="<<pt<<" potts->getFlipNeighbor()="<<potts->getFlipNeighbor()<<endl;
      
         cerr<<"energy change chmotaxis="<<energy<<endl;
      }*/
      return energy;
   }
 
  return 0.0;
}


void ChemotaxisDictyEnergy::readXML(XMLPullParser &in) {
  in.skip(TEXT);

  while (in.check(START_ELEMENT)) {
   if (in.getName() == "Lambda") {
      lambda = BasicString::parseDouble(in.matchSimple());      

    }
   else if (in.getName() == "NonChemotacticType") {
      unsigned char nonChemotacticType;
       nonChemotacticType= BasicString::parseUByte(in.matchSimple());

       nonChemotacticTypeVector.push_back(nonChemotacticType);
    } 
    
    else if (in.getName() == "ChemicalField") {

      
      chemicalFieldSource = in.getAttribute("Source").value;
      chemicalFieldName = in.matchSimple();
         
     
        
    }
        
   else {
      throw BasicException(string("Unexpected element '") + in.getName() +
                           "'!", in.getLocation());
    }

    in.skip(TEXT);
  }

}

void ChemotaxisDictyEnergy::writeXML(XMLSerializer &out) {
}
