/*************************************************************************
 *    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 POTTS3D_H
#define POTTS3D_H

#include <CompuCell3D/Field3D/Dim3D.h>
#include <CompuCell3D/Field3D/Point3D.h>
#include <CompuCell3D/Field3D/WatchableField3D.h>
#include <CompuCell3D/Field3D/NeighborFinder.h>
#include <CompuCell3D/Viz/VizProperties.h>

#include "DefaultAcceptanceFunction.h"

#include <BasicUtils/BasicArray.h>
#include <BasicUtils/BasicDynamicClassFactory.h>

#include <BasicUtils/BasicClassAccessor.h>
#include <BasicUtils/BasicClassGroupFactory.h>
#include <BasicUtils/BasicClassGroup.h>
#include "CellInventory.h"
#include "Cell.h"
#include <string>
#include <vector>
namespace CompuCell3D {
 	


  class EnergyFunction;
  class AcceptanceFunction;
  class CellGChangeWatcher;
  class BCGChangeWatcher;
  class Stepper;
  class Automaton;
  
  /** 
   * A generic implementation of the potts model in 3D.
   *
   * See http://scienceworld.wolfram.com/physics/PottsModel.html for
   * more information about the potts model.
   */
  class Potts3D {
    /// The potts field of cell spins.
    //WatchableField3D<Cell *> *cellField;
    WatchableField3D<CellG *> *cellFieldG;
	
    /// Cell class aggregator and allocator.
    
    BasicClassGroupFactory cellFactoryGroup; 	//creates aggregate of objects associated with cell 
                              						//DOES NOT creat group of cells (as a name might suggest)
    
    
    /// An array of energy functions to be evaluated to determine energy costs.
    BasicArray<EnergyFunction *> energyFunctions;

    /// An array of potts steppers.  These are called after each potts step.
    BasicArray<Stepper *> steppers;

    /// The automaton to use.  Assuming one automaton per simulation.
    Automaton* automaton;
    
    DefaultAcceptanceFunction defaultAcceptanceFunction;

    /// Used to determine the probablity that a pixel flip should be taken.
    AcceptanceFunction *acceptanceFunction;

    /// The current total energy of the system.
    double energy;

    std::string boundary_x; // boundary condition for x axiz
    std::string boundary_y; // boundary condition for y axis
    std::string boundary_z; // boundary condition for z axis

    /// This object keeps track of all cells available in the simulations. It allows for simple iteration over all the cells
    /// It becomes useful whenever one has to visit all the cells. Without inventory one would need to go pixel-by-pixel - very inefficient
    CellInventory cellInventory; 

    Point3D flipNeighbor;
    double depth;
    std::vector<Point3D> neighbors;
    std::vector<unsigned char> frozenTypeVec;///lists types which will remain frozen throughout the simulation
    unsigned int sizeFrozenTypeVec;  
    bool checkIfFrozen(unsigned char _type);
    
  public:
    Potts3D();
    Potts3D(const Dim3D dim);
    virtual ~Potts3D();

    /** 
     * Create the cell field.
     * 
     * @param dim The field dimensions.
     */
    void createCellField(const Dim3D dim);


    double getDepth(){return depth;}
    void setDepth(double _depth);
    
    void setFrozenTypeVector(std::vector<unsigned char> & _frozenTypeVec);
    
    Point3D getFlipNeighbor(){return flipNeighbor;}  
      
    void setBoundaryXName(std::string const & _xName){boundary_x=_xName;}
    void setBoundaryYName(std::string const & _yName){boundary_y=_yName;}
    void setBoundaryZName(std::string const & _zName){boundary_z=_zName;}
    std::string const & getBoundaryXName() const{return boundary_x;}
    std::string const & getBoundaryYName() const{return boundary_y;}
    std::string const & getBoundaryZName() const{return boundary_z;}

    BasicArray<EnergyFunction *>  & getEnergyFunctionsArray(){return energyFunctions;}
    
    CellInventory &getCellInventory(){return cellInventory;}
    
    /// Add an energy function to the list.
    virtual void registerEnergyFunction(EnergyFunction *function);

    /// Add the automaton.
    virtual void registerAutomaton(Automaton* autom);

    /// Return the automaton for this simulation.
    virtual Automaton* getAutomaton();
    
    /** 
     * Set the acceptance function.  This is DefaultAcceptanceFunction
     * by default.
     */    
    virtual void registerAcceptanceFunction(AcceptanceFunction *function);

    virtual AcceptanceFunction *getAcceptanceFunction() {
      return acceptanceFunction;
    }


    /// Add a cell field update watcher.
    //virtual void registerCellChangeWatcher(CellChangeWatcher *watcher);
    
    /// registration of the BCG watcher	
    virtual void Potts3D::registerCellGChangeWatcher(CellGChangeWatcher *_watcher);
    
    
    /// Register accessor to a class with a cellGroupFactory. Accessor will access a class which is a mamber of a BasicClassGroup	
    virtual void Potts3D::registerClassAccessor(BasicClassAccessorBase *_accessor);
    
    /// Add a potts stepper to be called after each potts step.
    virtual void registerStepper(Stepper *stepper);
    

    /** 
     * @return Current energy.
     */
    double getEnergy() {return energy;}

    /** 
     * Allocate a cell.
     * 
     * @param pt The point in the cell field to put the new cell.
     * 
     * @return The newly created cell.
     */
    

    virtual CellG *createCellG(const Point3D pt);
    virtual void Potts3D::destroyCellG(CellG * cell);

    BasicClassGroupFactory * getCellFactoryGroupPtr(){return &cellFactoryGroup;};
    

    /** 
     * Deallocate a cell.
     * 
     * @param cell The cell to destroy.
     */
    
    /// dealocate a BasicClassGroup
    //virtual void Potts3D::destroyBasicClassGroup(BasicClassGroup *_BCG); 


    /// @return The current number of cells in the field.
    virtual unsigned int getNumCells() {return cellInventory.getCellInventorySize();}


    /// @return The current size in bytes of a cell.
//    virtual unsigned int getCellSize() {return cellFactory.getClassSize();}

    /** 
     * Calculate the current total energy of the system.
     *
     * @return The freshly calculated energy.
     */
    virtual double totalEnergy();


    /** 
     * Calculate the energy change of a proposed flip.
     * 
     * @param pt The point to flip.
     * @param newCell The new spin.
     * @param oldCell The old spin.
     * 
     * @return The energy change.
     */
//     virtual double changeEnergy(Point3D pt, const Cell *newCell,
// 				const Cell *oldCell);

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

				
    /** 
     * Run the potts metropolis algorithm.
     * 
     * @param steps The numer of flip attempts to make.
     * @param temp The current temperature.
     * 
     * @return The total number of accepted flips.
     */
    virtual unsigned int metropolis(const unsigned int steps, 
				    const double temp);


    /// @return A pointer to the potts cell field.
//    virtual Field3D<Cell *> *getCellField() {return cellField;}
    
    /// @return A pointer to the potts field of BasicClassGroup.
    virtual Field3D<CellG *> *getCellFieldG () {return cellFieldG;}
  };
};
#endif
