/*=========================================================================

Program:   Visualization Toolkit
Module:    vtkHyperTreeGridGeometryEntry.cxx

Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkHyperTreeGridGeometryEntry.h"

#include "vtkHyperTree.h"
#include "vtkHyperTreeGrid.h"

#include <cassert>

//-----------------------------------------------------------------------------
void vtkHyperTreeGridGeometryEntry::PrintSelf( ostream& os, vtkIndent indent )
{
  os << indent << "--vtkHyperTreeGridGeometryLevelEntry--" << endl;
  os << indent << "Index:" << this->Index << endl;
  os << indent << "Origin:"
               << this->Origin[0] << ", "
               << this->Origin[1] << ", "
               << this->Origin[2] << endl;
}

//-----------------------------------------------------------------------------
void vtkHyperTreeGridGeometryEntry::Dump( ostream& os )
{
  os << "Index:" << this->Index << endl;
  os << "Origin:"
     << this->Origin[0] << ", "
     << this->Origin[1] << ", "
     << this->Origin[2] << endl;
}

//-----------------------------------------------------------------------------
vtkHyperTree* vtkHyperTreeGridGeometryEntry::Initialize( vtkHyperTreeGrid* grid, vtkIdType treeIndex, bool create )
{
  this->Index = 0;
  grid->GetLevelZeroOriginFromIndex( treeIndex, this->Origin);
  return grid->GetTree( treeIndex, create );
}

//-----------------------------------------------------------------------------
vtkIdType vtkHyperTreeGridGeometryEntry::GetGlobalNodeIndex( const vtkHyperTree* tree ) const
{
  assert( "pre: not_tree" &&
          tree );
  return tree->GetGlobalIndexFromLocal( this->Index );
}

//-----------------------------------------------------------------------------
void vtkHyperTreeGridGeometryEntry::SetGlobalIndexStart( vtkHyperTree* tree, vtkIdType index )
{
  assert( "pre: not_tree" &&
          tree );
  tree->SetGlobalIndexStart( index );
}

//-----------------------------------------------------------------------------
void vtkHyperTreeGridGeometryEntry::SetGlobalIndexFromLocal( vtkHyperTree* tree, vtkIdType index )
{
  assert( "pre: not_tree" &&
          tree );
  tree->SetGlobalIndexFromLocal( this->Index, index );
}

//-----------------------------------------------------------------------------
bool vtkHyperTreeGridGeometryEntry::IsLeaf( const vtkHyperTree* tree ) const
{
  assert( "pre: not_tree" &&
          tree );
  if ( this->Index )
  {
    return tree->IsLeaf( this->Index );
  }
  return ( tree->GetNumberOfVertices() == 1 );
}

//---------------------------------------------------------------------------
void vtkHyperTreeGridGeometryEntry::SubdivideLeaf( vtkHyperTree* tree, unsigned int level)
{
  assert( "pre: not_tree" &&
          tree );
  if ( this->IsLeaf( tree ) )
  {
    tree->SubdivideLeaf( this->Index, level );
  }
}

//---------------------------------------------------------------------------
bool vtkHyperTreeGridGeometryEntry::IsTerminalNode( const vtkHyperTree* tree ) const
{
  assert( "pre: not_tree" &&
          tree );
  bool result = ! this->IsLeaf( tree );
  if ( result )
  {
    result = tree->IsTerminalNode( this->Index );
  }
  assert( "post: compatible" &&
          ( ! result || ! this->IsLeaf( tree ) ) );
  return result;
}

//-----------------------------------------------------------------------------
void vtkHyperTreeGridGeometryEntry::ToChild(
  const vtkHyperTreeGrid* grid,
  const vtkHyperTree* tree,
  const double* sizeChild,
  unsigned char ichild
)
{
  assert( "pre: not_tree" &&
          tree );
  assert( "pre: not_leaf" &&
          ! this->IsLeaf( tree ) );
  assert( "pre: valid_child" &&
          ichild < tree->GetNumberOfChildren() );

  this->Index = tree->GetElderChildIndex( this->Index ) + ichild;

  // Divide cell size and translate origin per template parameter
  switch ( tree->GetNumberOfChildren() )
  {
    case 2: // dimension = 1, branch factor = 2
    {
      unsigned int axis = grid->GetOrientation();
      this->Origin[axis] += ( ichild & 1 ) * sizeChild[axis];
      break;
    }
    case 3: // dimension = 1, branch factor = 3
    {
      unsigned int axis = grid->GetOrientation();
      this->Origin[axis] += ( ichild % 3 ) * sizeChild[axis];
      break;
    }
    case 4: // dimension = 2, branch factor = 2
    {
      unsigned int axis1 = 0;
      unsigned int axis2 = 1;
      switch ( grid->GetOrientation() )
      {
        case 0:
          axis1 = 1;
          VTK_FALLTHROUGH;
        case 1:
          axis2 = 2;
      }
      this->Origin[axis1] += ( ichild & 1 ) * sizeChild[axis1];
      this->Origin[axis2] += ( ( ichild & 2 ) >> 1 ) * sizeChild[axis2];
      break;
    }
    case 9: // dimension = 2, branch factor = 3
    {
      unsigned int axis1 = 0;
      unsigned int axis2 = 1;
      switch ( grid->GetOrientation() )
      {
        case 0:
          axis1 = 1;
          VTK_FALLTHROUGH;
        case 1:
          axis2 = 2;
      }
      this->Origin[axis1] += ( ichild % 3 ) * sizeChild[axis1];
      this->Origin[axis2] += ( ( ichild % 9 ) / 3 ) * sizeChild[axis2];
      break;
    }
    case 8: // dimension = 3, branch factor = 2
    {
      this->Origin[0] += ( ichild & 1 ) * sizeChild[0];
      this->Origin[1] += ( ( ichild & 2 ) >> 1 ) * sizeChild[1];
      this->Origin[2] += ( ( ichild & 4 ) >> 2 ) * sizeChild[2];
      break;
    }
    case 27: // dimension = 3, branch factor = 3
    {
      this->Origin[0] += ( ichild % 3 ) * sizeChild[0];
      this->Origin[1] += ( ( ichild % 9 ) / 3 ) * sizeChild[1];
      this->Origin[2] += ( ichild / 9 ) * sizeChild[2];
      break;
    }
  }
}
