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

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

=========================================================================*/
#include "vtkNumberToString.h"

// clang-format off
#include "vtk_doubleconversion.h"
#include VTK_DOUBLECONVERSION_HEADER(double-conversion.h)
// clang-format on

#include <array>
#include <sstream>

VTK_ABI_NAMESPACE_BEGIN

namespace
{
template <typename TagT>
inline ostream& ToString(ostream& stream, const TagT& tag)
{
  vtkNumberToString converter;
  stream << converter.Convert(tag.Value);
  return stream;
}
}

//------------------------------------------------------------------------------
ostream& operator<<(ostream& stream, const vtkNumberToString::TagDouble& tag)
{
  return ToString(stream, tag);
}

//------------------------------------------------------------------------------
ostream& operator<<(ostream& stream, const vtkNumberToString::TagFloat& tag)
{
  return ToString(stream, tag);
}

//------------------------------------------------------------------------------
void vtkNumberToString::SetLowExponent(int lowExponent)
{
  this->LowExponent = lowExponent;
}

//------------------------------------------------------------------------------
int vtkNumberToString::GetLowExponent()
{
  return this->LowExponent;
}

//------------------------------------------------------------------------------
void vtkNumberToString::SetHighExponent(int highExponent)
{
  this->HighExponent = highExponent;
}

//------------------------------------------------------------------------------
int vtkNumberToString::GetHighExponent()
{
  return this->HighExponent;
}

//------------------------------------------------------------------------------
std::string vtkNumberToString::Convert(double val)
{
  // Copied from double-conversion::EcmaScriptConverter
  // the last two arguments of the constructor have no effect with ToShortest
  constexpr int flags = double_conversion::DoubleToStringConverter::UNIQUE_ZERO |
    double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
  double_conversion::DoubleToStringConverter converter(
    flags, "Infinity", "NaN", 'e', this->LowExponent, this->HighExponent + 1, 6, 0);

  std::array<char, 256> buf;
  double_conversion::StringBuilder builder(buf.data(), static_cast<int>(buf.size()));
  builder.Reset();
  converter.ToShortest(val, &builder);
  return builder.Finalize();
}

std::string vtkNumberToString::Convert(float val)
{
  // Copied from double-conversion::EcmaScriptConverter
  // the last two arguments of the constructor have no effect with ToShortest
  constexpr int flags = double_conversion::DoubleToStringConverter::UNIQUE_ZERO |
    double_conversion::DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN;
  double_conversion::DoubleToStringConverter converter(
    flags, "Infinity", "NaN", 'e', this->LowExponent, this->HighExponent + 1, 6, 0);

  std::array<char, 256> buf;
  double_conversion::StringBuilder builder(buf.data(), static_cast<int>(buf.size()));
  builder.Reset();
  converter.ToShortestSingle(val, &builder);
  return builder.Finalize();
}

VTK_ABI_NAMESPACE_END
