// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-FileCopyrightText: Copyright 2008 Sandia Corporation
// SPDX-License-Identifier: LicenseRef-BSD-3-Clause-Sandia-USGov

#include "vtkLabelHierarchyCompositeIterator.h"

#include "vtkObjectFactory.h"
#include "vtkSmartPointer.h"

#include <utility>
#include <vector>

VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkLabelHierarchyCompositeIterator);

class vtkLabelHierarchyCompositeIterator::Internal
{
public:
  typedef std::vector<std::pair<vtkSmartPointer<vtkLabelHierarchyIterator>, int>> IteratorVector;
  IteratorVector Iterators;
  IteratorVector::size_type CurrentIterator;
  IteratorVector::size_type InitialTraversal;
  int CurrentCount;
};

vtkLabelHierarchyCompositeIterator::vtkLabelHierarchyCompositeIterator()
{
  this->Implementation = new Internal();
  this->Implementation->CurrentIterator = 0;
  this->Implementation->InitialTraversal = 0;
  this->Implementation->CurrentCount = 0;
}

vtkLabelHierarchyCompositeIterator::~vtkLabelHierarchyCompositeIterator()
{
  delete this->Implementation;
}

void vtkLabelHierarchyCompositeIterator::AddIterator(vtkLabelHierarchyIterator* it, int count)
{
  this->Implementation->Iterators.emplace_back(
    vtkSmartPointer<vtkLabelHierarchyIterator>(it), count);
}

void vtkLabelHierarchyCompositeIterator::ClearIterators()
{
  this->Implementation->Iterators.clear();
}

void vtkLabelHierarchyCompositeIterator::Begin(vtkIdTypeArray* list)
{
  this->Implementation->CurrentIterator = 0;
  this->Implementation->CurrentCount = 0;
  this->Implementation->InitialTraversal = 0;

  // Take care of the no-iterator case
  if (this->Implementation->Iterators.empty())
  {
    return;
  }

  // Call Begin on each child iterator.
  for (Internal::IteratorVector::size_type i = 0; i < this->Implementation->Iterators.size(); ++i)
  {
    this->Implementation->Iterators[i].first->Begin(list);
    if (this->TraversedBounds)
    {
      this->Implementation->Iterators[i].first->SetTraversedBounds(this->TraversedBounds);
    }
  }

  // Find a non-empty iterator to start at if it exists.
  // If not, CurrentIterator will be past the end of the array, signaling IsAtEnd.
  while (this->Implementation->CurrentIterator < this->Implementation->Iterators.size() &&
    this->Implementation->Iterators[this->Implementation->CurrentIterator].first->IsAtEnd())
  {
    this->Implementation->CurrentIterator++;
  }
}

void vtkLabelHierarchyCompositeIterator::Next()
{
  Internal::IteratorVector::size_type numIterators = this->Implementation->Iterators.size();
  Internal::IteratorVector::size_type numTried = 0;
  vtkLabelHierarchyIterator* iter =
    this->Implementation->Iterators[this->Implementation->CurrentIterator].first;
  int count = this->Implementation->Iterators[this->Implementation->CurrentIterator].second;
  while (
    numTried <= numIterators && (iter->IsAtEnd() || this->Implementation->CurrentCount >= count))
  {
    this->Implementation->CurrentCount = 0;
    this->Implementation->CurrentIterator =
      (this->Implementation->CurrentIterator + 1) % numIterators;
    iter = this->Implementation->Iterators[this->Implementation->CurrentIterator].first;
    count = this->Implementation->Iterators[this->Implementation->CurrentIterator].second;
    if (!iter->IsAtEnd())
    {
      // Don't call Next() if this is the first time we are traversing this iterator.
      if (this->Implementation->InitialTraversal < this->Implementation->CurrentIterator)
      {
        this->Implementation->InitialTraversal = this->Implementation->CurrentIterator;
      }
      else
      {
        iter->Next();
      }
    }
    ++numTried;
  }
  this->Implementation->CurrentCount++;
  if (numTried > numIterators)
  {
    // Signal end of iterator.
    this->Implementation->CurrentIterator = numIterators;
  }
}

bool vtkLabelHierarchyCompositeIterator::IsAtEnd()
{
  return this->Implementation->CurrentIterator >= this->Implementation->Iterators.size();
}

vtkIdType vtkLabelHierarchyCompositeIterator::GetLabelId()
{
  if (this->Implementation->CurrentIterator < this->Implementation->Iterators.size())
  {
    return this->Implementation->Iterators[this->Implementation->CurrentIterator]
      .first->GetLabelId();
  }
  return -1;
}

vtkLabelHierarchy* vtkLabelHierarchyCompositeIterator::GetHierarchy()
{
  if (this->Implementation->CurrentIterator < this->Implementation->Iterators.size())
  {
    return this->Implementation->Iterators[this->Implementation->CurrentIterator]
      .first->GetHierarchy();
  }
  return nullptr;
}

void vtkLabelHierarchyCompositeIterator::GetNodeGeometry(double ctr[3], double& size)
{
  if (this->Implementation->CurrentIterator < this->Implementation->Iterators.size())
  {
    this->Implementation->Iterators[this->Implementation->CurrentIterator].first->GetNodeGeometry(
      ctr, size);
  }
}

void vtkLabelHierarchyCompositeIterator::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
}
VTK_ABI_NAMESPACE_END
