//#####################################################################
// Copyright 2005-2008, Eran Guendelman, Jerry Talton.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class FACE_ITERATOR
//#####################################################################
#ifndef __FACE_ITERATOR__
#define __FACE_ITERATOR__

#include <Core/Grids/FACE_INDEX.h>
#include <Core/Grids/FACE_RANGE_ITERATOR.h>
#include <Core/Grids/GRID.h>
#include <Core/Utilities/PHYSBAM_ATTRIBUTE.h>

namespace PhysBAM{

template<class TV>
class FACE_ITERATOR:public FACE_RANGE_ITERATOR<TV::m>
{
public:
    typedef VECTOR<int,TV::m> IV;typedef typename TV::SCALAR T;
    typedef TV VECTOR_T;
    typedef FACE_RANGE_ITERATOR<TV::m> BASE;
    using BASE::Set_Range;using BASE::Initialize;using BASE::face;
    using BASE::side;

    const GRID<TV>& grid;

    // axis_input==0 means iterate through faces in all dimensions
    FACE_ITERATOR(const GRID<TV>& grid_input,const int number_of_ghost_cells_input=0,
        const GRID_REGION& region_type_input=WHOLE_REGION,
        const int side_input=-1,int axis_input=-1);

    FACE_ITERATOR(const GRID<TV>& grid_input,const RANGE<IV>& explicit_region_input,
        const int axis_input);

    int Axis() const
    {return face.axis;}

    const IV& Face_Index() const
    {return face.index;}

    FACE_INDEX<TV::m> Full_Index() const
    {return face;}

    TV Location() const
    {return grid.Face_X(Full_Index());}

    IV First_Cell_Index() const
    {IV i(face.index);i(face.axis)--;return i;}

    IV Second_Cell_Index() const
    {return face.index;}

    void Unordered_Cell_Indices_Touching_Face(IV& cell1,IV& cell2) const
    {cell1=First_Cell_Index();cell2=Second_Cell_Index();}

    RANGE<TV> Dual_Cell() const
    {return RANGE<TV>(Location()-(T).5*grid.dX,Location()+(T).5*grid.dX);}

    TV First_Cell_Center() const
    {return grid.Cell_X(First_Cell_Index());}

    TV Second_Cell_Center() const
    {return grid.Cell_X(Second_Cell_Index());}

    bool First_Boundary() const // returns true if currently on left, bottom, or front boundary
    {return side%2==0;}

    IV Face_Node_Index(const int node) const // 1-based
    {return grid.Face_Node_Index(face.axis,face.index,node);}
//#####################################################################
};
}
#endif
