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

  Program:   Visualization Toolkit
  Module:    vtkLabelHierarchyIterator.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.

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "vtkLabelHierarchyIterator.h"

#include "vtkCamera.h"
#include "vtkCellType.h"
#include "vtkCoordinate.h"
#include "vtkDataArray.h"
#include "vtkExtractSelectedFrustum.h"
#include "vtkIntArray.h"
#include "vtkLabelHierarchy.h"
#include "vtkLabelHierarchyPrivate.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPlanes.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"

vtkCxxSetObjectMacro(vtkLabelHierarchyIterator,Hierarchy,vtkLabelHierarchy);
vtkCxxSetObjectMacro(vtkLabelHierarchyIterator,TraversedBounds,vtkPolyData);

vtkLabelHierarchyIterator::vtkLabelHierarchyIterator()
{
  this->Hierarchy = nullptr;
  this->TraversedBounds = nullptr;
  this->BoundsFactor = 1.0;
  this->AllBounds = 0;
  this->AllBoundsRecorded = 0;
}

vtkLabelHierarchyIterator::~vtkLabelHierarchyIterator()
{
  if ( this->Hierarchy )
  {
    this->Hierarchy->Delete();
  }
  if ( this->TraversedBounds )
  {
    this->TraversedBounds->Delete();
  }
}

void vtkLabelHierarchyIterator::PrintSelf( ostream& os, vtkIndent indent )
{
  this->Superclass::PrintSelf( os, indent );
  os << indent << "Hierarchy: " << this->Hierarchy << "\n";
  os << indent << "BoundsFactor: " << this->BoundsFactor << "\n";
  os << indent << "TraversedBounds: " << this->TraversedBounds << "\n";
  os << indent << "AllBounds: " << this->AllBounds << "\n";
  os << indent << "AllBoundsRecorded: " << this->AllBoundsRecorded << "\n";
}

void vtkLabelHierarchyIterator::GetPoint( double x[3] )
{
  this->GetHierarchy()->GetPoints()->GetPoint( this->GetLabelId(), x );
}

void vtkLabelHierarchyIterator::GetSize( double sz[2] )
{
  if ( ! this->GetHierarchy() )
  {
    sz[0] = sz[1] = 0.;
    return;
  }
  vtkDataArray* labelSizeArr = this->GetHierarchy()->GetSizes();
  if ( ! labelSizeArr )
  {
    sz[0] = sz[1] = 0.;
    return;
  }
  vtkIdType lid = this->GetLabelId();
  double* ls = labelSizeArr->GetTuple( lid );
  sz[0] = ls[0];
  sz[1] = ls[1];
}

int vtkLabelHierarchyIterator::GetType()
{
  if ( ! this->GetHierarchy() )
  {
    return -1;
  }
  vtkDataArray* labelTypeArr = this->GetHierarchy()->GetPointData()->GetArray( "Type" );
  if ( ! labelTypeArr )
  {
    return -1;
  }
  vtkIntArray* labelTypeIArr = vtkArrayDownCast<vtkIntArray>( labelTypeArr );
  if ( ! labelTypeIArr )
  {
    return -1;
  }
  if (labelTypeIArr->GetNumberOfTuples()==0)
  {
    return -1;
  }
  vtkIdType lid = this->GetLabelId();
  return labelTypeIArr->GetValue( lid );
}

vtkStdString vtkLabelHierarchyIterator::GetLabel()
{
  if ( ! this->GetHierarchy() )
  {
    return vtkStdString();
  }
  vtkAbstractArray* labelArr = this->GetHierarchy()->GetLabels();
  if (!labelArr)
  {
    return "";
  }
  return labelArr->GetVariantValue(this->GetLabelId()).ToString();
}

vtkUnicodeString vtkLabelHierarchyIterator::GetUnicodeLabel()
{
  if ( ! this->GetHierarchy() )
  {
    return vtkUnicodeString();
  }
  vtkAbstractArray* labelArr = this->GetHierarchy()->GetLabels();
  if ( ! labelArr )
  {
    return vtkUnicodeString();
  }
  return labelArr->GetVariantValue(this->GetLabelId()).ToUnicodeString();
}

double vtkLabelHierarchyIterator::GetOrientation()
{
  if ( ! this->GetHierarchy() )
  {
    return 0.0;
  }
  vtkDataArray* arr = this->GetHierarchy()->GetOrientations();
  if ( ! arr )
  {
    return 0.0;
  }
  return arr->GetTuple1(this->GetLabelId());
}

void vtkLabelHierarchyIterator::GetBoundedSize( double sz[2] )
{
  if ( ! this->GetHierarchy() )
  {
    sz[0] = sz[1] = 0.;
    return;
  }
  vtkDataArray* boundedSizeArr = this->GetHierarchy()->GetBoundedSizes();
  if ( ! boundedSizeArr )
  {
    sz[0] = sz[1] = 0.;
    return;
  }
  vtkIdType lid = this->GetLabelId();
  double* ls = boundedSizeArr->GetTuple( lid );
  sz[0] = ls[0];
  sz[1] = ls[1];
}

void vtkLabelHierarchyIterator::BoxNode()
{
  if ( ! this->TraversedBounds || this->IsAtEnd() )
  {
    return;
  }

  if ( this->AllBounds )
  {
    if ( ! this->AllBoundsRecorded )
    {
      this->AllBoundsRecorded = 1;
      this->BoxAllNodes( this->TraversedBounds );
    }
    return;
  }

  double ctr[3];
  double sz;
  this->GetNodeGeometry( ctr, sz );
  double tf = this->BoundsFactor;

  if ( this->Hierarchy->GetImplementation()->Hierarchy3 )
  {
    this->BoxNodeInternal3( ctr, tf * sz );
  }
  else if ( this->Hierarchy->GetImplementation()->Hierarchy2 )
  {
    this->BoxNodeInternal2( ctr, tf * sz );
  }
}

void vtkLabelHierarchyIterator::BoxAllNodes( vtkPolyData* boxes )
{
  if ( ! boxes )
  {
    return;
  }

  vtkPolyData* tmp = this->TraversedBounds;
  this->TraversedBounds = boxes;
  double tf = this->BoundsFactor;

  if ( this->Hierarchy->GetImplementation()->Hierarchy3 )
  {
    vtkLabelHierarchy::Implementation::HierarchyIterator3 iter;
    for (
      iter = this->Hierarchy->GetImplementation()->Hierarchy3->begin( true );
      iter != this->Hierarchy->GetImplementation()->Hierarchy3->end( true );
      ++ iter )
    {
      this->BoxNodeInternal3( iter->value().GetCenter(), iter->value().GetSize() / 2. * tf );
    }
  }
  else if ( this->Hierarchy->GetImplementation()->Hierarchy2 )
  {
    vtkLabelHierarchy::Implementation::HierarchyIterator2 iter;
    double ctr[3];
    double zvalfoo = this->Hierarchy->GetImplementation()->Z2;
    for (
      iter = this->Hierarchy->GetImplementation()->Hierarchy2->begin( true );
      iter != this->Hierarchy->GetImplementation()->Hierarchy2->end( true );
      ++ iter )
    {
      ctr[0] = iter->value().GetCenter()[0];
      ctr[1] = iter->value().GetCenter()[1];
      ctr[2] = zvalfoo;
      this->BoxNodeInternal2( ctr, iter->value().GetSize() / 2. * tf );
    }
  }

  this->TraversedBounds = tmp;
}

static const int vtkLabelHierarchyIteratorEdgeIds[12][2] =
{
  {  0,  1 },
  {  1,  2 },
  {  2,  3 },
  {  3,  0 },

  {  4,  5 },
  {  5,  6 },
  {  6,  7 },
  {  7,  4 },

  {  0,  4 },
  {  1,  5 },
  {  2,  6 },
  {  3,  7 },
};


void vtkLabelHierarchyIterator::BoxNodeInternal3( const double* ctr, double sz )
{
  vtkIdType conn[8];
  vtkPoints* pts = this->TraversedBounds->GetPoints();
  conn[0] = pts->InsertNextPoint( ctr[0] - sz, ctr[1] - sz, ctr[2] - sz );
  conn[1] = pts->InsertNextPoint( ctr[0] + sz, ctr[1] - sz, ctr[2] - sz );
  conn[2] = pts->InsertNextPoint( ctr[0] + sz, ctr[1] + sz, ctr[2] - sz );
  conn[3] = pts->InsertNextPoint( ctr[0] - sz, ctr[1] + sz, ctr[2] - sz );
  conn[4] = pts->InsertNextPoint( ctr[0] - sz, ctr[1] - sz, ctr[2] + sz );
  conn[5] = pts->InsertNextPoint( ctr[0] + sz, ctr[1] - sz, ctr[2] + sz );
  conn[6] = pts->InsertNextPoint( ctr[0] + sz, ctr[1] + sz, ctr[2] + sz );
  conn[7] = pts->InsertNextPoint( ctr[0] - sz, ctr[1] + sz, ctr[2] + sz );
  vtkIdType econn[2];
  for ( int i = 0; i < 12; ++ i )
  {
    econn[0] = conn[vtkLabelHierarchyIteratorEdgeIds[i][0]];
    econn[1] = conn[vtkLabelHierarchyIteratorEdgeIds[i][1]];
    this->TraversedBounds->InsertNextCell( VTK_LINE, 2, econn );
  }
}

void vtkLabelHierarchyIterator::BoxNodeInternal2( const double* ctr, double sz )
{
  vtkIdType conn[4];
  vtkPoints* pts = this->TraversedBounds->GetPoints();
  conn[0] = pts->InsertNextPoint( ctr[0] - sz, ctr[1] - sz, ctr[2] );
  conn[1] = pts->InsertNextPoint( ctr[0] + sz, ctr[1] - sz, ctr[2] );
  conn[2] = pts->InsertNextPoint( ctr[0] + sz, ctr[1] + sz, ctr[2] );
  conn[3] = pts->InsertNextPoint( ctr[0] - sz, ctr[1] + sz, ctr[2] );
  vtkIdType econn[2];
  for ( int i = 0; i < 4; ++ i )
  {
    econn[0] = conn[vtkLabelHierarchyIteratorEdgeIds[i][0]];
    econn[1] = conn[vtkLabelHierarchyIteratorEdgeIds[i][1]];
    this->TraversedBounds->InsertNextCell( VTK_LINE, 2, econn );
  }
}

