#include "vtkStringToken.h"
#include "vtkStringManager.h"

#include <cstring>
#include <exception>
#include <thread>
#include <mutex>

static std::mutex s_managerLock;
vtkSmartPointer<vtkStringManager> vtkStringToken::Manager;

vtkStringToken::vtkStringToken(const char* data, std::size_t size)
{
  if (!data)
  {
    this->Id = vtkStringManager::Invalid;
  }
  else
  {
    if (size == std::string::npos)
    {
      size = std::strlen(data);
    }
    this->Id = vtkStringToken::GetManager()->Manage(std::string(data, size));
  }
}

vtkStringToken::vtkStringToken(const std::string& data)
{
  this->Id = vtkStringToken::GetManager()->Manage(data);
}

const std::string& vtkStringToken::Data() const
{
  return vtkStringToken::GetManager()->Value(this->Id);
}

bool vtkStringToken::operator==(const vtkStringToken& other) const
{
  return this->Id == other.Id;
}

bool vtkStringToken::operator!=(const vtkStringToken& other) const
{
  return this->Id != other.Id;
}

bool vtkStringToken::operator<(const vtkStringToken& other) const
{
  return this->Data() < other.Data();
}

bool vtkStringToken::operator>(const vtkStringToken& other) const
{
  return this->Data() > other.Data();
}

bool vtkStringToken::operator<=(const vtkStringToken& other) const
{
  return this->Data() <= other.Data();
}

bool vtkStringToken::operator>=(const vtkStringToken& other) const
{
  return this->Data() >= other.Data();
}

vtkStringManager* vtkStringToken::GetManager()
{
  if (vtkStringToken::Manager)
  {
    return vtkStringToken::Manager.GetPointer();
  }
  else
  {
    std::lock_guard<std::mutex> lock(s_managerLock);
    if (!vtkStringToken::Manager)
    {
      vtkStringToken::Manager = vtkSmartPointer<vtkStringManager>::New();
    }
  }
  return vtkStringToken::Manager.GetPointer();
}

bool operator==(const std::string& a, const vtkStringToken& b)
{
  return a == b.Data();
}
bool operator!=(const std::string& a, const vtkStringToken& b)
{
  return a != b.Data();
}
bool operator>(const std::string& a, const vtkStringToken& b)
{
  return a > b.Data();
}
bool operator<(const std::string& a, const vtkStringToken& b)
{
  return a < b.Data();
}
bool operator>=(const std::string& a, const vtkStringToken& b)
{
  return a >= b.Data();
}
bool operator<=(const std::string& a, const vtkStringToken& b)
{
  return a <= b.Data();
}

bool operator==(const vtkStringToken& a, const std::string& b)
{
  return a.Data() == b;
}
bool operator!=(const vtkStringToken& a, const std::string& b)
{
  return a.Data() != b;
}
bool operator>(const vtkStringToken& a, const std::string& b)
{
  return a.Data() > b;
}
bool operator<(const vtkStringToken& a, const std::string& b)
{
  return a.Data() < b;
}
bool operator>=(const vtkStringToken& a, const std::string& b)
{
  return a.Data() >= b;
}
bool operator<=(const vtkStringToken& a, const std::string& b)
{
  return a.Data() <= b;
}

bool operator==(const char* a, const vtkStringToken& b)
{
  return std::string(a) == b.Data();
}
bool operator!=(const char* a, const vtkStringToken& b)
{
  return std::string(a) != b.Data();
}
bool operator>(const char* a, const vtkStringToken& b)
{
  return std::string(a) > b.Data();
}
bool operator<(const char* a, const vtkStringToken& b)
{
  return std::string(a) < b.Data();
}
bool operator>=(const char* a, const vtkStringToken& b)
{
  return std::string(a) >= b.Data();
}
bool operator<=(const char* a, const vtkStringToken& b)
{
  return std::string(a) <= b.Data();
}

bool operator==(const vtkStringToken& a, const char* b)
{
  return a.Data() == std::string(b);
}
bool operator!=(const vtkStringToken& a, const char* b)
{
  return a.Data() != std::string(b);
}
bool operator>(const vtkStringToken& a, const char* b)
{
  return a.Data() > std::string(b);
}
bool operator<(const vtkStringToken& a, const char* b)
{
  return a.Data() < std::string(b);
}
bool operator>=(const vtkStringToken& a, const char* b)
{
  return a.Data() >= std::string(b);
}
bool operator<=(const vtkStringToken& a, const char* b)
{
  return a.Data() <= std::string(b);
}
