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

#include "Boundary.h"
#include "Algorithm.h"
#include <src/CompuCell3D/Field3D/Dim3D.h>
#include <src/CompuCell3D/Field3D/Point3D.h>

using namespace std;

namespace CompuCell3D {

/*
 * Implements the singleton for Boundary strategies
 * Each axis is assigned its own boundary strategy
 */
 
    class BoundaryStrategy {

          private:

               static BoundaryStrategy *singleton;

               Dim3D dim;
               int currentStep;
               bool regular;
               Boundary *strategy_x;
               Boundary *strategy_y;
               Boundary *strategy_z;

               Algorithm* algorithm;
      

               BoundaryStrategy();
               BoundaryStrategy(string boundary_x, string boundary_y,
                             string boundary_z, string alg, int index, int size, string inputfile) ;

               
               bool isValid(const int coordinate, const int max_value);

          public:
               
               int getNumPixels(int x, int y, int z) const;               
               bool isValid(const Point3D &pt) const;
               void setIrregular();
               void setDim(const Dim3D theDim);
               void setCurrentStep(const int currentStep);
               Point3D getNeighbor(const Point3D& pt, unsigned int& token,
                                   double& distance, bool checkBounds = true);
               ~BoundaryStrategy();
   
               /*
                * Instantiates a singleton, if not done already.
                *
                * @param boundary_x boundary condition for x axis
                * @param boundary_y boundary condition for y axis
                * @param boundary_z boundary condition for z axis
                *
                **/            
               static void instantiate(string boundary_x, string boundary_y,
                                       string boundary_z, string alg,
                                       int index, int size, string inputfile) {

                     
                         if(!singleton) {

                             singleton = new BoundaryStrategy(boundary_x, boundary_y,
                                                          boundary_z, alg, index, size, inputfile);

                             
                         }
                      
               }
               
               /*
                * Return the instance of Boundary Strategy
                *
                * @return BoundaryStrategy singleton instance
                */
               static BoundaryStrategy *getInstance() {

                   if(!singleton) {
                    
                       singleton = new BoundaryStrategy();
                  
                   }
                  
                   return singleton;

               }
               
               /*
                * Destroy the singleton 
                *
                */
               static void destroy() {

                  if(singleton) delete singleton;

               }              
               

    }; 


};

#endif
