
#include <vtkm/cont/ColorTable.h>
#include <vtkm/rendering/CanvasRayTracer.h>

#include <vtkm/cont/testing/Testing.h>

namespace
{

static const vtkm::Id TABLE_IMAGE_WIDTH = 512;
static const vtkm::Id TABLE_IMAGE_HEIGHT = 1;

std::string FilenameFriendly(const std::string& name)
{
  std::string filename;
  for (auto&& ch : name)
  {
    if (((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z')) ||
        ((ch >= '0') && (ch <= '9')))
    {
      filename.push_back(ch);
    }
    else
    {
      filename.push_back('-');
    }
  }
  return filename;
}

void CreateColorTableImage(const std::string& name)
{
  std::cout << "Creating color table " << name << std::endl;

  vtkm::cont::ColorTable colorTable(name);

  // Create a CanvasRayTracer simply for the color buffer and the ability to
  // write out images.
  vtkm::rendering::CanvasRayTracer canvas(TABLE_IMAGE_WIDTH, TABLE_IMAGE_HEIGHT);
  using ColorBufferType = vtkm::rendering::CanvasRayTracer::ColorBufferType;
  ColorBufferType colorBuffer = canvas.GetColorBuffer();
  ColorBufferType::PortalControl colorPortal = colorBuffer.GetPortalControl();
  VTKM_TEST_ASSERT(colorPortal.GetNumberOfValues() ==
                     TABLE_IMAGE_WIDTH * TABLE_IMAGE_HEIGHT,
                   "Wrong size of color buffer.");

  vtkm::cont::ArrayHandle<vtkm::Vec<vtkm::UInt8, 4>> temp;
  colorTable.Sample(TABLE_IMAGE_WIDTH, temp);

  constexpr vtkm::Float32 conversionToFloatSpace = (1.0f / 255.0f);

  for (vtkm::Id j = 0; j < TABLE_IMAGE_HEIGHT; ++j)
  {
    auto tempPortal = temp.GetPortalConstControl();
    for (vtkm::Id i = 0; i < TABLE_IMAGE_WIDTH; ++i)
    {
      auto color = tempPortal.Get(i);
      vtkm::Vec<vtkm::Float32, 4> t(color[0] * conversionToFloatSpace,
                                    color[1] * conversionToFloatSpace,
                                    color[2] * conversionToFloatSpace,
                                    color[3] * conversionToFloatSpace);
      colorPortal.Set(j * TABLE_IMAGE_WIDTH + i, t);
    }
  }

  canvas.SaveAs(FilenameFriendly(name) + ".ppm");
}

void DoColorTables()
{
  vtkm::cont::ColorTable table;
  std::set<std::string> names = table.GetPresets();
  for (auto n = names.cbegin(); n != names.cend(); ++n)
  {
    CreateColorTableImage(*n);
  }
}

} // anonymous namespace

int ColorTables(int, char* [])
{
  return vtkm::cont::testing::Testing::Run(DoColorTables);
}
