/*************************************************************************
 *    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 "UniformFieldInitializer.h"

#include <CompuCell3D/Potts3D/CellInventory.h>
#include <CompuCell3D/Automaton/Automaton.h>

#include <CompuCell3D/Simulator.h>
#include <CompuCell3D/Potts3D/Cell.h>
#include <CompuCell3D/Potts3D/Potts3D.h>
#include <CompuCell3D/Field3D/Point3D.h>
#include <CompuCell3D/Field3D/Dim3D.h>
using namespace CompuCell3D;

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

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

#include <BasicUtils/BasicRandomNumberGenerator.h>
#include <string>
using namespace std;


UniformFieldInitializer::UniformFieldInitializer() :
  potts(0), gap(1), width(2) {}

UniformFieldInitializer::UniformFieldInitializer(int gap, 
							   int width) :
  potts(0), gap(gap), width(width) {
  
  ASSERT_OR_THROW("initializeCellField() width cannot be <= 0!", width > 0);
  ASSERT_OR_THROW("initializeCellField() gap cannot be < 0", gap >= 0);  
}

void UniformFieldInitializer::init(Simulator *simulator) {
  potts = simulator->getPotts();
}

void UniformFieldInitializer::start() {
  // TODO: Chage this code so it write the 0 spins too.  This will make it
  //       possible to re-initialize a previously used field.

  int size = gap + width;

  Field3D<CellG *> *cellField = potts->getCellFieldG();
  ASSERT_OR_THROW("initField() Cell field cannot be null!", cellField);

  Dim3D dim = cellField->getDim();

//  CenterOfMassPlugin * comPlugin=(CenterOfMassPlugin*)(Simulator::pluginManager.get("CenterOfMass"));
//  Cell *c;
  
//  comPlugin->getCenterOfMass(c);

  Dim3D itDim;

  itDim.x = dim.x / size;
  if (dim.x % size) itDim.x += 1;
  itDim.y = dim.y / size;
  if (dim.y % size) itDim.y += 1;
  itDim.z = dim.z / size;
  if (dim.z % size) itDim.z += 1;

  Point3D pt;
  Point3D cellPt;
  CellG *cell;

  for (int z = 0; z < itDim.z; z++)
    for (int y = 0; y < itDim.y; y++)
      for (int x = 0; x < itDim.x; x++) {
   pt.x = x * size;
   pt.y = y * size;
   pt.z = z * size;

   if (BoundaryStrategy::getInstance()->isValid(pt))
   cell = potts->createCellG(pt);
   else
       continue;


   for (cellPt.z = pt.z; cellPt.z < pt.z + width &&
          cellPt.z < dim.z; cellPt.z++)
     for (cellPt.y = pt.y; cellPt.y < pt.y + width &&
       cellPt.y < dim.y; cellPt.y++)
       for (cellPt.x = pt.x; cellPt.x < pt.x + width &&
         cellPt.x < dim.x; cellPt.x++){

         if (BoundaryStrategy::getInstance()->isValid(pt))
                  cellField->set(cellPt, cell);

       }
      }

   //Now will initialize types of cells
   initializeCellTypes();
/*   cerr<<"\t\tFIELD INITIALIZATION COMPLETE"<<endl;
   exit(0);*/
}

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

  dim = Dim3D(-1, -1, -1);
  while (in.check(START_ELEMENT)) {
    if (in.getName() == "Gap") {
      gap = BasicString::parseUInteger(in.matchSimple());

    } else if (in.getName() == "Width") {
      width = BasicString::parseUInteger(in.matchSimple());

    } 
    else if (in.getName() == "RangeBox") {
      dim.readXML(in);
      in.matchSimple();
    }
    else {
      throw BasicException(string("Unexpected element '") + in.getName() + 
			   "'!", in.getLocation());
    }

    in.skip(TEXT);
  }
}

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


void UniformFieldInitializer::initializeCellTypes(){
   BasicRandomNumberGenerator *rand = BasicRandomNumberGenerator::getInstance();
   
   cellInventoryPtr=& potts->getCellInventory();

   ///will initialize cell type here depending on the position of the cells
   CellInventory::cellInventoryIterator cInvItr;
   ///loop over all the cells in the inventory
   Point3D com;
   CellG * cell;

   
   float x,y,z;

   for(cInvItr=cellInventoryPtr->cellInventoryBegin() ; cInvItr !=cellInventoryPtr->cellInventoryEnd() ;++cInvItr ){

      cell=*cInvItr;
      ///BCGPtr=cellAccessorPtr->get(*cInvItr);
      x = cell->xCM / (float)cell->volume;
      y = cell->yCM / (float)cell->volume;
      z = cell->zCM / (float)cell->volume;
         cell->type=rand->getInteger(0,1)+1;
         cell->type=1;
/*         if ((x > 25) && (x < 30)){
            cell->type = 1;
         }else{
             if ((z >= 60) && (z <= 90)){
              cell->type = 2;
              }
             else{
              cell->type = 2;
              }
            
         }*/
         //cerr<<"vol old = "<<cell->volume<<endl;
       //cerr<<"INIT typeNode.get(cellNodes)->type "<<(int)typeNode.get(cellNodes)->type<<
       //" G part="<<(int)cellTypeGAccessorPtr->get(*cInvItr)->type<<endl;



   }



}





