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

#include "vtkActor2DCollection.h"
#include "vtkObjectFactory.h"

VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkActor2DCollection);

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

// protected function to delete an element. Internal use only.
void vtkActor2DCollection::DeleteElement(vtkCollectionElement* e)
{
  vtkCollection::DeleteElement(e);
}

// Destructor for the vtkActor2DCollection class. This removes all
// objects from the collection.
vtkActor2DCollection::~vtkActor2DCollection()
{
  this->RemoveAllItems();
}

// Sort and then render the collection of 2D actors.
void vtkActor2DCollection::RenderOverlay(vtkViewport* viewport)
{
  if (this->NumberOfItems != 0)
  {
    this->Sort();
    vtkActor2D* tempActor;
    vtkCollectionSimpleIterator adit;
    for (this->InitTraversal(adit); (tempActor = this->GetNextActor2D(adit));)
    {
      // Make sure that the actor is visible before rendering
      if (tempActor->GetVisibility() == 1)
      {
        tempActor->RenderOverlay(viewport);
      }
    }
  }
}

// Add an actor to the list.  The new actor is
// inserted in the list according to it's layer
// number.
void vtkActor2DCollection::AddItem(vtkActor2D* a)
{
  vtkCollectionElement* indexElem;
  vtkCollectionElement* elem = new vtkCollectionElement;

  // Check if the top item is nullptr
  if (this->Top == nullptr)
  {
    vtkDebugMacro(<< "vtkActor2DCollection::AddItem - Adding item to top of the list");

    this->Top = elem;
    elem->Item = a;
    elem->Next = nullptr;
    this->Bottom = elem;
    this->NumberOfItems++;
    a->Register(this);
    return;
  }

  for (indexElem = this->Top; indexElem != nullptr; indexElem = indexElem->Next)
  {

    vtkActor2D* tempActor = static_cast<vtkActor2D*>(indexElem->Item);
    if (a->GetLayerNumber() < tempActor->GetLayerNumber())
    {
      // The indexElem item's layer number is larger, so swap
      // the new item and the indexElem item.
      vtkDebugMacro(<< "vtkActor2DCollection::AddItem - Inserting item");
      elem->Item = indexElem->Item;
      elem->Next = indexElem->Next;
      indexElem->Item = a;
      indexElem->Next = elem;
      this->NumberOfItems++;
      a->Register(this);
      return;
    }
  }

  // End of list found before a larger layer number
  vtkDebugMacro(<< "vtkActor2DCollection::AddItem - Adding item to end of the list");
  elem->Item = a;
  elem->Next = nullptr;
  this->Bottom->Next = elem;
  this->Bottom = elem;
  this->NumberOfItems++;
  a->Register(this);
}

// Sorts the vtkActor2DCollection by layer number.  Smaller layer
// numbers are first.  Layer numbers can be any integer value.
void vtkActor2DCollection::Sort()
{
  int index;

  vtkDebugMacro(<< "vtkActor2DCollection::Sort");

  int numElems = this->GetNumberOfItems();

  // Create an array of pointers to actors
  vtkActor2D** actorPtrArr = new vtkActor2D*[numElems];

  vtkDebugMacro(<< "vtkActor2DCollection::Sort - Getting actors from collection");

  // Start at the beginning of the collection
  vtkCollectionSimpleIterator ait;
  this->InitTraversal(ait);

  // Fill the actor array with the items in the collection
  for (index = 0; index < numElems; index++)
  {
    actorPtrArr[index] = this->GetNextActor2D(ait);
  }

  vtkDebugMacro(<< "vtkActor2DCollection::Sort - Starting selection sort");
  // Start the sorting - selection sort
  int i, j, min;
  vtkActor2D* t;

  for (i = 0; i < numElems - 1; i++)
  {
    min = i;
    for (j = i + 1; j < numElems; j++)
    {
      if (actorPtrArr[j]->GetLayerNumber() < actorPtrArr[min]->GetLayerNumber())
      {
        min = j;
      }
    }
    t = actorPtrArr[min];
    actorPtrArr[min] = actorPtrArr[i];
    actorPtrArr[i] = t;
  }

  vtkDebugMacro(<< "vtkActor2DCollection::Sort - Selection sort done.");

  for (index = 0; index < numElems; index++)
  {
    vtkDebugMacro(<< "vtkActor2DCollection::Sort - actorPtrArr[" << index
                  << "] layer: " << actorPtrArr[index]->GetLayerNumber());
  }

  vtkDebugMacro(<< "vtkActor2DCollection::Sort - Rearraging the linked list.");
  // Now move the items around in the linked list -
  // keep the links the same, but swap around the items

  vtkCollectionElement* elem = this->Top;
  elem->Item = actorPtrArr[0];

  for (i = 1; i < numElems; i++)
  {
    elem = elem->Next;
    elem->Item = actorPtrArr[i];
  }

  delete[] actorPtrArr;
}
VTK_ABI_NAMESPACE_END
