//#####################################################################
// Copyright 2004-2005, Eran Guendelman, Andrew Selle.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class QT_UNIFORM_SLICE
//##################################################################### 
#ifndef __QT_UNIFORM_SLICE__
#define __QT_UNIFORM_SLICE__

#include <Core/Basic_Geometry/PLANE.h>
#include <Core/Grids/GRID.h>
#include "QT_PRIMITIVES.h"
#include "QT_SLICE.h"
#include <Core/Math_Tools/max.h>
#include <Core/Math_Tools/min.h>

namespace PhysBAM{
class QT_WORLD;
template<class T>
class QT_UNIFORM_SLICE:public OPENGL_SLICE
{
    typedef VECTOR<T,3> TV;typedef VECTOR<int,3> IV;
public:
    QT_WORLD& world;
    GRID<TV> grid;

    QT_SLICE::SLICE_MODE mode;

    int axis;
    int index;

    GLenum clip_plane_id1,clip_plane_id2;

    QT_UNIFORM_SLICE(OPENGL_WORLD<T>& world_input)
        : world(world_input),clip_plane_id1(0),clip_plane_id2(0)
    {
        Initialize(GRID<TV>(IV()+1,RANGE<TV>::Unit_Box()));
    }

    int Maximum_Slice_Index_In_Current_Mode()
    {
        VECTOR<int,3> grid_cells(grid.numbers_of_cells);
        if(mode==NODE_SLICE) return grid_cells[axis];
        else if(mode==CELL_SLICE) return grid_cells[axis]-1;
        else return -1;
    }

    void Initialize(GRID<TV> grid_input)
    {
        grid=grid_input;
        mode=NO_SLICE;
        axis=2;
        index=grid_input.Numbers_Of_Nodes().z/2;
        Update_Clip_Planes();
    }

    template<class T2>
    static void Get_Face_Index_Range(const QT_UNIFORM_SLICE<T>* slice,const ARRAYS_ND_BASE<T2,VECTOR<int,3> >& array,int face,VECTOR<int,3> &index_start,VECTOR<int,3> &index_end,int scale=1)
    {
        index_start=VECTOR<int,3>(array.domain.min_corner.x,array.domain.min_corner.y,array.domain.min_corner.z);
        index_end=VECTOR<int,3>(array.domain.max_corner.x,array.domain.max_corner.y,array.domain.max_corner.z);
        if(!slice) return;
        else if(slice->mode==CELL_SLICE) {
            if(face==slice->axis) {
                index_start[slice->axis]=max(slice->index/scale,index_start[slice->axis]);
                index_end[slice->axis]=min(slice->index/scale+1,index_end[slice->axis]);
            } else {
                index_start[slice->axis]=max(slice->index/scale,index_start[slice->axis]);
                index_end[slice->axis]=min(slice->index/scale,index_end[slice->axis]);
            }
        } else if(slice->mode==NODE_SLICE) {
            if(face==slice->axis) {
                index_start[slice->axis]=max(slice->index/scale,index_start[slice->axis]);
                index_end[slice->axis]=min(slice->index/scale,index_end[slice->axis]);
            } else {
                index_start=VECTOR<int,3>(1,1,1);
                index_end=VECTOR<int,3>(0,0,0);
            }
        }
    }

    GRID<TV> Get_Slice_Grid() const
    {
        GRID<TV> slice_grid(grid);
        slice_grid.domain.min_corner(axis)+=index*grid.dX(axis);
        slice_grid.domain.max_corner(axis)=slice_grid.domain.min_corner(axis)+grid.dX(axis);
        slice_grid.numbers_of_cells(axis)=1;
        slice_grid.numbers_of_cells=slice_grid.numbers_of_cells;
        return slice_grid;
    }

    void Print_Slice_Info(std::ostream& output_stream) override;
    bool Is_Slice_Mode() override;
    void Set_Slice_Mode(QT_SLICE::SLICE_MODE mode_input) override;
    void Toggle_Slice_Mode() override;    
    void Toggle_Slice_Axis() override;
    void Increment_Slice() override;
    void Decrement_Slice() override;    
    void Enable_Clip_Planes() override;
private:
    void Update_Clip_Planes() override;
};
}
#endif
