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

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

=========================================================================*/
// Test vtkImageToAMR filter.

#include "vtkCellData.h"
#include "vtkPointData.h"

#include "vtkAMRBox.h"
#include "vtkDataObject.h"
#include "vtkIdFilter.h"
#include "vtkIdTypeArray.h"
#include "vtkImageData.h"
#include "vtkImageToAMR.h"
#include "vtkNew.h"
#include "vtkOverlappingAMR.h"
#include "vtkRTAnalyticSource.h"
#include "vtkUniformGrid.h"
#include "vtkVector.h"

#include <vector>
#define VTK_SUCCESS 0
#define VTK_FAILURE 1

namespace
{
//
int ComputeNumCells(vtkOverlappingAMR* amr)
{
  int n(0);
  for (unsigned int level = 0; level < amr->GetNumberOfLevels(); level++)
  {
    int numDataSets = amr->GetNumberOfDataSets(level);
    for (int i = 0; i < numDataSets; i++)
    {
      vtkUniformGrid* grid = amr->GetDataSet(level, i);
      int numCells = grid->GetNumberOfCells();
      for (int cellId = 0; cellId < numCells; cellId++)
      {
        n += grid->IsCellVisible(cellId) ? 1 : 0;
      }
    }
  }
  return n;
}

vtkIdType FindCell(vtkImageData* image, double point[3])
{
  double pcoords[3];
  int subid = 0;
  return image->vtkImageData::FindCell(point, nullptr, -1, 0.1, subid, pcoords, nullptr);
}
};

int TestImageToAMR(int, char*[])
{
  vtkNew<vtkRTAnalyticSource> imageSource;
  imageSource->SetWholeExtent(0, 0, -128, 128, -128, 128);

  vtkNew<vtkIdFilter> idFilter;
  idFilter->SetInputConnection(imageSource->GetOutputPort());

  vtkNew<vtkImageToAMR> amrConverter;
  amrConverter->SetInputConnection(idFilter->GetOutputPort());
  amrConverter->SetNumberOfLevels(4);

  std::vector<vtkVector3d> samples;
  for (int i = -118; i < 122; i += 10)
  {
    samples.push_back(vtkVector3d(0.0, (double)i, (double)i));
  }

  for (unsigned int numLevels = 1; numLevels <= 4; numLevels++)
  {
    for (int maxBlocks = 10; maxBlocks <= 50; maxBlocks += 10)
    {
      amrConverter->SetNumberOfLevels(numLevels);
      amrConverter->SetMaximumNumberOfBlocks(maxBlocks);
      amrConverter->Update();
      vtkImageData* image = vtkImageData::SafeDownCast(idFilter->GetOutputDataObject(0));
      vtkOverlappingAMR* amr =
        vtkOverlappingAMR::SafeDownCast(amrConverter->GetOutputDataObject(0));
      amr->Audit();
      // cout<<amr->GetTotalNumberOfBlocks()<<" "<<maxBlocks<<endl;
      if (amr->GetNumberOfLevels() != numLevels)
      {
        return VTK_FAILURE;
      }
      if (maxBlocks < static_cast<int>(amr->GetTotalNumberOfBlocks()))
      {
        return VTK_FAILURE;
      }
      if (ComputeNumCells(amr) != image->GetNumberOfCells())
      {
        return VTK_FAILURE;
      }

      vtkIdTypeArray* cd =
        vtkArrayDownCast<vtkIdTypeArray>(image->GetCellData()->GetArray("vtkIdFilter_Ids"));
      assert(cd);
      for (std::vector<vtkVector3d>::iterator itr = samples.begin(); itr != samples.end(); ++itr)
      {
        double* x = (*itr).GetData();
        vtkIdType cellId = FindCell(image, x);
        vtkIdType value = cd->GetValue(cellId);
        assert(cellId == value);

        unsigned int level, id;
        if (amr->FindGrid(x, level, id))
        {
          vtkUniformGrid* grid = amr->GetDataSet(level, id);
          vtkIdTypeArray* cd1 =
            vtkArrayDownCast<vtkIdTypeArray>(grid->GetCellData()->GetArray("vtkIdFilter_Ids"));
          vtkIdType cellId1 = FindCell(grid, x);
          vtkIdType value1 = cd1->GetValue(cellId1);
          if (value1 != value)
          {
            return VTK_FAILURE;
          }
        }
        else
        {
          return VTK_FAILURE;
        }
      }
    }
  }

  return VTK_SUCCESS;
}
