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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

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

#ifndef US_ANY_H
#define US_ANY_H

#include <algorithm>
#include <typeinfo>
#include <sstream>
#include <vector>
#include <list>
#include <set>
#include <map>

#include <usGlobalConfig.h>
#include <MitkCppMicroServicesExports.h>

namespace us {

class Any;

MITKCPPMICROSERVICES_EXPORT std::string any_value_to_string(const Any& any);

MITKCPPMICROSERVICES_EXPORT std::string any_value_to_json(const Any& val);
MITKCPPMICROSERVICES_EXPORT std::string any_value_to_json(const std::string& val);
MITKCPPMICROSERVICES_EXPORT std::string any_value_to_json(bool val);

template<class T>
std::string any_value_to_string(const T& val)
{
  std::stringstream ss;
  ss << val;
  return ss.str();
}

template<class T>
std::string any_value_to_json(const T& val)
{
  return any_value_to_string(val);
}

/**
 * \internal
 */
template<typename Iterator>
std::string container_to_string(Iterator i1, Iterator i2)
{
  std::stringstream ss;
  ss << "[";
  const Iterator begin = i1;
  for ( ; i1 != i2; ++i1)
  {
    if (i1 == begin) ss << any_value_to_string(*i1);
    else ss << "," << any_value_to_string(*i1);
  }
  ss << "]";
  return ss.str();
}

/**
 * \internal
 */
template<typename Iterator>
std::string container_to_json(Iterator i1, Iterator i2)
{
  std::stringstream ss;
  ss << "[";
  const Iterator begin = i1;
  for ( ; i1 != i2; ++i1)
  {
    if (i1 == begin) ss << any_value_to_json(*i1);
    else ss << "," << any_value_to_json(*i1);
  }
  ss << "]";
  return ss.str();
}

template<class E>
std::string any_value_to_string(const std::vector<E>& vec)
{
  return container_to_string(vec.begin(), vec.end());
}

template<class E>
std::string any_value_to_json(const std::vector<E>& vec)
{
  return container_to_json(vec.begin(), vec.end());
}

template<class E>
std::string any_value_to_string(const std::list<E>& l)
{
  return container_to_string(l.begin(), l.end());
}

template<class E>
std::string any_value_to_json(const std::list<E>& l)
{
  return container_to_json(l.begin(), l.end());
}

template<class E>
std::string any_value_to_string(const std::set<E>& s)
{
  return container_to_string(s.begin(), s.end());
}

template<class E>
std::string any_value_to_json(const std::set<E>& s)
{
  return container_to_json(s.begin(), s.end());
}

template<class M>
std::string any_value_to_string(const std::map<M, Any>& m);

template<class K, class V>
std::string any_value_to_string(const std::map<K, V>& m);

template<class M>
std::string any_value_to_json(const std::map<M, Any>& m);

template<class K, class V>
std::string any_value_to_json(const std::map<K, V>& m);


/**
 * \ingroup MicroServicesUtils
 *
 * \brief An Any class represents a general type and is capable of storing any type, supporting type-safe extraction
 * of the internally stored data.
 *
 * Code taken from the Boost 1.46.1 library. Original copyright by Kevlin Henney. Modified for CppMicroServices.
 */
class Any
{
public:

  /**
   * \brief Creates an empty any type.
   */
  Any(): _content(nullptr)
  { }

  /**
   * \brief Creates an Any which stores the init parameter inside.
   *
   * \param value The content of the Any
   *
   * Example:
   * \code
   * Any a(13);
   * Any a(string("12345"));
   * \endcode
   */
  template <typename ValueType>
  Any(const ValueType& value)
    : _content(new Holder<ValueType>(value))
  { }

  /**
   * \brief Copy constructor, works with empty Anys and initialized Any values.
   *
   * \param other The Any to copy
   */
  Any(const Any& other)
    : _content(other._content ? other._content->Clone() : nullptr)
  { }

  ~Any()
  {
    delete _content;
  }

  /**
   * \brief Swaps the content of the two Anys.
   *
   * \param rhs The Any to swap this Any with.
   */
  Any& Swap(Any& rhs)
  {
    std::swap(_content, rhs._content);
    return *this;
  }

  /**
   * \brief Assignment operator for all types != Any.
   *
   * \param rhs The value which should be assigned to this Any.
   *
   * Example:
   * \code
   * Any a = 13;
   * Any a = string("12345");
   * \endcode
   */
  template <typename ValueType>
  Any& operator = (const ValueType& rhs)
  {
    Any(rhs).Swap(*this);
    return *this;
  }

  /**
   * \brief Assignment operator for Any.
   *
   * \param rhs The Any which should be assigned to this Any.
   */
  Any& operator = (const Any& rhs)
  {
    Any(rhs).Swap(*this);
    return *this;
  }

  /**
   * \brief Returns true if the Any is empty.
   */
  bool Empty() const
  {
    return !_content;
  }

  /**
   * \brief Returns a string representation for the content.
   * If this Any is empty, returns an empty string.
   *
   * Custom types should either provide a <code>std::ostream& operator<<(std::ostream& os, const CustomType& ct)</code>
   * function or specialize the any_value_to_string template function for meaningful output.
   */
  std::string ToString() const
  {
    return Empty() ? std::string() : _content->ToString();
  }

  /**
   * \brief Returns a JSON representation for the content.
   *
   * Custom types should specialize the any_value_to_json template function for meaningful output.
   */
  std::string ToJSON() const
  {
    return Empty() ? "null" : _content->ToJSON();
  }

  /**
   * \brief Returns the type information of the stored content.
   * If the Any is empty typeid(void) is returned.
   * It is suggested to always query an Any for its type info before trying to extract
   * data via an any_cast/ref_any_cast.
   */
  const std::type_info& Type() const
  {
    return _content ? _content->Type() : typeid(void);
  }

private:

  class Placeholder
  {
  public:
    virtual ~Placeholder()
    { }

    virtual std::string ToString() const = 0;
    virtual std::string ToJSON() const = 0;

    virtual const std::type_info& Type() const = 0;
    virtual Placeholder* Clone() const = 0;
  };

  template <typename ValueType>
  class Holder: public Placeholder
  {
  public:
    Holder(const ValueType& value)
      : _held(value)
    { }

    std::string ToString() const override
    {
      return any_value_to_string(_held);
    }

    std::string ToJSON() const override
    {
      return any_value_to_json(_held);
    }

    const std::type_info& Type() const override
    {
      return typeid(ValueType);
    }

    Placeholder* Clone() const override
    {
      return new Holder(_held);
    }

    ValueType _held;

  private: // intentionally left unimplemented
    Holder& operator=(const Holder &);
  };

private:
    template <typename ValueType>
    friend ValueType* any_cast(Any*);

    template <typename ValueType>
    friend ValueType* unsafe_any_cast(Any*);

    Placeholder* _content;
};

/**
 * \ingroup MicroServicesUtils
 *
 * \brief Exception thrown when an any_cast fails due to a type mismatch.
 *
 * \sa Any
 * \sa any_cast
 */
class BadAnyCastException : public std::bad_cast
{
public:

  BadAnyCastException(const std::string& msg = "")
    : std::bad_cast(), _msg(msg)
  {}

  ~BadAnyCastException() throw() override {}

  const char * what() const throw() override
  {
    if (_msg.empty())
      return "us::BadAnyCastException: "
             "failed conversion using us::any_cast";
    else
      return _msg.c_str();
  }

private:

  std::string _msg;
};

/**
 * \brief any_cast operator used to extract the ValueType from an Any*. Will return a pointer
 * to the stored value.
 *
 * Example Usage:
 * \code
 * MyType* pTmp = any_cast<MyType*>(pAny)
 * \endcode
 * Will return nullptr if the cast fails, i.e. types don't match.
 */
template <typename ValueType>
ValueType* any_cast(Any* operand)
{
  return operand && operand->Type() == typeid(ValueType)
      ? &static_cast<Any::Holder<ValueType>*>(operand->_content)->_held
      : nullptr;
}

/**
 * \brief any_cast operator used to extract a const ValueType pointer from an const Any*. Will return a const pointer
 * to the stored value.
 *
 * Example Usage:
 * \code
 * const MyType* pTmp = any_cast<MyType*>(pAny)
 * \endcode
 * Will return nullptr if the cast fails, i.e. types don't match.
 */
template <typename ValueType>
const ValueType* any_cast(const Any* operand)
{
  return any_cast<ValueType>(const_cast<Any*>(operand));
}

/**
 * \brief any_cast operator used to extract a copy of the ValueType from an const Any&.
 *
 * Example Usage:
 * \code
 * MyType tmp = any_cast<MyType>(anAny)
 * \endcode
 * Will throw a BadCastException if the cast fails.
 * Dont use an any_cast in combination with references, i.e. MyType& tmp = ... or const MyType& = ...
 * Some compilers will accept this code although a copy is returned. Use the ref_any_cast in
 * these cases.
 */
template <typename ValueType>
ValueType any_cast(const Any& operand)
{
  ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
  if (!result) throw BadAnyCastException("Failed to convert between const Any types");
  return *result;
}

/**
 * \brief any_cast operator used to extract a copy of the ValueType from an Any&.
 *
 * Example Usage:
 * \code
 * MyType tmp = any_cast<MyType>(anAny)
 * \endcode
 * Will throw a BadCastException if the cast fails.
 * Dont use an any_cast in combination with references, i.e. MyType& tmp = ... or const MyType& tmp = ...
 * Some compilers will accept this code although a copy is returned. Use the ref_any_cast in
 * these cases.
 */
template <typename ValueType>
ValueType any_cast(Any& operand)
{
  ValueType* result = any_cast<ValueType>(&operand);
  if (!result) throw BadAnyCastException("Failed to convert between Any types");
  return *result;
}

/**
 * \brief ref_any_cast operator used to return a const reference to the internal data.
 *
 * Example Usage:
 * \code
 * const MyType& tmp = ref_any_cast<MyType>(anAny);
 * \endcode
 */
template <typename ValueType>
const ValueType& ref_any_cast(const Any & operand)
{
  ValueType* result = any_cast<ValueType>(const_cast<Any*>(&operand));
  if (!result) throw BadAnyCastException("RefAnyCast: Failed to convert between const Any types");
  return *result;
}

/**
 * \brief ref_any_cast operator used to return a reference to the internal data.
 *
 * Example Usage:
 * \code
 * MyType& tmp = ref_any_cast<MyType>(anAny);
 * \endcode
 */
template <typename ValueType>
ValueType& ref_any_cast(Any& operand)
{
  ValueType* result = any_cast<ValueType>(&operand);
  if (!result) throw BadAnyCastException("RefAnyCast: Failed to convert between Any types");
  return *result;
}

/**
 * \internal
 *
 * The "unsafe" versions of any_cast are not part of the
 * public interface and may be removed at any time. They are
 * required where we know what type is stored in the any and can't
 * use typeid() comparison, e.g., when our types may travel across
 * different shared libraries.
 */
template <typename ValueType>
ValueType* unsafe_any_cast(Any* operand)
{
  return &static_cast<Any::Holder<ValueType>*>(operand->_content)->_held;
}

/**
 * \internal
 *
 * The "unsafe" versions of any_cast are not part of the
 * public interface and may be removed at any time. They are
 * required where we know what type is stored in the any and can't
 * use typeid() comparison, e.g., when our types may travel across
 * different shared libraries.
 */
template <typename ValueType>
const ValueType* unsafe_any_cast(const Any* operand)
{
  return any_cast<ValueType>(const_cast<Any*>(operand));
}


template<class K>
std::string any_value_to_string(const std::map<K, Any>& m)
{
  std::stringstream ss;
  ss << "{";
  typedef typename std::map<K, Any>::const_iterator Iterator;
  Iterator i1 = m.begin();
  const Iterator begin = i1;
  const Iterator end = m.end();
  for ( ; i1 != end; ++i1)
  {
    if (i1 == begin) ss << i1->first << " : " << i1->second.ToString();
    else ss << ", " << i1->first << " : " << i1->second.ToString();
  }
  ss << "}";
  return ss.str();
}

template<class K, class V>
std::string any_value_to_string(const std::map<K, V>& m)
{
  std::stringstream ss;
  ss << "{";
  typedef typename std::map<K, V>::const_iterator Iterator;
  Iterator i1 = m.begin();
  const Iterator begin = i1;
  const Iterator end = m.end();
  for ( ; i1 != end; ++i1)
  {
    if (i1 == begin) ss << i1->first << " : " << i1->second;
    else ss << ", " << i1->first << " : " << i1->second;
  }
  ss << "}";
  return ss.str();
}

template<class K>
std::string any_value_to_json(const std::map<K, Any>& m)
{
  std::stringstream ss;
  ss << "{";
  typedef typename std::map<K, Any>::const_iterator Iterator;
  Iterator i1 = m.begin();
  const Iterator begin = i1;
  const Iterator end = m.end();
  for ( ; i1 != end; ++i1)
  {
    if (i1 == begin) ss << "\"" << i1->first << "\" : " << i1->second.ToJSON();
    else ss << ", " << "\"" << i1->first << "\" : " << i1->second.ToJSON();
  }
  ss << "}";
  return ss.str();
}

template<class K, class V>
std::string any_value_to_json(const std::map<K, V>& m)
{
  std::stringstream ss;
  ss << "{";
  typedef typename std::map<K, V>::const_iterator Iterator;
  Iterator i1 = m.begin();
  const Iterator begin = i1;
  const Iterator end = m.end();
  for ( ; i1 != end; ++i1)
  {
    if (i1 == begin) ss << "\"" << i1->first << "\" : " << i1->second;
    else ss << ", " << "\"" << i1->first << "\" : " << i1->second;
  }
  ss << "}";
  return ss.str();
}

}

#endif // US_ANY_H
