// SPDX-FileCopyrightText: Copyright (c) Kitware Inc.
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkMaterialInterfaceProcessRing.h"
#include <iostream>

using std::endl;
using std::ostream;
//
class vtkMaterialInterfaceProcessRing::BufferContainer : public std::vector<vtkIdType>
{
};
//
vtkMaterialInterfaceProcessRing::vtkMaterialInterfaceProcessRing()
{
  this->NextElement = 0;
  this->BufferSize = 0;
  this->Buffer = new BufferContainer;
}
//
vtkMaterialInterfaceProcessRing::~vtkMaterialInterfaceProcessRing()
{
  delete this->Buffer;
}
//
void vtkMaterialInterfaceProcessRing::Clear()
{
  this->NextElement = 0;
  this->BufferSize = 0;
  this->Buffer->clear();
}
//
void vtkMaterialInterfaceProcessRing::Initialize(int nProcs)
{
  this->NextElement = 0;
  this->BufferSize = nProcs;
  this->Buffer->resize(nProcs);
  for (int procId = 0; procId < nProcs; ++procId)
  {
    (*this->Buffer)[procId] = procId;
  }
}
//
// void vtkMaterialInterfaceProcessRing::Initialize(
//     vtkMaterialInterfaceProcessPriorityQueue &Q,
//     vtkIdType upperLoadingBound)
// {
//   this->NextElement=0;
//   this->BufferSize=0;
//   this->Buffer->clear();
//
//   // check that upper bound does not exclude
//   // all processes.
//   vtkMaterialInterfaceProcessLoading &pl=Q.Pop();
//   vtkIdType minimumLoading=pl.GetLoadFactor();
//
//   // Make sure at least one process can be used.
//   if (upperLoadingBound!=-1
//       && minimumLoading>upperLoadingBound)
//     {
//     upperLoadingBound=minimumLoading;
//     std::cerr << "vtkMaterialInterfaceProcessRing "
//           << "[" << __LINE__ << "] "
//           << "Error: Upper loading bound excludes all processes."
//           << endl;
//     }
//
//   // Build ring of process ids.
//   this->Buffer->push_back(pl.GetId());
//   ++this->BufferSize;
//   while (!Q.Empty())
//     {
//     pl=Q.Pop();
//     if (upperLoadingBound!=-1
//         && pl.GetLoadFactor()>upperLoadingBound)
//       {
//       break;
//       }
//     this->Buffer->push_back(pl.GetId());
//     ++this->BufferSize;
//     }
// }
//
void vtkMaterialInterfaceProcessRing::Initialize(
  std::vector<vtkMaterialInterfaceProcessLoading>& Q, vtkIdType upperLoadingBound)
{
  this->NextElement = 0;
  this->BufferSize = 0;
  this->Buffer->clear();

  size_t nItems = Q.size();
  assert(nItems > 0);

  // check that upper bound does not exclude
  // all processes.
  vtkMaterialInterfaceProcessLoading& pl = Q[0];
  vtkIdType minimumLoading = pl.GetLoadFactor();

  // Make sure at least one process can be used.
  if (upperLoadingBound != -1 && minimumLoading > upperLoadingBound)
  {
    upperLoadingBound = minimumLoading;
    std::cerr << "vtkMaterialInterfaceProcessRing "
              << "[" << __LINE__ << "] "
              << "Error: Upper loading bound excludes all processes." << endl;
  }

  // Build ring of process ids.
  this->Buffer->push_back(pl.GetId());
  ++this->BufferSize;
  for (size_t itemId = 1; itemId < nItems; ++itemId)
  {
    pl = Q[itemId];
    if (upperLoadingBound != -1 && pl.GetLoadFactor() > upperLoadingBound)
    {
      break;
    }
    this->Buffer->push_back(pl.GetId());
    ++this->BufferSize;
  }
}
//
vtkIdType vtkMaterialInterfaceProcessRing::GetNextId()
{
  vtkIdType id = (*this->Buffer)[this->NextElement];
  ++this->NextElement;
  if (this->NextElement == this->BufferSize)
  {
    this->NextElement = 0;
  }
  return id;
}
//
void vtkMaterialInterfaceProcessRing::Print()
{
  size_t n = this->Buffer->size();
  if (n == 0)
  {
    std::cerr << "{}";
    return;
  }
  std::cerr << "{" << (*this->Buffer)[0];
  for (size_t i = 1; i < n; ++i)
  {
    std::cerr << ", " << (*this->Buffer)[i];
  }
  std::cerr << "}";
}
