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

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

=========================================================================*/
/*-------------------------------------------------------------------------
  Copyright 2008 Sandia Corporation.
  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
  the U.S. Government retains certain rights in this software.
-------------------------------------------------------------------------*/

#include "vtkVariant.h"

#include "vtkAbstractArray.h"
#include "vtkArrayIteratorIncludes.h"
#include "vtkDataArray.h"
#include "vtkMath.h"
#include "vtkObjectBase.h"
#include "vtkSetGet.h"
#include "vtkStdString.h"
#include "vtkStringArray.h"
#include "vtkType.h"
#include "vtkUnicodeString.h"
#include "vtkVariantArray.h"

#include "vtksys/SystemTools.hxx"
#include <locale> // C++ locale
#include <sstream>

//----------------------------------------------------------------------------

// Implementation of vtkVariant's
// fast-but-potentially-counterintuitive < operation
bool vtkVariantStrictWeakOrder::operator()(const vtkVariant& s1, const vtkVariant& s2) const
{
  // First sort on type if they are different
  if (s1.Type != s2.Type)
  {
    return s1.Type < s2.Type;
  }

  // Next check for nulls
  if (!(s1.Valid && s2.Valid))
  {
    if (!(s1.Valid || s2.Valid))
    {
      return false; // nulls are equal to one another
    }
    else if (!s1.Valid)
    {
      return true; // null is less than any valid value
    }
    else
    {
      return false;
    }
  }

  switch (s1.Type)
  {
    case VTK_STRING:
      return (*(s1.Data.String) < *(s2.Data.String));

    case VTK_UNICODE_STRING:
      return (*(s1.Data.UnicodeString) < *(s2.Data.UnicodeString));

    case VTK_OBJECT:
      return (s1.Data.VTKObject < s2.Data.VTKObject);

    case VTK_CHAR:
      return (s1.Data.Char < s2.Data.Char);

    case VTK_SIGNED_CHAR:
      return (s1.Data.SignedChar < s2.Data.SignedChar);

    case VTK_UNSIGNED_CHAR:
      return (s1.Data.UnsignedChar < s2.Data.UnsignedChar);

    case VTK_SHORT:
      return (s1.Data.Short < s2.Data.Short);

    case VTK_UNSIGNED_SHORT:
      return (s1.Data.UnsignedShort < s2.Data.UnsignedShort);

    case VTK_INT:
      return (s1.Data.Int < s2.Data.Int);

    case VTK_UNSIGNED_INT:
      return (s1.Data.UnsignedInt < s2.Data.UnsignedInt);

    case VTK_LONG:
      return (s1.Data.Long < s2.Data.Long);

    case VTK_UNSIGNED_LONG:
      return (s1.Data.UnsignedLong < s2.Data.UnsignedLong);

    case VTK_LONG_LONG:
      return (s1.Data.LongLong < s2.Data.LongLong);

    case VTK_UNSIGNED_LONG_LONG:
      return (s1.Data.UnsignedLongLong < s2.Data.UnsignedLongLong);

    case VTK_FLOAT:
      return (s1.Data.Float < s2.Data.Float);

    case VTK_DOUBLE:
      return (s1.Data.Double < s2.Data.Double);

    default:
      cerr << "ERROR: Unhandled type " << s1.Type << " in vtkVariantStrictWeakOrder\n";
      return false;
  }
}

// ----------------------------------------------------------------------

bool
vtkVariantStrictEquality::operator()(const vtkVariant &s1, const vtkVariant &s2) const
{
  // First sort on type if they are different
  if (s1.Type != s2.Type)
  {
    cerr << "Types differ: " << s1.Type << " and " << s2.Type << "\n";
    return false;
  }

  // Next check for nulls
  if (!(s1.Valid && s2.Valid))
  {
    cerr << "Validity may differ: " << s1.Valid << " and " << s2.Valid << "\n";
    return (s1.Valid == s2.Valid);
  }

  // At this point we know that both variants contain a valid value.
  switch (s1.Type)
  {
    case VTK_STRING:
    {
    if (*(s1.Data.String) != *(s2.Data.String))
    {
      cerr << "Strings differ: '"
           << *(s1.Data.String) << "' and '"
           << *(s2.Data.String) << "'\n";
    }
      return (*(s1.Data.String) == *(s2.Data.String));
    };

    case VTK_UNICODE_STRING:
      return (*(s1.Data.UnicodeString) == *(s2.Data.UnicodeString));

    case VTK_OBJECT:
      return (s1.Data.VTKObject == s2.Data.VTKObject);

    case VTK_CHAR:
      return (s1.Data.Char == s2.Data.Char);

    case VTK_SIGNED_CHAR:
      return (s1.Data.SignedChar == s2.Data.SignedChar);

    case VTK_UNSIGNED_CHAR:
      return (s1.Data.UnsignedChar == s2.Data.UnsignedChar);

    case VTK_SHORT:
      return (s1.Data.Short == s2.Data.Short);

    case VTK_UNSIGNED_SHORT:
      return (s1.Data.UnsignedShort == s2.Data.UnsignedShort);

    case VTK_INT:
      return (s1.Data.Int == s2.Data.Int);

    case VTK_UNSIGNED_INT:
      return (s1.Data.UnsignedInt == s2.Data.UnsignedInt);

    case VTK_LONG:
      return (s1.Data.Long == s2.Data.Long);

    case VTK_UNSIGNED_LONG:
      return (s1.Data.UnsignedLong == s2.Data.UnsignedLong);

    case VTK_LONG_LONG:
      return (s1.Data.LongLong == s2.Data.LongLong);

    case VTK_UNSIGNED_LONG_LONG:
      return (s1.Data.UnsignedLongLong == s2.Data.UnsignedLongLong);

    case VTK_FLOAT:
      return (s1.Data.Float == s2.Data.Float);

    case VTK_DOUBLE:
      return (s1.Data.Double == s2.Data.Double);

    default:
      cerr << "ERROR: Unhandled type " << s1.Type << " in vtkVariantStrictEquality\n";
      return false;
  }
}

// ----------------------------------------------------------------------

bool
vtkVariantLessThan::operator()(const vtkVariant &v1, const vtkVariant &v2) const
{
  return v1.operator<(v2);
}

// ----------------------------------------------------------------------

bool
vtkVariantEqual::operator()(const vtkVariant &v1, const vtkVariant &v2) const
{
  return v1.operator==(v2);
}

//----------------------------------------------------------------------------
vtkVariant::vtkVariant()
{
  this->Valid = 0;
  this->Type = 0;
}

vtkVariant::vtkVariant(const vtkVariant & other)
{
  this->Valid = other.Valid;
  this->Type = other.Type;
  this->Data = other.Data;
  if (this->Valid)
  {
    switch (other.Type)
    {
      case VTK_STRING:
        this->Data.String = new vtkStdString(*other.Data.String);
        break;
      case VTK_UNICODE_STRING:
        this->Data.UnicodeString = new vtkUnicodeString(*other.Data.UnicodeString);
        break;
      case VTK_OBJECT:
        this->Data.VTKObject->Register(nullptr);
        break;
    }
  }
}

vtkVariant::vtkVariant(const vtkVariant &s2, unsigned int type)
{
  bool valid = false;

  if (s2.Valid)
  {
    switch (type)
    {
      case VTK_STRING:
        this->Data.String = new vtkStdString(s2.ToString());
        valid = true;
        break;

      case VTK_UNICODE_STRING:
        this->Data.UnicodeString =
          new vtkUnicodeString(s2.ToUnicodeString());
        valid = true;
        break;

      case VTK_OBJECT:
        this->Data.VTKObject = s2.ToVTKObject();
        if (this->Data.VTKObject)
        {
          this->Data.VTKObject->Register(nullptr);
          valid = true;
        }
        break;

      case VTK_CHAR:
        this->Data.Char = s2.ToChar(&valid);
        break;

      case VTK_SIGNED_CHAR:
        this->Data.SignedChar = s2.ToSignedChar(&valid);
        break;

      case VTK_UNSIGNED_CHAR:
        this->Data.UnsignedChar = s2.ToUnsignedChar(&valid);
        break;

      case VTK_SHORT:
        this->Data.Short = s2.ToShort(&valid);
        break;

      case VTK_UNSIGNED_SHORT:
        this->Data.UnsignedShort = s2.ToUnsignedShort(&valid);
        break;

      case VTK_INT:
        this->Data.Int = s2.ToInt(&valid);
        break;

      case VTK_UNSIGNED_INT:
        this->Data.UnsignedInt = s2.ToUnsignedInt(&valid);
        break;

      case VTK_LONG:
        this->Data.Long = s2.ToLong(&valid);
        break;

      case VTK_UNSIGNED_LONG:
        this->Data.UnsignedLong = s2.ToUnsignedLong(&valid);
        break;

      case VTK_LONG_LONG:
        this->Data.LongLong = s2.ToLongLong(&valid);
        break;

      case VTK_UNSIGNED_LONG_LONG:
        this->Data.UnsignedLongLong = s2.ToUnsignedLongLong(&valid);
        break;

      case VTK_FLOAT:
        this->Data.Float = s2.ToFloat(&valid);
        break;

      case VTK_DOUBLE:
        this->Data.Double = s2.ToDouble(&valid);
        break;
    }
  }

  this->Type = (valid ? type : 0);
  this->Valid = valid;
}

vtkVariant & vtkVariant::operator= (const vtkVariant & other)
{
  // Short circuit if assigning to self:
  if (this == &other)
  {
    return *this;
  }

  // First delete current variant item.
  if (this->Valid)
  {
    switch (this->Type)
    {
      case VTK_STRING:
        delete this->Data.String;
        break;
      case VTK_UNICODE_STRING:
        delete this->Data.UnicodeString;
        break;
      case VTK_OBJECT:
        this->Data.VTKObject->Delete();
        break;
    }
  }

  // Then set the appropriate value.
  this->Valid = other.Valid;
  this->Type = other.Type;
  this->Data = other.Data;
  if (this->Valid)
  {
    switch (other.Type)
    {
      case VTK_STRING:
        this->Data.String = new vtkStdString(*other.Data.String);
        break;
      case VTK_UNICODE_STRING:
        this->Data.UnicodeString = new vtkUnicodeString(*other.Data.UnicodeString);
        break;
      case VTK_OBJECT:
        this->Data.VTKObject->Register(nullptr);
        break;
    }
  }
  return *this;
}

vtkVariant::~vtkVariant()
{
  if (this->Valid)
  {
    switch (this->Type)
    {
      case VTK_STRING:
        delete this->Data.String;
        break;
      case VTK_UNICODE_STRING:
        delete this->Data.UnicodeString;
        break;
      case VTK_OBJECT:
        this->Data.VTKObject->Delete();
        break;
    }
  }
}

vtkVariant::vtkVariant(bool value)
{
  this->Data.Char = value;
  this->Valid = 1;
  this->Type = VTK_CHAR;
}

vtkVariant::vtkVariant(char value)
{
  this->Data.Char = value;
  this->Valid = 1;
  this->Type = VTK_CHAR;
}

vtkVariant::vtkVariant(unsigned char value)
{
  this->Data.UnsignedChar = value;
  this->Valid = 1;
  this->Type = VTK_UNSIGNED_CHAR;
}

vtkVariant::vtkVariant(signed char value)
{
  this->Data.SignedChar = value;
  this->Valid = 1;
  this->Type = VTK_SIGNED_CHAR;
}

vtkVariant::vtkVariant(short value)
{
  this->Data.Short = value;
  this->Valid = 1;
  this->Type = VTK_SHORT;
}

vtkVariant::vtkVariant(unsigned short value)
{
  this->Data.UnsignedShort = value;
  this->Valid = 1;
  this->Type = VTK_UNSIGNED_SHORT;
}

vtkVariant::vtkVariant(int value)
{
  this->Data.Int = value;
  this->Valid = 1;
  this->Type = VTK_INT;
}

vtkVariant::vtkVariant(unsigned int value)
{
  this->Data.UnsignedInt = value;
  this->Valid = 1;
  this->Type = VTK_UNSIGNED_INT;
}

vtkVariant::vtkVariant(long value)
{
  this->Data.Long = value;
  this->Valid = 1;
  this->Type = VTK_LONG;
}

vtkVariant::vtkVariant(unsigned long value)
{
  this->Data.UnsignedLong = value;
  this->Valid = 1;
  this->Type = VTK_UNSIGNED_LONG;
}

vtkVariant::vtkVariant(long long value)
{
  this->Data.LongLong = value;
  this->Valid = 1;
  this->Type = VTK_LONG_LONG;
}

vtkVariant::vtkVariant(unsigned long long value)
{
  this->Data.UnsignedLongLong = value;
  this->Valid = 1;
  this->Type = VTK_UNSIGNED_LONG_LONG;
}

vtkVariant::vtkVariant(float value)
{
  this->Data.Float = value;
  this->Valid = 1;
  this->Type = VTK_FLOAT;
}

vtkVariant::vtkVariant(double value)
{
  this->Data.Double = value;
  this->Valid = 1;
  this->Type = VTK_DOUBLE;
}

vtkVariant::vtkVariant(const char* value)
{
  this->Valid = 0;
  this->Type = 0;
  if (value)
  {
    this->Data.String = new vtkStdString(value);
    this->Valid = 1;
    this->Type = VTK_STRING;
  }
}

vtkVariant::vtkVariant(vtkStdString value)
{
  this->Data.String = new vtkStdString(value);
  this->Valid = 1;
  this->Type = VTK_STRING;
}

vtkVariant::vtkVariant(const vtkUnicodeString& value)
{
  this->Data.UnicodeString = new vtkUnicodeString(value);
  this->Valid = 1;
  this->Type = VTK_UNICODE_STRING;
}

vtkVariant::vtkVariant(vtkObjectBase* value)
{
  this->Valid = 0;
  this->Type = 0;
  if (value)
  {
    value->Register(nullptr);
    this->Data.VTKObject = value;
    this->Valid = 1;
    this->Type = VTK_OBJECT;
  }
}

bool vtkVariant::IsValid() const
{
  return this->Valid != 0;
}

bool vtkVariant::IsString() const
{
  return this->Type == VTK_STRING;
}

bool vtkVariant::IsUnicodeString() const
{
  return this->Type == VTK_UNICODE_STRING;
}

bool vtkVariant::IsNumeric() const
{
  return this->IsFloat()
    || this->IsDouble()
    || this->IsChar()
    || this->IsUnsignedChar()
    || this->IsSignedChar()
    || this->IsShort()
    || this->IsUnsignedShort()
    || this->IsInt()
    || this->IsUnsignedInt()
    || this->IsLong()
    || this->IsUnsignedLong()
    || this->IsLongLong()
    || this->IsUnsignedLongLong();
}

bool vtkVariant::IsFloat() const
{
  return this->Type == VTK_FLOAT;
}

bool vtkVariant::IsDouble() const
{
  return this->Type == VTK_DOUBLE;
}

bool vtkVariant::IsChar() const
{
  return this->Type == VTK_CHAR;
}

bool vtkVariant::IsUnsignedChar() const
{
  return this->Type == VTK_UNSIGNED_CHAR;
}

bool vtkVariant::IsSignedChar() const
{
  return this->Type == VTK_SIGNED_CHAR;
}

bool vtkVariant::IsShort() const
{
  return this->Type == VTK_SHORT;
}

bool vtkVariant::IsUnsignedShort() const
{
  return this->Type == VTK_UNSIGNED_SHORT;
}

bool vtkVariant::IsInt() const
{
  return this->Type == VTK_INT;
}

bool vtkVariant::IsUnsignedInt() const
{
  return this->Type == VTK_UNSIGNED_INT;
}

bool vtkVariant::IsLong() const
{
  return this->Type == VTK_LONG;
}

bool vtkVariant::IsUnsignedLong() const
{
  return this->Type == VTK_UNSIGNED_LONG;
}

bool vtkVariant::Is__Int64() const
{
  return false;
}

bool vtkVariant::IsUnsigned__Int64() const
{
  return false;
}

bool vtkVariant::IsLongLong() const
{
  return this->Type == VTK_LONG_LONG;
}

bool vtkVariant::IsUnsignedLongLong() const
{
  return this->Type == VTK_UNSIGNED_LONG_LONG;
}

bool vtkVariant::IsVTKObject() const
{
  return this->Type == VTK_OBJECT;
}

bool vtkVariant::IsArray() const
{
  return this->Type == VTK_OBJECT
    && this->Valid
    && this->Data.VTKObject->IsA("vtkAbstractArray");
}

unsigned int vtkVariant::GetType() const
{
  return this->Type;
}

const char* vtkVariant::GetTypeAsString() const
{
  if (this->Type == VTK_OBJECT && this->Valid)
  {
    return this->Data.VTKObject->GetClassName();
  }
  return vtkImageScalarTypeNameMacro(this->Type);
}

template <typename iterT>
vtkStdString vtkVariantArrayToString(iterT* it)
{
  vtkIdType maxInd = it->GetNumberOfValues();
  std::ostringstream ostr;
  for (vtkIdType i = 0; i < maxInd; i++)
  {
    if (i > 0)
    {
      ostr << " ";
    }
    ostr << it->GetValue(i);
  }
  return ostr.str();
}

vtkStdString vtkVariant::ToString() const
{
  if (!this->IsValid())
  {
    return vtkStdString();
  }
  if (this->IsString())
  {
    return vtkStdString(*(this->Data.String));
  }
  if (this->IsUnicodeString())
  {
    return vtkUnicodeString(*(this->Data.UnicodeString)).utf8_str();
  }
  if (this->IsFloat())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.Float;
    return vtkStdString(ostr.str());
  }
  if (this->IsDouble())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.Double;
    return vtkStdString(ostr.str());
  }
  if (this->IsChar())
  {
    std::ostringstream ostr;
    ostr << this->Data.Char;
    return vtkStdString(ostr.str());
  }
  if (this->IsUnsignedChar())
  {
    std::ostringstream ostr;
    ostr << static_cast<unsigned int>(this->Data.UnsignedChar);
    return vtkStdString(ostr.str());
  }
  if (this->IsSignedChar())
  {
    std::ostringstream ostr;
    ostr << this->Data.SignedChar;
    return vtkStdString(ostr.str());
  }
  if (this->IsShort())
  {
    std::ostringstream ostr;
    ostr << this->Data.Short;
    return vtkStdString(ostr.str());
  }
  if (this->IsUnsignedShort())
  {
    std::ostringstream ostr;
    ostr << this->Data.UnsignedShort;
    return vtkStdString(ostr.str());
  }
  if (this->IsInt())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.Int;
    return vtkStdString(ostr.str());
  }
  if (this->IsUnsignedInt())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.UnsignedInt;
    return vtkStdString(ostr.str());
  }
  if (this->IsLong())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.Long;
    return vtkStdString(ostr.str());
  }
  if (this->IsUnsignedLong())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.UnsignedLong;
    return vtkStdString(ostr.str());
  }
  if (this->IsLongLong())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.LongLong;
    return vtkStdString(ostr.str());
  }
  if (this->IsUnsignedLongLong())
  {
    std::ostringstream ostr;
    ostr.imbue(std::locale::classic());
    ostr << this->Data.UnsignedLongLong;
    return vtkStdString(ostr.str());
  }
  if (this->IsArray())
  {
    vtkAbstractArray* arr = vtkAbstractArray::SafeDownCast(this->Data.VTKObject);
    vtkArrayIterator* iter = arr->NewIterator();
    vtkStdString str;
    switch(arr->GetDataType())
    {
      vtkArrayIteratorTemplateMacro(
        str = vtkVariantArrayToString(static_cast<VTK_TT*>(iter)));
    }
    iter->Delete();
    return str;
  }
  vtkGenericWarningMacro(
    << "Cannot convert unknown type (" << this->GetTypeAsString() << ") to a string.");
  return vtkStdString();
}

vtkUnicodeString vtkVariant::ToUnicodeString() const
{
  if (!this->IsValid())
  {
    return vtkUnicodeString();
  }
  if (this->IsString())
  {
    return vtkUnicodeString::from_utf8(*this->Data.String);
  }
  if (this->IsUnicodeString())
  {
    return *this->Data.UnicodeString;
  }

  return vtkUnicodeString::from_utf8(this->ToString());
}

vtkObjectBase* vtkVariant::ToVTKObject() const
{
  if (this->IsVTKObject())
  {
    return this->Data.VTKObject;
  }
  return nullptr;
}

vtkAbstractArray* vtkVariant::ToArray() const
{
  if (this->IsArray())
  {
    return vtkAbstractArray::SafeDownCast(this->Data.VTKObject);
  }
  return nullptr;
}

// Used internally by vtkVariantStringToNumeric to find non-finite numbers.
// Most numerics do not support non-finite numbers, hence the default simply
// fails.  Overload for doubles and floats detect non-finite numbers they
// support
template <typename T>
T vtkVariantStringToNonFiniteNumeric(vtkStdString vtkNotUsed(str), bool *valid)
{
  if (valid) *valid = 0;
  return 0;
}

template<> double vtkVariantStringToNonFiniteNumeric<double>(vtkStdString str,
                                                             bool *valid)
{
  if (vtksys::SystemTools::Strucmp(str.c_str(), "nan") == 0)
  {
    if (valid) *valid = true;
    return vtkMath::Nan();
  }
  if (   (vtksys::SystemTools::Strucmp(str.c_str(), "infinity") == 0)
      || (vtksys::SystemTools::Strucmp(str.c_str(), "inf") == 0) )
  {
    if (valid) *valid = true;
    return vtkMath::Inf();
  }
  if (   (vtksys::SystemTools::Strucmp(str.c_str(), "-infinity") == 0)
      || (vtksys::SystemTools::Strucmp(str.c_str(), "-inf") == 0) )
  {
    if (valid) *valid = true;
    return vtkMath::NegInf();
  }
  if (valid) *valid = false;
  return vtkMath::Nan();
}

template<> float vtkVariantStringToNonFiniteNumeric<float>(vtkStdString str,
                                                           bool *valid)
{
  return static_cast<float>(
                        vtkVariantStringToNonFiniteNumeric<double>(str, valid));
}

template <typename T>
T vtkVariantStringToNumeric(vtkStdString str, bool* valid, T* vtkNotUsed(ignored) = nullptr)
{
  std::istringstream vstr(str);
  T data = 0;
  vstr >> data;
  if(!vstr.eof())
  {
    // take in white space so that it can reach eof.
    vstr >> std::ws;
  }
  bool v = ( !vstr.fail() && vstr.eof() );
  if (valid) *valid = v;
  if (!v)
  {
    data = vtkVariantStringToNonFiniteNumeric<T>(str, valid);
  }
  return data;
}

//----------------------------------------------------------------------------
// Definition of ToNumeric

#include "vtkVariantToNumeric.cxx"

//----------------------------------------------------------------------------
// Explicitly instantiate the ToNumeric member template to make sure
// the symbols are exported from this object file.
// This explicit instantiation exists to resolve VTK issue #5791.

#if !defined(VTK_VARIANT_NO_INSTANTIATE)

#define vtkVariantToNumericInstantiateMacro(x)                          \
  template x vtkVariant::ToNumeric< x >(bool*, x*) const

vtkVariantToNumericInstantiateMacro(char);
vtkVariantToNumericInstantiateMacro(float);
vtkVariantToNumericInstantiateMacro(double);
vtkVariantToNumericInstantiateMacro(unsigned char);
vtkVariantToNumericInstantiateMacro(signed char);
vtkVariantToNumericInstantiateMacro(short);
vtkVariantToNumericInstantiateMacro(unsigned short);
vtkVariantToNumericInstantiateMacro(int);
vtkVariantToNumericInstantiateMacro(unsigned int);
vtkVariantToNumericInstantiateMacro(long);
vtkVariantToNumericInstantiateMacro(unsigned long);
vtkVariantToNumericInstantiateMacro(long long);
vtkVariantToNumericInstantiateMacro(unsigned long long);

#endif

//----------------------------------------------------------------------------
// Callers causing implicit instantiations of ToNumeric

float vtkVariant::ToFloat(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<float *>(nullptr));
}

double vtkVariant::ToDouble(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<double *>(nullptr));
}

char vtkVariant::ToChar(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<char *>(nullptr));
}

unsigned char vtkVariant::ToUnsignedChar(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<unsigned char *>(nullptr));
}

signed char vtkVariant::ToSignedChar(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<signed char *>(nullptr));
}

short vtkVariant::ToShort(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<short *>(nullptr));
}

unsigned short vtkVariant::ToUnsignedShort(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<unsigned short *>(nullptr));
}

int vtkVariant::ToInt(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<int *>(nullptr));
}

unsigned int vtkVariant::ToUnsignedInt(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<unsigned int *>(nullptr));
}

long vtkVariant::ToLong(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<long *>(nullptr));
}

unsigned long vtkVariant::ToUnsignedLong(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<unsigned long *>(nullptr));
}

long long vtkVariant::ToLongLong(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<long long *>(nullptr));
}

unsigned long long vtkVariant::ToUnsignedLongLong(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<unsigned long long *>(nullptr));
}

vtkTypeInt64 vtkVariant::ToTypeInt64(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<vtkTypeInt64 *>(nullptr));
}

vtkTypeUInt64 vtkVariant::ToTypeUInt64(bool *valid) const
{
  return this->ToNumeric(valid, static_cast<vtkTypeUInt64 *>(nullptr));
}

bool vtkVariant::IsEqual(const vtkVariant& other) const
{
  return this->operator==(other);
}

ostream& operator << ( ostream& os, const vtkVariant& val )
{
  if ( ! val.Valid )
  {
    os << "(invalid)";
    return os;
  }
  switch ( val.Type )
  {
  case VTK_STRING:
    if ( val.Data.String )
    {
      os << "\"" << val.Data.String->c_str() << "\"";
    }
    else
    {
      os << "\"\"";
    }
    break;
  case VTK_UNICODE_STRING:
    if ( val.Data.UnicodeString )
    {
      os << "\"" << val.Data.UnicodeString->utf8_str() << "\"";
    }
    else
    {
      os << "\"\"";
    }
    break;
  case VTK_FLOAT:
    os << val.Data.Float;
    break;
  case VTK_DOUBLE:
    os << val.Data.Double;
    break;
  case VTK_CHAR:
    os << val.Data.Char;
    break;
  case VTK_UNSIGNED_CHAR:
    os << val.Data.UnsignedChar;
    break;
  case VTK_SIGNED_CHAR:
    os << val.Data.SignedChar;
    break;
  case VTK_SHORT:
    os << val.Data.Short;
    break;
  case VTK_UNSIGNED_SHORT:
    os << val.Data.UnsignedShort;
    break;
  case VTK_INT:
    os << val.Data.Int;
    break;
  case VTK_UNSIGNED_INT:
    os << val.Data.UnsignedInt;
    break;
  case VTK_LONG:
    os << val.Data.Long;
    break;
  case VTK_UNSIGNED_LONG:
    os << val.Data.UnsignedLong;
    break;
  case VTK_LONG_LONG:
    os << val.Data.LongLong;
    break;
  case VTK_UNSIGNED_LONG_LONG:
    os << val.Data.UnsignedLongLong;
    break;
  case VTK_OBJECT:
    if ( val.Data.VTKObject )
    {
      os << "(" << val.Data.VTKObject->GetClassName() << ")" << hex << val.Data.VTKObject << dec;
    }
    else
    {
      os << "(vtkObjectBase)0x0";
    }
    break;
  }
  return os;
}
