// file      : xsd/cxx/xml/string.hxx
// author    : Boris Kolpackov <boris@codesynthesis.com>
// copyright : Copyright (c) 2005 Code Synthesis Tools CC
// license   : GNU GPL v2 + exceptions; see accompanying LICENSE file

#ifndef XSD_CXX_XML_STRING_HXX
#define XSD_CXX_XML_STRING_HXX

#include <string>
#include <cassert>

#include <xercesc/util/XMLString.hpp>

namespace xsd
{
  namespace cxx
  {
    namespace xml
    {
      template <typename C>
      std::basic_string<C>
      transcode (XMLCh const* s, std::size_t length = 0);

      template <typename C>
      XMLCh*
      transcode (std::basic_string<C> const& s);

      //
      //
      class string
      {
      public :
        template <typename C>
        string (std::basic_string<C> const& s)
            : s_ (transcode<C> (s))
        {
        }

        template <typename C>
        string (C const* s)
            : s_ (transcode<C> (s))
        {
        }

        ~string ()
        {
          xercesc::XMLString::release (&s_);
        }

        XMLCh const*
        c_str () const
        {
          return s_;
        }

      private:
        string (string const&);

        string&
        operator= (string const&);

      private:
        XMLCh* s_;
      };


      template <>
      inline
      std::basic_string<char>
      transcode<char> (XMLCh const* s, std::size_t length)
      {
        if (s == 0)
          return std::basic_string<char> ();

        XMLCh const* src (s);

        if (length != 0)
        {
          // Know a better way? Let me know.
          //
          XMLCh* tmp = new XMLCh[length + 1];
          memcpy (tmp, s, length * sizeof (XMLCh));

          tmp[length] = XMLCh (0);

          src = tmp;
        }

        char* buf (xercesc::XMLString::transcode (s));

        if (src != s)
          delete[] (src);

        std::basic_string<char> r (buf);

        xercesc::XMLString::release (&buf);

        return r;
      }

      template <>
      inline
      std::basic_string<wchar_t>
      transcode<wchar_t> (XMLCh const* s, std::size_t length)
      {
        if (s == 0)
          return std::basic_string<wchar_t> ();

        // std::wcerr << s << std::endl;

        std::size_t l (0);

        if (length)
        {
          for (; l < length; ++l)
          {
            if (s[l] == 0)
              break;
          }
        }
        else
          l = xercesc::XMLString::stringLen (s);

        std::basic_string<wchar_t> r (l, L'0');

        for (std::size_t i (0); i <= l; ++s, ++i)
        {
          r[i] = *s;
        }

        return r;
      }

      template <>
      inline
      XMLCh*
      transcode (std::basic_string<char> const& s)
      {
        return xercesc::XMLString::transcode (s.c_str ());
      }

      template <>
      inline
      XMLCh*
      transcode (std::basic_string<wchar_t> const& s)
      {
        std::size_t l (s.length ());

        XMLCh* r (new XMLCh[l + 1]);
        XMLCh* ir (r);

        for (std::size_t i (0); i < l; ++ir, ++i)
        {
          *ir = static_cast<XMLCh>(s[i]);
          //std::wcerr << s[i] << "->" << *ir << std::endl;
        }

        *ir = XMLCh (0);

        // std::wcerr << r << std::endl;

        return r;
      }
    }
  }
}

#endif  // XSD_CXX_XML_STRING_HXX
