
/*

  KLayout Layout Viewer
  Copyright (C) 2006-2017 Matthias Koefferlein

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

*/


#ifndef _HDR_gsiSerialisation
#define _HDR_gsiSerialisation

#include "gsiTypes.h"
#include "tlHeap.h"
#include "tlUtils.h"

#include <list>
#include <memory>

namespace gsi
{

// ------------------------------------------------------------
//  SerialArgs definition

class AdaptorBase;

/**
 *  @brief Copy the contents of adaptor-provided data to the given type X
 *  X can be a valid target type for the adaptor's container scheme - for
 *  example a vector for a vector adaptor.
 *  This generic function will copy the elements of the vector one by one
 *  to the target.
 */
template <class X> void copy_to (AdaptorBase &a, X &x, tl::Heap &heap);

/**
 *  @brief Tie the contents of adaptor-provided data to the given type X
 *  This generic function will first copy the contents of the adaptor-provided
 *  container to the object x. It will also tie both containers, so when the
 *  adaptor is deleted, it will pull it's content from the former target x.
 *  This is used to implement "out" parameter schemes for adapted containers.
 *  This function will take over the ownership of the a adaptor.
 */
template <class X> void tie_copies (AdaptorBase *a, X &x, tl::Heap &heap);

/**
 *  @brief An adaptor factory for adaptors of type X
 */
template <class Tag, class X>
struct adaptor_factory
{
  /**
   *  @brief The factory method
   *  This method will return a new adaptor object providing access to the raw object v.
   */
  static AdaptorBase *get (const X &v);
};

/**
 *  @brief An exception thrown if there are not enough arguments on the serialization buffer
 */
struct GSI_PUBLIC ArglistUnderflowException
  : public tl::Exception
{
  ArglistUnderflowException ()
    : tl::Exception (tl::to_string (QObject::tr ("Too few arguments or no return value supplied")))
  { }
};

/**
 *  @brief An exception thrown if a reference is null (nil)
 */
struct GSI_PUBLIC NilPointerToReference
  : public tl::Exception
{
  NilPointerToReference ()
    : tl::Exception (tl::to_string (QObject::tr ("nil object passed to a reference")))
  { }
};

/**
 *  @brief This class provides the basic argument serialization mechanism for the C++/scripting interface
 */
class GSI_PUBLIC SerialArgs
{
public:
  /**
   *  @brief Default constructor
   *  Creates an empty list.
   */
  SerialArgs ()
    : mp_buffer (0)
  {
    mp_write = mp_read = mp_buffer;
  }

  /**
   *  @brief Constructor
   *  Creates a buffer with space for len bytes.
   */
  SerialArgs (size_t len)
    : mp_buffer (0)
  {
    //  use the internal buffer for small argument lists (which are quite common)
    if (len > sizeof (m_buffer)) {
      mp_buffer = new char [len];
    } else if (len > 0) {
      mp_buffer = m_buffer;
    }
    mp_write = mp_read = mp_buffer;
  }

  /**
   *  @brief Destructor
   */
  ~SerialArgs ()
  {
    if (mp_buffer && mp_buffer != m_buffer) {
      delete [] mp_buffer;
    }
    mp_buffer = 0;
  }

  /**
   *  @brief Resets the write and read pointer
   */
  void reset ()
  {
    mp_read = mp_write = mp_buffer;
  }

  /**
   *  @brief gets a pointer to the buffer
   */
  char *cptr ()
  {
    return mp_buffer;
  }

  /**
   *  @brief gets a const pointer to the buffer
   */
  const char *cptr () const
  {
    return mp_buffer;
  }

  /**
   *  @brief Gets a pointer to the current write position
   */
  char *wptr ()
  {
    return mp_write;
  }

  /**
   *  @brief Gets a const pointer to the current write position
   */
  const char *wptr () const
  {
    return mp_write;
  }

  /**
   *  @brief Gets a pointer to the current read position
   */
  char *rptr ()
  {
    return mp_read;
  }

  /**
   *  @brief Gets a const pointer to the current read position
   */
  const char *rptr () const
  {
    return mp_read;
  }

  /**
   *  @brief Writes a value into the buffer
   */
  template <class X>
  inline void write (const X &x)
  {
    this->write_impl (typename type_traits<X>::tag (), x);
  }

  /**
   *  @brief Reads a value from the buffer
   */
  template <class X>
  inline X read (tl::Heap &heap)
  {
    return this->read_impl<X> (typename type_traits<X>::tag (), heap);
  }

  /**
   *  @brief returns true, if there is still data available for read
   */
  operator bool () const
  {
    return mp_read && mp_read < mp_write;
  }

private:
  char *mp_buffer;
  char *mp_read, *mp_write;
  char m_buffer[200];

  inline void check_data () const
  {
    if (! *this) {
      throw ArglistUnderflowException ();
    }
  }

  // -----------------------------------------------------------
  //  reader implementations

  template <class X>
  void write_impl (const pod_direct_tag &, const X &x)
  {
    *((X *)mp_write) = x;
    mp_write += item_size<X> ();
  }

  template <class X>
  void write_impl (const x_tag &, const X &x)
  {
    *((X **)mp_write) = new X (x);
    mp_write += item_size<X *> ();
  }

  template <class X>
  void write_impl (const ref_tag &, X &x)
  {
    *((X **)mp_write) = &x;
    mp_write += item_size<X *> ();
  }

  template <class X>
  void write_impl (const ptr_tag &, X *x)
  {
    *((X **)mp_write) = x;
    mp_write += item_size<X *> ();
  }

  template <class X>
  void write_impl (const pod_cref_tag &, const X &x)
  {
    X *r = (X *)mp_write;
    new (r) X(x);
    mp_write += item_size<X> ();
  }

  template <class X>
  void write_impl (const npod_cref_tag &, const X &x)
  {
    *((X const **)mp_write) = &x;
    mp_write += item_size<const X *> ();
  }

  template <class X>
  void write_impl (const x_cref_tag &, const X &x)
  {
    *((X const **)mp_write) = &x;
    mp_write += item_size<const X *> ();
  }

  template <class X>
  void write_impl (const pod_cptr_tag &, const X *x)
  {
    *(bool *)mp_write = (x != 0);
    mp_write += item_size<bool> ();
    if (x) {
      *(X *)mp_write = *x;
    }
    mp_write += item_size<X> ();
  }

  //  see notes on the serialization for this type:
  template <class X>
  void write_impl (const npod_cptr_tag &, const X *x)
  {
    *((X const **)mp_write) = x;
    mp_write += item_size<const X *> ();
  }

  template <class X>
  void write_impl (const x_cptr_tag &, const X *x)
  {
    *((X const **)mp_write) = x;
    mp_write += item_size<const X *> ();
  }

  void write_impl (const vptr_tag &, void *x)
  {
    *((void **)mp_write) = x;
    mp_write += item_size<void *> ();
  }

  void write_impl (const vptr_tag &, const void *x)
  {
    *((const void **)mp_write) = x;
    mp_write += item_size<const void *> ();
  }

  template <class X>
  void write_impl (const adaptor_direct_tag &, const X &x)
  {
    *((void **)mp_write) = adaptor_factory<typename gsi::type_traits<X>::tag, X>::get (x);
    mp_write += item_size<void *> ();
  }

  template <class X>
  void write_impl (const adaptor_ptr_tag &, X *x)
  {
    if (x) {
      *((void **)mp_write) = adaptor_factory<typename gsi::type_traits<X *>::tag, X *>::get (x);
    } else {
      *((void **)mp_write) = 0;
    }
    mp_write += item_size<void *> ();
  }

  template <class X>
  void write_impl (const adaptor_cptr_tag &, const X *x)
  {
    if (x) {
      *((void **)mp_write) = adaptor_factory<typename gsi::type_traits<const X *>::tag, const X *>::get (x);
    } else {
      *((void **)mp_write) = 0;
    }
    mp_write += item_size<void *> ();
  }

  template <class X>
  void write_impl (const adaptor_ref_tag &, X &x)
  {
    *((void **)mp_write) = adaptor_factory<typename gsi::type_traits<X &>::tag, X &>::get (x);
    mp_write += item_size<void *> ();
  }

  template <class X>
  void write_impl (const adaptor_cref_tag &, const X &x)
  {
    *((void **)mp_write) = adaptor_factory<typename gsi::type_traits<const X &>::tag, const X &>::get (x);
    mp_write += item_size<void *> ();
  }

  // -----------------------------------------------------------
  //  reader implementations

  template <class X>
  X read_impl (const pod_direct_tag &, tl::Heap &)
  {
    check_data ();
    X r = *((X *)mp_read);
    mp_read += item_size<X> ();
    return r;
  }

  template <class X>
  X read_impl (const x_tag &, tl::Heap &)
  {
    check_data ();
    X *xp = *(X **)mp_read;
    X x = *xp;
    delete xp;
    mp_read += item_size<void *> ();
    return x;
  }

  template <class X>
  X read_impl (const vptr_tag &, tl::Heap &)
  {
    void *r = *((void **)mp_read);
    mp_read += item_size<void *> ();
    // Hint: X can be const unsigned char *, const signed char * as well.
    return (X)r;
  }

  template <class X>
  X read_impl (const ref_tag &, tl::Heap &)
  {
    typedef typename type_traits<X>::value_type value_type;
    check_data ();
    value_type *r = *((value_type **)mp_read);
    mp_read += item_size<value_type *> ();
    if (! r) {
      throw NilPointerToReference ();
    }
    return *r;
  }

  template <class X>
  X read_impl (const pod_cref_tag &, tl::Heap &)
  {
    //  X is actually an (const X &)
    typedef typename type_traits<X>::value_type value_type;
    check_data ();
    const value_type *r = ((const value_type *)mp_read);
    mp_read += item_size<value_type> ();
    return *r;
  }

  template <class X>
  X read_impl (const npod_cref_tag &, tl::Heap &)
  {
    //  X is actually an (const X &)
    typedef typename type_traits<X>::value_type value_type;
    check_data ();
    const value_type *r = *((const value_type **)mp_read);
    mp_read += item_size<const value_type *> ();
    if (! r) {
      throw NilPointerToReference ();
    }
    return *r;
  }

  template <class X>
  X read_impl (const x_cref_tag &, tl::Heap &)
  {
    //  X is actually an (const X &)
    typedef typename type_traits<X>::value_type value_type;
    check_data ();
    const value_type *r = *((const value_type **)mp_read);
    mp_read += item_size<const value_type *> ();
    if (! r) {
      throw NilPointerToReference ();
    }
    return *r;
  }

  template <class X>
  X read_impl (const ptr_tag &, tl::Heap &)
  {
    //  X is actually an (X *)
    typedef typename type_traits<X>::value_type value_type;
    check_data ();
    value_type * const &r = *((value_type **)mp_read);
    mp_read += item_size<value_type *> ();
    return r;
  }

  template <class X>
  X read_impl (const pod_cptr_tag &, tl::Heap &)
  {
    //  X is actually an (const X *)
    check_data ();
    bool h = *(bool *)mp_read;
    mp_read += item_size<bool> ();
    X r = h ? (X)mp_read : (X)0;
    mp_read += item_size<X> ();
    return r;
  }

  //  see notes on the serialization for this type:
  template <class X>
  X read_impl (const npod_cptr_tag &, tl::Heap &)
  {
    //  X is actually an (const X *)
    check_data ();
    X r = *((X *)mp_read);
    mp_read += item_size<X> ();
    return r;
  }

  template <class X>
  X read_impl (const x_cptr_tag &, tl::Heap &)
  {
    //  X is actually an (const X *)
    check_data ();
    X r = *((X *)mp_read);
    mp_read += item_size<X> ();
    return r;
  }

  template <class X>
  X read_impl (const adaptor_direct_tag &, tl::Heap &heap)
  {
    check_data ();

    std::auto_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
    mp_read += item_size<AdaptorBase *> ();
    tl_assert (p.get () != 0);

    X x = X ();
    copy_to<X> (*p, x, heap);
    return x;
  }

  template <class X>
  X read_impl (const adaptor_cref_tag &, tl::Heap &heap)
  {
    typedef typename tl::get_inner_type<X>::result x_type;

    check_data ();

    std::auto_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
    mp_read += item_size<AdaptorBase *> ();
    tl_assert (p.get () != 0);

    x_type *x = new x_type ();
    heap.push (x);
    copy_to<x_type> (*p, *x, heap);

    return *x;
  }

  template <class X>
  X read_impl (const adaptor_ref_tag &, tl::Heap &heap)
  {
    typedef typename tl::get_inner_type<X>::result x_type;

    check_data ();

    AdaptorBase *p = *(AdaptorBase **)mp_read;
    mp_read += item_size<AdaptorBase *> ();
    tl_assert (p != 0);

    x_type *x = new x_type ();
    heap.push (x);
    tie_copies<x_type> (p, *x, heap);

    return *x;
  }

  template <class X>
  X read_impl (const adaptor_cptr_tag &, tl::Heap &heap)
  {
    typedef typename tl::get_inner_type<X>::result x_type;

    check_data ();

    std::auto_ptr<AdaptorBase> p (*(AdaptorBase **)mp_read);
    mp_read += item_size<AdaptorBase *> ();

    x_type *x = 0;
    if (p.get () != 0) {
      x = new x_type ();
      heap.push (x);
      copy_to<x_type> (*p, *x, heap);
    }

    return x;
  }

  template <class X>
  X read_impl (const adaptor_ptr_tag &, tl::Heap &heap)
  {
    typedef typename tl::get_inner_type<X>::result x_type;

    check_data ();

    AdaptorBase *p = *(AdaptorBase **)mp_read;
    mp_read += item_size<AdaptorBase *> ();

    x_type *x = 0;
    if (p != 0) {

      x = new x_type ();
      heap.push (x);
      tie_copies<x_type> (p, *x, heap);

    }

    return x;
  }
};

// ------------------------------------------------------------
//  Basic adaptor 

class GSI_PUBLIC AdaptorBase
{
public:
  AdaptorBase ();
  virtual ~AdaptorBase ();

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const = 0;

  void tie_copies (AdaptorBase *target, tl::Heap &heap);
};

// ------------------------------------------------------------
//  String adaptor framework

/**
 *  @brief A generic adaptor for strings
 *  This is the base class for implementing generic access to strings
 */
class GSI_PUBLIC StringAdaptor
  : public AdaptorBase
{
public:
  /**
   *  @brief Default constructor
   */
  StringAdaptor () { }

  /**
   *  @brief Destructor
   */
  virtual ~StringAdaptor () { }

  /**
   *  @brief Returns the size of the string
   */
  virtual size_t size () const = 0;

  /**
   *  @brief Returns a pointer to a UTF8 encoded character array with size size()
   */
  virtual const char *c_str () const = 0;

  /**
   *  @brief Sets the string to the given UTF8 string with length s
   */
  virtual void set (const char *c_str, size_t s, tl::Heap &heap) = 0;

  /**
   *  @brief copy_to implementation
   */
  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const 
  {
    StringAdaptor *s = dynamic_cast<StringAdaptor *>(target);
    tl_assert (s);
    s->set (c_str (), size (), heap);
  }
};

/**
 *  @brief Generic string adaptor implementation
 */
template <class X> 
class StringAdaptorImpl 
  : public StringAdaptor
{
};

/**
 *  @brief Specialization for QByteArray
 */
template <>
class StringAdaptorImpl<QByteArray>
  : public StringAdaptor
{
public:
  StringAdaptorImpl (QByteArray *s) 
    : mp_s (s), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const QByteArray *s) 
    : mp_s (const_cast<QByteArray *> (s)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const QByteArray &s) 
    : m_is_const (false), m_s (s) 
  { 
    mp_s = &m_s; 
  }

  StringAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_s = &m_s; 
  }

  virtual ~StringAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_s->size (); 
  }

  virtual const char *c_str () const
  {
    return mp_s->constData (); 
  }

  virtual void set (const char *c_str, size_t s, tl::Heap &) 
  {
    if (! m_is_const) {
      *mp_s = QByteArray (c_str, s);
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    StringAdaptorImpl<QByteArray> *s = dynamic_cast<StringAdaptorImpl<QByteArray> *>(target);
    if (s) {
      *s->mp_s = *mp_s;
    } else {
      StringAdaptor::copy_to (target, heap);
    }
  }
   
private:
  QByteArray *mp_s;
  bool m_is_const;
  QByteArray m_s;
};

/**
 *  @brief Specialization for QString
 */
template <>
class StringAdaptorImpl<QString>
  : public StringAdaptor
{
public:
  StringAdaptorImpl (QString *s) 
    : mp_s (s), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const QString *s) 
    : mp_s (const_cast<QString *> (s)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const QString &s) 
    : m_is_const (false), m_s (s) 
  { 
    mp_s = &m_s; 
  }

  StringAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_s = &m_s; 
  }

  virtual ~StringAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_s->toUtf8 ().size (); 
  }

  virtual const char *c_str () const
  {
    m_s_utf8 = mp_s->toUtf8 ();
    return m_s_utf8.constData ();
  }

  virtual void set (const char *c_str, size_t s, tl::Heap &) 
  {
    if (! m_is_const) {
      *mp_s = QString::fromUtf8 (c_str, s);
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    StringAdaptorImpl<QString> *s = dynamic_cast<StringAdaptorImpl<QString> *>(target);
    if (s) {
      *s->mp_s = *mp_s;
    } else {
      StringAdaptor::copy_to (target, heap);
    }
  }
   
private:
  QString *mp_s;
  bool m_is_const;
  QString m_s;
  mutable QByteArray m_s_utf8;
};

/**
 *  @brief Specialization for QStringRef
 */
template <>
class StringAdaptorImpl<QStringRef>
  : public StringAdaptor
{
public:
  StringAdaptorImpl (QStringRef *s) 
    : mp_s (s), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const QStringRef *s) 
    : mp_s (const_cast<QStringRef *> (s)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const QStringRef &s) 
    : m_is_const (false), m_s (s) 
  { 
    mp_s = &m_s; 
  }

  StringAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_s = &m_s; 
  }

  virtual ~StringAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_s->toString ().toUtf8 ().size ();
  }

  virtual const char *c_str () const
  {
    m_s_utf8 = mp_s->toString ().toUtf8 ();
    return m_s_utf8.constData ();
  }

  virtual void set (const char *c_str, size_t s, tl::Heap &heap) 
  {
    if (! m_is_const) {
      QString *qstr = new QString (QString::fromUtf8 (c_str, s));
      heap.push (qstr);
      *mp_s = QStringRef (qstr);
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    StringAdaptorImpl<QStringRef> *s = dynamic_cast<StringAdaptorImpl<QStringRef> *>(target);
    if (s) {
      *s->mp_s = *mp_s;
    } else {
      StringAdaptor::copy_to (target, heap);
    }
  }
   
private:
  QStringRef *mp_s;
  bool m_is_const;
  QStringRef m_s;
  mutable QByteArray m_s_utf8;
};

/**
 *  @brief Specialization for std::string
 */
template <>
class StringAdaptorImpl<std::string>
  : public StringAdaptor
{
public:
  StringAdaptorImpl (std::string *s) 
    : mp_s (s), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const std::string *s) 
    : mp_s (const_cast<std::string *> (s)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImpl (const std::string &s) 
    : m_is_const (false), m_s (s) 
  { 
    mp_s = &m_s; 
  }

  StringAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_s = &m_s; 
  }

  virtual ~StringAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_s->size (); 
  }

  virtual const char *c_str () const
  {
    return mp_s->c_str ();
  }

  virtual void set (const char *c_str, size_t s, tl::Heap &) 
  {
    if (! m_is_const) {
      *mp_s = std::string (c_str, s);
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    StringAdaptorImpl<std::string> *s = dynamic_cast<StringAdaptorImpl<std::string> *>(target);
    if (s) {
      *s->mp_s = *mp_s;
    } else {
      StringAdaptor::copy_to (target, heap);
    }
  }
   
private:
  std::string *mp_s;
  bool m_is_const;
  std::string m_s;
};

/**
 *  @brief Specialization for const unsigned char *
 */
template <class CP>
class StringAdaptorImplCCP
  : public StringAdaptor
{
public:
  StringAdaptorImplCCP (CP *s) 
    : mp_s (s), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImplCCP (const CP *s) 
    : mp_s (const_cast<CP *> (s)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  StringAdaptorImplCCP (CP s) 
    : m_is_const (false), m_s ((const char *) s) 
  { 
    mp_s = 0; 
  }

  StringAdaptorImplCCP () 
    : m_is_const (false)
  { 
    mp_s = 0; 
  }

  virtual ~StringAdaptorImplCCP () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_s ? strlen ((const char *) *mp_s) : m_s.size ();
  }

  virtual const char *c_str () const
  {
    return mp_s ? (const char *) *mp_s : m_s.c_str ();
  }

  virtual void set (const char *c_str, size_t s, tl::Heap &heap) 
  {
    if (! m_is_const) {
      if (! mp_s) {
        //  This adaptor is not attached to an external "const char *" pointer, so we can 
        //  safely use the internal storage.
        m_s = std::string (c_str, s);
      } else {
        //  This means we assign a simple pointer some other pointer without 
        //  knowning how long the other points lives. To account for that we create 
        //  a temporary string on the heap and take the pointer from there.
        //  Since the target is a pointer outside this adaptor, we cannot use the
        //  adaptor's internal storage since the adaptor won't survive the outside
        //  use case.
        std::string *tmp_string = new std::string (c_str, s);
        heap.push (tmp_string);
        *mp_s = (CP) tmp_string->c_str ();
      }
    }
  }

private:
  CP *mp_s;
  bool m_is_const;
  std::string m_s;
};

/**
 *  @brief Specialization for const char *
 */
template <>
class StringAdaptorImpl<const char *>
  : public StringAdaptorImplCCP<const char *>
{
public:
  typedef char char_type;
  StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP<const char_type *> (s) { }
  StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP<const char_type *> (s) { }
  StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP<const char_type *> (s) { }
};

/**
 *  @brief Specialization for const unsigned char *
 */
template <>
class StringAdaptorImpl<const unsigned char *>
  : public StringAdaptorImplCCP<const unsigned char *>
{
public:
  typedef unsigned char char_type;
  StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP<const char_type *> (s) { }
  StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP<const char_type *> (s) { }
  StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP<const char_type *> (s) { }
};

/**
 *  @brief Specialization for const signed char *
 */
template <>
class StringAdaptorImpl<const signed char *>
  : public StringAdaptorImplCCP<const signed char *>
{
public:
  typedef signed char char_type;
  StringAdaptorImpl (const char_type **s) : StringAdaptorImplCCP<const char_type *> (s) { }
  StringAdaptorImpl (const char_type * const *s) : StringAdaptorImplCCP<const char_type *> (s) { }
  StringAdaptorImpl (const char_type *s) : StringAdaptorImplCCP<const char_type *> (s) { }
};

// ------------------------------------------------------------
//  Variant adaptor framework

/**
 *  @brief A generic adaptor for strings
 *  This is the base class for implementing generic access to strings
 */
class GSI_PUBLIC VariantAdaptor
  : public AdaptorBase
{
public:
  /**
   *  @brief Default constructor
   */
  VariantAdaptor () { }

  /**
   *  @brief Destructor
   */
  virtual ~VariantAdaptor () { }

  /**
   *  @brief Gets the tl::Variant representing this variant
   */
  virtual tl::Variant var () const = 0;

  /**
   *  @brief Sets the variant's value
   */
  virtual void set (const tl::Variant &v) = 0;

  /**
   *  @brief Implementation of copy_to
   */
  virtual void copy_to (AdaptorBase *target, tl::Heap & /*heap*/) const
  {
    VariantAdaptor *v = dynamic_cast<VariantAdaptor *>(target);
    tl_assert (v);
    v->set (var ());
  }
};

/**
 *  @brief Generic string adaptor implementation
 */
template <class X> 
class VariantAdaptorImpl 
  : public VariantAdaptor
{
};

/**
 *  @brief Specialization for QVariant
 */
template <>
class VariantAdaptorImpl<QVariant>
  : public VariantAdaptor
{
public:
  VariantAdaptorImpl (QVariant *v) 
    : mp_v (v), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  VariantAdaptorImpl (const QVariant *v) 
    : mp_v (const_cast<QVariant *> (v)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  VariantAdaptorImpl (const QVariant &v) 
    : m_is_const (true), m_v (v)
  { 
    mp_v = &m_v; 
  }

  VariantAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_v = &m_v; 
  }

  virtual ~VariantAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual tl::Variant var () const 
  { 
    return tl::Variant (*mp_v);
  }

  const QVariant &qvar () const 
  { 
    return *mp_v;
  }

  virtual void set (const tl::Variant &v) 
  {
    if (! m_is_const) {
      *mp_v = v.to_qvariant ();
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    VariantAdaptorImpl<QVariant> *v = dynamic_cast<VariantAdaptorImpl<QVariant> *>(target);
    if (v) {
      *v->mp_v = qvar ();
    } else {
      VariantAdaptor::copy_to (target, heap);
    }
  }
   
private:
  QVariant *mp_v;
  bool m_is_const;
  QVariant m_v;
};

/**
 *  @brief Specialization for tl::Variant
 */
template <>
class VariantAdaptorImpl<tl::Variant>
  : public VariantAdaptor
{
public:
  VariantAdaptorImpl (tl::Variant *v) 
    : mp_v (v), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  VariantAdaptorImpl (const tl::Variant *v) 
    : mp_v (const_cast<tl::Variant *> (v)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  VariantAdaptorImpl (const tl::Variant &v) 
    : m_is_const (true), m_v (v)
  { 
    mp_v = &m_v; 
  }

  VariantAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_v = &m_v; 
  }

  virtual ~VariantAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual tl::Variant var () const 
  { 
    return *mp_v;
  }

  const tl::Variant &var_ref () const 
  { 
    return *mp_v;
  }

  virtual void set (const tl::Variant &v) 
  {
    if (! m_is_const) {
      *mp_v = v;
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    VariantAdaptorImpl<tl::Variant> *v = dynamic_cast<VariantAdaptorImpl<tl::Variant> *>(target);
    if (v) {
      *v->mp_v = var_ref ();
    } else {
      VariantAdaptor::copy_to (target, heap);
    }
  }
   
private:
  tl::Variant *mp_v;
  bool m_is_const;
  tl::Variant m_v;
};

// ------------------------------------------------------------
//  Vector adaptor framework

/**
 *  @brief A generalization to the vector (array) iterator
 *  This is the base class for the actual implementation
 */
class GSI_PUBLIC VectorAdaptorIterator
{
public:
  /**
   *  @brief Default constructor
   */
  VectorAdaptorIterator () { }

  /**
   *  @brief Destructor
   */
  virtual ~VectorAdaptorIterator () { }

  /**
   *  @brief Gets the currently pointed member
   *  The member is written to the serial buffer.
   *  The buffer is not cleared before.
   */
  virtual void get (SerialArgs &w, tl::Heap &) const = 0;

  /**
   *  @brief Returns true, if the iterator is at the end of the sequence
   */
  virtual bool at_end () const = 0;

  /**
   *  @brief Increments the iterator
   */
  virtual void inc () = 0;
};

/**
 *  @brief A generic adaptor for vectors (arrays in general)
 *  This is the base class for implementing generic access to vectors or other linear containers.
 */
class GSI_PUBLIC VectorAdaptor
  : public AdaptorBase
{
public:
  /**
   *  @brief Default constructor
   */
  VectorAdaptor () { }

  /**
   *  @brief Destructor
   */
  virtual ~VectorAdaptor () { }

  /**
   *  @brief Returns the size of the array
   */
  virtual size_t size () const = 0;

  /**
   *  @brief Creates a generic iterator object
   *  The object must be destroyed by the caller
   */
  virtual VectorAdaptorIterator *create_iterator () const = 0;

  /**
   *  @brief Adds a new member to the container
   *  The member is expected as a serialized object on the SerialArgs buffer.
   *  The heap must be provided to account for cases where temporary objects need to be created
   *  upon reading (for example a vector<vector *>).
   */
  virtual void push (SerialArgs &r, tl::Heap &heap) = 0;

  /**
   *  @brief Clears the vector
   */
  virtual void clear () = 0;

  /**
   *  @brief Gets the size the serial buffer requires to represent a value
   */
  virtual size_t serial_size () const = 0;

  /**
   *  @brief Implementation of copy_to
   */
  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    VectorAdaptor *v = dynamic_cast<VectorAdaptor *>(target);
    tl_assert (v);

    v->clear ();
    gsi::SerialArgs rr (serial_size ());
    tl_assert (v->serial_size () == serial_size ());

    std::auto_ptr<VectorAdaptorIterator> i (create_iterator ());
    while (! i->at_end ()) {
      rr.reset ();
      i->get (rr, heap);
      v->push (rr, heap);
      i->inc ();
    }
  }
};

/**
 *  @brief Implementation of the generic iterator adaptor for a specific container
 */
template <class Cont>
class VectorAdaptorIteratorImpl
  : public VectorAdaptorIterator
{
public:
  typedef typename Cont::value_type value_type;

  VectorAdaptorIteratorImpl (const Cont &v)
    : m_b (v.begin ()), m_e (v.end ())
  {
  }

  void get (SerialArgs &ww, tl::Heap &) const 
  {
    ww.write<value_type> (*m_b);
  }

  bool at_end () const 
  {
    return m_b == m_e;
  }

  void inc () 
  {
    ++m_b;
  }

private:
  typename Cont::const_iterator m_b, m_e;
};

template <class X>
void push_vector (std::vector<X> &v, const X &x)
{
  v.push_back (x);
}

template <class X>
void push_vector (std::list<X> &v, const X &x)
{
  v.push_back (x);
}

template <class X>
void push_vector (std::set<X> &v, const X &x)
{
  v.insert (x);
}

template <class X>
void push_vector (QVector<X> &v, const X &x)
{
  v.push_back (x);
}

inline void push_vector (QStringList &v, const QString &x)
{
  v.push_back (x);
}

template <class X>
void push_vector (QList<X> &v, const X &x)
{
  v.push_back (x);
}

template <class X>
void push_vector (QSet<X> &v, const X &x)
{
  v.insert (x);
}

/**
 *  @brief Implementation of the generic adaptor for a specific container
 */
template <class Cont>
class VectorAdaptorImpl 
  : public VectorAdaptor
{
public:
  typedef typename Cont::value_type value_type;

  VectorAdaptorImpl (Cont *v) 
    : mp_v (v), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  VectorAdaptorImpl (const Cont *v) 
    : mp_v (const_cast<Cont *> (v)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  VectorAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_v = &m_v; 
  }

  VectorAdaptorImpl (const Cont &v) 
    : m_is_const (false), m_v (v)
  { 
    mp_v = &m_v; 
  }

  virtual ~VectorAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_v->size (); 
  }

  virtual VectorAdaptorIterator *create_iterator () const 
  {
    return new VectorAdaptorIteratorImpl<Cont> (*mp_v);
  }

  virtual void push (SerialArgs &r, tl::Heap &heap) 
  {
    if (! m_is_const) {
      push_vector<value_type> (*mp_v, r.read<value_type> (heap));
    }
  }

  virtual void clear () 
  {
    if (! m_is_const) {
      mp_v->clear ();
    }
  }

  virtual size_t serial_size () const 
  {
    return gsi::type_traits<value_type>::serial_size ();
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    //  simplify copies to identical kinds
    VectorAdaptorImpl<Cont> *t = dynamic_cast<VectorAdaptorImpl<Cont> *> (target);
    if (t) {
      if (! t->m_is_const) {
        *t->mp_v = *mp_v;
      }
    } else {
      VectorAdaptor::copy_to (target, heap);
    }
  }

private:
  Cont *mp_v;
  bool m_is_const;
  Cont m_v;
};

// ------------------------------------------------------------
//  Map adaptor framework

/**
 *  @brief A generalization to the map iterator
 *  This is the base class for the actual implementation
 */
class GSI_PUBLIC MapAdaptorIterator
{
public:
  /**
   *  @brief Default constructor
   */
  MapAdaptorIterator () { }

  /**
   *  @brief Destructor
   */
  virtual ~MapAdaptorIterator () { }

  /**
   *  @brief Gets the currently pointed key and value
   *  The key and value is written to the serial buffer in that order.
   *  The buffer is not cleared before.
   */
  virtual void get (SerialArgs &w, tl::Heap &) const = 0;

  /**
   *  @brief Returns true, if the iterator is at the end of the sequence
   */
  virtual bool at_end () const = 0;

  /**
   *  @brief Increments the iterator
   */
  virtual void inc () = 0;
};

/**
 *  @brief A generic adaptor for maps (associative containers in general)
 *  This is the base class for implementing generic access to map or other associative containers.
 */
class GSI_PUBLIC MapAdaptor
  : public AdaptorBase
{
public:
  /**
   *  @brief Default constructor
   */
  MapAdaptor () { }

  /**
   *  @brief Destructor
   */
  virtual ~MapAdaptor () { }

  /**
   *  @brief Returns the size of the map
   */
  virtual size_t size () const = 0;

  /**
   *  @brief Clears the map
   */
  virtual void clear () = 0;

  /**
   *  @brief Gets the size of the serial buffer for key and value
   */
  virtual size_t serial_size () const = 0;

  /**
   *  @brief Creates a generic iterator object
   *  The object must be destroyed by the caller
   */
  virtual MapAdaptorIterator *create_iterator () const = 0;

  /**
   *  @brief Adds a new member to the map
   *  The key and value is expected as a serialized object on the SerialArgs buffers.
   *  The heap must be provided to account for cases where temporary objects need to be created
   *  upon reading (for example a map<int, vector *>).
   */
  virtual void insert (SerialArgs &rr, tl::Heap &heap) = 0;

  /**
   *  @brief Copies the content of this to the target
   */
  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    MapAdaptor *v = dynamic_cast<MapAdaptor *>(target);
    tl_assert (v);

    v->clear ();
    gsi::SerialArgs rr (serial_size ());
    tl_assert (v->serial_size () == serial_size ());

    std::auto_ptr<MapAdaptorIterator> i (create_iterator ());
    while (! i->at_end ()) {
      rr.reset ();
      i->get (rr, heap);
      v->insert (rr, heap);
      i->inc ();
    }
  }
};

/**
 *  @brief Abstract accessor for maps (STL type)
 *  This template provides abstract insert and getters.
 */
template <class Cont>
struct map_access 
{
  typedef typename Cont::key_type key_type;
  typedef typename Cont::mapped_type value_type;
  typedef typename Cont::const_iterator const_iterator;

  static void insert (Cont &c, const key_type &k, const value_type &v)
  {
    c.insert (std::make_pair (k, v));
  }

  static const key_type &get_key (const_iterator i)
  {
    return i->first;
  }

  static const value_type &get_value (const_iterator i)
  {
    return i->second;
  }
};

/**
 *  @brief Specialization for QMap
 */
template <class X, class Y>
struct map_access<QMap<X, Y> >
{
  typedef QMap<X, Y> cont;
  typedef typename cont::key_type key_type;
  typedef typename cont::mapped_type value_type;
  typedef typename cont::const_iterator const_iterator;

  static void insert (cont &c, const key_type &k, const value_type &v)
  {
    c.insert (k, v);
  }

  static const key_type &get_key (const_iterator i)
  {
    return i.key ();
  }

  static const value_type &get_value (const_iterator i)
  {
    return i.value ();
  }
};

/**
 *  @brief Specialization for QHash
 */
template <class X, class Y>
struct map_access<QHash<X, Y> >
{
  typedef QHash<X, Y> cont;
  typedef typename cont::key_type key_type;
  typedef typename cont::mapped_type value_type;
  typedef typename cont::const_iterator const_iterator;

  static void insert (cont &c, const key_type &k, const value_type &v)
  {
    c.insert (k, v);
  }

  static const key_type &get_key (const_iterator i)
  {
    return i.key ();
  }

  static const value_type &get_value (const_iterator i)
  {
    return i.value ();
  }
};

/**
 *  @brief Implementation of the generic iterator adaptor for a specific container
 */
template <class Cont>
class MapAdaptorIteratorImpl
  : public MapAdaptorIterator
{
public:
  typedef typename Cont::key_type key_type;
  typedef typename Cont::mapped_type value_type;

  MapAdaptorIteratorImpl (const Cont &v)
    : m_b (v.begin ()), m_e (v.end ())
  {
  }

  void get (SerialArgs &ww, tl::Heap &) const 
  {
    ww.write<key_type> (map_access<Cont>::get_key (m_b));
    ww.write<value_type> (map_access<Cont>::get_value (m_b));
  }

  bool at_end () const 
  {
    return m_b == m_e;
  }

  void inc () 
  {
    ++m_b;
  }

private:
  typename Cont::const_iterator m_b, m_e;
};

/**
 *  @brief Implementation of the generic adaptor for a specific container
 */
template <class Cont>
class MapAdaptorImpl 
  : public MapAdaptor
{
public:
  typedef typename Cont::key_type key_type;
  typedef typename Cont::mapped_type value_type;

  MapAdaptorImpl (Cont *m) 
    : mp_m (m), m_is_const (false) 
  { 
    //  .. nothing yet ..
  }

  MapAdaptorImpl (const Cont *m) 
    : mp_m (const_cast<Cont *> (m)), m_is_const (true) 
  { 
    //  .. nothing yet ..
  }

  MapAdaptorImpl (const Cont &m) 
    : m_is_const (false), m_m (m)
  { 
    mp_m = &m_m; 
  }

  MapAdaptorImpl () 
    : m_is_const (false)
  { 
    mp_m = &m_m; 
  }

  virtual ~MapAdaptorImpl () 
  { 
    //  .. nothing yet ..
  }

  virtual size_t size () const 
  { 
    return mp_m->size (); 
  }

  virtual void clear () 
  {
    if (! m_is_const) {
      mp_m->clear ();
    }
  }

  virtual size_t serial_size () const
  {
    return (gsi::type_traits<key_type>::serial_size () + gsi::type_traits<value_type>::serial_size ());
  }

  virtual MapAdaptorIterator *create_iterator () const 
  {
    return new MapAdaptorIteratorImpl<Cont> (*mp_m);
  }

  virtual void insert (SerialArgs &rr, tl::Heap &heap) 
  {
    if (! m_is_const) {
      key_type x = rr.read<key_type> (heap);
      value_type y = rr.read<value_type> (heap);
      map_access<Cont>::insert (*mp_m, x, y);
    }
  }

  virtual void copy_to (AdaptorBase *target, tl::Heap &heap) const
  {
    //  simplify copies to identical kinds
    MapAdaptorImpl<Cont> *t = dynamic_cast<MapAdaptorImpl<Cont> *> (target);
    if (t) {
      if (! t->m_is_const) {
        *t->mp_m = *mp_m;
      }
    } else {
      MapAdaptor::copy_to (target, heap);
    }
  }

private:
  Cont *mp_m;
  bool m_is_const;
  Cont m_m;
};

// ------------------------------------------------------------
//  Create adaptors for various categories

template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const vector_adaptor_tag & /*tag*/, V v)
{
  return new VectorAdaptorImpl<X> (v);
}

template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const map_adaptor_tag & /*tag*/, V v)
{
  return new MapAdaptorImpl<X> (v);
}

template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const string_adaptor_tag & /*tag*/, V v)
{
  return new StringAdaptorImpl<X> (v);
}

template <class X, class V>
inline AdaptorBase *create_adaptor_by_category(const variant_adaptor_tag & /*tag*/, const V &v)
{
  return new VariantAdaptorImpl<X> (v);
}

template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_direct_tag & /*tag*/, const Tag &tag2, const X &v)
{
  return create_adaptor_by_category<X> (tag2, v);
}

template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_cref_tag & /*tag*/, const Tag &tag2, const X &v)
{
  return create_adaptor_by_category<X> (tag2, &v);
}

template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_ref_tag & /*tag*/, const Tag &tag2, X &v)
{
  return create_adaptor_by_category<X> (tag2, &v);
}

template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_cptr_tag & /*tag*/, const Tag &tag2, const X *v)
{
  return create_adaptor_by_category<X> (tag2, v);
}

template <class Tag, class X>
inline AdaptorBase *create_adaptor2 (const adaptor_ptr_tag & /*tag*/, const Tag &tag2, X *v)
{
  return create_adaptor_by_category<X> (tag2, v);
}

template <class Tag, class X> 
inline AdaptorBase *adaptor_factory<Tag, X>::get (const X &v)
{
  Tag tag;
  return create_adaptor2 (tag, tag, v);
}

// ------------------------------------------------------------
//  A generic function to transfer adaptor-managed information into a C++ object

template <class X>
inline void copy_to (AdaptorBase &a, X &x, tl::Heap &heap)
{
  std::auto_ptr<AdaptorBase> t (adaptor_factory<typename gsi::type_traits<X &>::tag, X &>::get (x));
  a.copy_to (t.get (), heap);
}

template <class X>
inline void tie_copies (AdaptorBase *a, X &x, tl::Heap &heap)
{
  AdaptorBase *t (adaptor_factory<typename gsi::type_traits<X &>::tag, X &>::get (x));
  a->tie_copies (t, heap);
}

}

#endif

