//#####################################################################
// Copyright 2005-2017, Eran Guendelman, Lin Huang, Avi Robinson-Mosher, Andrew Selle, Jonathan Su.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class CELL_ITERATOR_THREADED
//#####################################################################
#ifndef __CELL_ITERATOR_THREADED__
#define __CELL_ITERATOR_THREADED__

#include <Core/Grids/Binary_Counts.h>
#include <Core/Grids/FACE_INDEX.h>
#include <Core/Grids/GRID.h>
#include <Core/Grids/GRID_ITERATOR_BASE.h>
namespace PhysBAM{

template<class TV>
class CELL_ITERATOR_THREADED:public GRID_ITERATOR_BASE<TV>
{
    typedef VECTOR<int,TV::m> IV;
public:
    typedef GRID_REGION T_REGION;
    typedef TV VECTOR_T;
    using GRID_ITERATOR_BASE<TV>::index;using GRID_ITERATOR_BASE<TV>::Add_Region;using GRID_ITERATOR_BASE<TV>::Reset;using GRID_ITERATOR_BASE<TV>::Reset_Regions;

    GRID<TV> grid;
    CELL_ITERATOR_THREADED(const GRID<TV>& grid_input,const int number_of_ghost_cells=0);
    CELL_ITERATOR_THREADED(const GRID<TV>& grid_input,const RANGE<IV>& region_input);

    const IV& Cell_Index() const
    {return index;}

    TV Location() const
    {return grid.Cell_X(index);}

    RANGE<TV> Bounding_Box() const
    {TV minimum_corner=grid.Node_X(index);return RANGE<TV>(minimum_corner,minimum_corner+grid.dX);}

    IV Cell_Node_Index(const int node) const
    {return index+Binary_Counts<TV::m>(node);}

    IV First_Face_Index(const int axis) const
    {return grid.First_Face_Index_In_Cell(axis,index);}

    IV Second_Face_Index(const int axis) const
    {return grid.Second_Face_Index_In_Cell(axis,index);}

    FACE_INDEX<TV::m> Full_First_Face_Index(const int axis) const
    {return FACE_INDEX<TV::m>(axis,grid.First_Face_Index_In_Cell(axis,index));}

    FACE_INDEX<TV::m> Full_Second_Face_Index(const int axis) const
    {return FACE_INDEX<TV::m>(axis,grid.Second_Face_Index_In_Cell(axis,index));}

    IV Cell_Neighbor(const int i) const // 1 to 2*dimension
    {return GRID<TV>::Node_Neighbor(index,i);}
};
//#####################################################################
}
#endif
