// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkUniformGridAMR.h"
#include "vtkAMRDataInternals.h"
#include "vtkAMRInformation.h"
#include "vtkInformation.h"
#include "vtkInformationKey.h"
#include "vtkInformationVector.h"
#include "vtkLegacy.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkType.h"
#include "vtkUniformGrid.h"
#include "vtkUniformGridAMRDataIterator.h"

VTK_ABI_NAMESPACE_BEGIN
vtkStandardNewMacro(vtkUniformGridAMR);
vtkCxxSetSmartPointerMacro(vtkUniformGridAMR, AMRInfo, vtkAMRInformation);
vtkCxxSetSmartPointerMacro(vtkUniformGridAMR, AMRData, vtkAMRDataInternals);

//------------------------------------------------------------------------------
vtkUniformGridAMR::vtkUniformGridAMR()
{
  this->Initialize();
}

//------------------------------------------------------------------------------
vtkUniformGridAMR::~vtkUniformGridAMR() = default;

//------------------------------------------------------------------------------
vtkUniformGrid* vtkUniformGridAMR::GetDataSet(unsigned int level, unsigned int idx)
{
  if (!this->AMRData)
  {
    return nullptr;
  }

  return this->AMRData->GetDataSet(this->GetCompositeIndex(level, idx));
}

//------------------------------------------------------------------------------
vtkCompositeDataIterator* vtkUniformGridAMR::NewIterator()
{
  vtkUniformGridAMRDataIterator* iter = vtkUniformGridAMRDataIterator::New();
  iter->SetDataSet(this);
  return iter;
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::Initialize()
{
  this->Initialize(0, nullptr);
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::Initialize(int numLevels, const int* blocksPerLevel)
{
  this->AMRInfo = vtkSmartPointer<vtkAMRInformation>::New();
  this->AMRInfo->Initialize(numLevels, blocksPerLevel);

  this->AMRData = vtkSmartPointer<vtkAMRDataInternals>::New();
  this->AMRData->Initialize();
}

//------------------------------------------------------------------------------
unsigned int vtkUniformGridAMR::GetNumberOfLevels()
{
  return this->AMRInfo->GetNumberOfLevels();
}

//------------------------------------------------------------------------------
unsigned int vtkUniformGridAMR::GetTotalNumberOfBlocks()
{
  return this->AMRInfo->GetTotalNumberOfBlocks();
}

//------------------------------------------------------------------------------
unsigned int vtkUniformGridAMR::GetNumberOfDataSets(unsigned int level)
{
  return this->AMRInfo->GetNumberOfDataSets(level);
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::SetDataSet(unsigned int level, unsigned int idx, vtkUniformGrid* grid)
{
  if (!grid || !this->AMRData)
  {
    return; // nullptr grid, nothing to do
  }
  if (level >= this->GetNumberOfLevels() || idx >= this->GetNumberOfDataSets(level))
  {
    vtkErrorMacro("Invalid data set index: " << level << " " << idx);
    return;
  }

  if (this->AMRInfo->GetGridDescription() < 0)
  {
    this->AMRInfo->SetGridDescription(grid->GetDataDescription());
  }
  else if (grid->GetDataDescription() != this->AMRInfo->GetGridDescription())
  {
    vtkErrorMacro("Inconsistent types of vtkUniformGrid");
    return;
  }
  int index = this->AMRInfo->GetIndex(level, idx);
  this->AMRData->Insert(index, grid);
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::SetDataSet(vtkCompositeDataIterator* compositeIter, vtkDataObject* dataObj)
{
  if (auto amrIter = vtkUniformGridAMRDataIterator::SafeDownCast(compositeIter))
  {
    this->SetDataSet(amrIter->GetCurrentLevel(), amrIter->GetCurrentIndex(),
      vtkUniformGrid::SafeDownCast(dataObj));
  }
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::SetGridDescription(int gridDescription)
{
  this->AMRInfo->SetGridDescription(gridDescription);
}

//------------------------------------------------------------------------------
int vtkUniformGridAMR::GetGridDescription()
{
  return this->AMRInfo->GetGridDescription();
}

//------------------------------------------------------------------------------
vtkDataObject* vtkUniformGridAMR::GetDataSet(vtkCompositeDataIterator* compositeIter)
{
  if (auto amrIter = vtkUniformGridAMRDataIterator::SafeDownCast(compositeIter))
  {
    return this->GetDataSet(amrIter->GetCurrentLevel(), amrIter->GetCurrentIndex());
  }
  return nullptr;
}

//------------------------------------------------------------------------------
int vtkUniformGridAMR::GetCompositeIndex(unsigned int level, unsigned int index)
{
  if (level >= this->GetNumberOfLevels() || index >= this->GetNumberOfDataSets(level))
  {
    vtkErrorMacro("Invalid level-index pair: " << level << ", " << index);
    return 0;
  }
  return this->AMRInfo->GetIndex(level, index);
}
//------------------------------------------------------------------------------
void vtkUniformGridAMR::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  this->AMRData->PrintSelf(os, indent.GetNextIndent());
  this->AMRInfo->PrintSelf(os, indent.GetNextIndent());
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::GetLevelAndIndex(
  unsigned int compositeIdx, unsigned int& level, unsigned int& idx)
{
  this->AMRInfo->ComputeIndexPair(compositeIdx, level, idx);
}

//------------------------------------------------------------------------------
vtkUniformGridAMR* vtkUniformGridAMR::GetData(vtkInformation* info)
{
  return info ? vtkUniformGridAMR::SafeDownCast(info->Get(DATA_OBJECT())) : nullptr;
}

//------------------------------------------------------------------------------
vtkUniformGridAMR* vtkUniformGridAMR::GetData(vtkInformationVector* v, int i)
{
  return vtkUniformGridAMR::GetData(v->GetInformationObject(i));
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::CompositeShallowCopy(vtkCompositeDataSet* src)
{
  if (src == this || !this->AMRData)
  {
    return;
  }

  this->Superclass::CompositeShallowCopy(src);

  if (vtkUniformGridAMR* hbds = vtkUniformGridAMR::SafeDownCast(src))
  {
    this->SetAMRInfo(hbds->GetAMRInfo());
    this->AMRData->CompositeShallowCopy(hbds->GetAMRData());
  }

  this->Modified();
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::DeepCopy(vtkDataObject* src)
{
  if (src == this)
  {
    return;
  }
  auto mkhold = vtkMemkindRAII(this->GetIsInMemkind());
  this->Superclass::DeepCopy(src);

  if (vtkUniformGridAMR* hbds = vtkUniformGridAMR::SafeDownCast(src))
  {
    this->Initialize();
    this->AMRInfo->DeepCopy(hbds->GetAMRInfo());
    this->AMRData->DeepCopy(hbds->GetAMRData());
  }

  this->Modified();
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::CopyStructure(vtkCompositeDataSet* src)
{
  if (src == this)
  {
    return;
  }

  this->Superclass::CopyStructure(src);

  if (vtkUniformGridAMR* hbds = vtkUniformGridAMR::SafeDownCast(src))
  {
    this->SetAMRInfo(hbds->GetAMRInfo());
  }

  this->Modified();
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::ShallowCopy(vtkDataObject* src)
{
  if (src == this || !this->AMRData)
  {
    return;
  }

  this->Superclass::ShallowCopy(src);

  if (vtkUniformGridAMR* hbds = vtkUniformGridAMR::SafeDownCast(src))
  {
    this->SetAMRInfo(hbds->GetAMRInfo());
    this->AMRData->ShallowCopy(hbds->GetAMRData());
  }

  this->Modified();
}

//------------------------------------------------------------------------------
const double* vtkUniformGridAMR::GetBounds()
{
  return this->AMRInfo->GetBounds();
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::GetBounds(double bounds[6])
{
  const double* bb = this->GetBounds();
  for (int i = 0; i < 6; ++i)
  {
    bounds[i] = bb[i];
  }
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::GetMin(double min[3])
{
  const double* bb = this->GetBounds();
  min[0] = bb[0];
  min[1] = bb[2];
  min[2] = bb[4];
}

//------------------------------------------------------------------------------
void vtkUniformGridAMR::GetMax(double max[3])
{
  const double* bb = this->GetBounds();
  max[0] = bb[1];
  max[1] = bb[3];
  max[2] = bb[5];
}

//------------------------------------------------------------------------------
vtkAMRInformation* vtkUniformGridAMR::GetAMRInfo()
{
  return this->AMRInfo;
}

//------------------------------------------------------------------------------
vtkAMRDataInternals* vtkUniformGridAMR::GetAMRData()
{
  return this->AMRData;
}

VTK_ABI_NAMESPACE_END
