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

#ifndef XSD_CXX_XML_DOM_SERIALIZATION_HXX
#define XSD_CXX_XML_DOM_SERIALIZATION_HXX

#include <map>
#include <string>
#include <ostream>
#include <sstream>

#include <xsd/cxx/xml/error-handler.hxx>
#include <xsd/cxx/xml/dom/elements.hxx>

namespace xsd
{
  namespace cxx
  {
    namespace xml
    {
      namespace dom
      {
        //
        //
        template <typename C>
        struct namespace_info
        {
          typedef std::basic_string<C> string;

          namespace_info ()
          {
          }

          namespace_info (string const& name_, string const& schema_)
              : name (name_),
                schema (schema_)
          {
          }

          std::basic_string<C> name;
          std::basic_string<C> schema;
        };


        // Map of namespace prefix to namespace_info.
        //
        template <typename C>
        struct namespace_infomap:
          public std::map<std::basic_string<C>, namespace_info<C> >
        {
        };


        // No mapping provided for a namespace.
        //
        template <typename C>
        struct mapping
        {
          mapping (std::basic_string<C> const& name)
              : name_ (name)
          {
          }

          std::basic_string<C> const&
          name () const
          {
            return name_;
          }

        private:
          std::basic_string<C> name_;
        };


        // 'xsi' prefix is already in use and no user-defined mapping has
        //  been provided.
        //
        struct xsi_already_in_use {};


        template <typename C>
        xml::dom::auto_ptr<xercesc::DOMDocument>
        dom (std::basic_string<C> const& root_element,
             std::basic_string<C> const& root_element_namespace,
             namespace_infomap<C> const& map);

        // This one helps Sun C++ to overcome its fears.
        //
        template <typename C>
        xml::dom::auto_ptr<xercesc::DOMDocument>
        dom (C const* root_element,
             C const* root_element_namespace,
             namespace_infomap<C> const& map)
        {
          return dom (std::basic_string<C> (root_element),
                      std::basic_string<C> (root_element_namespace),
                      map);
        }

        //
        //
        template <typename C>
        bool
        serialize (xercesc::XMLFormatTarget& target,
                   xercesc::DOMDocument const& doc,
                   std::basic_string<C> const& enconding,
                   error_handler<C>& eh);

        template <typename C>
        bool
        serialize (xercesc::XMLFormatTarget& target,
                   xercesc::DOMDocument const& doc,
                   std::basic_string<C> const& enconding,
                   xercesc::DOMErrorHandler& eh);

        //
        //
        class ostream_format_target: public xercesc::XMLFormatTarget
        {
        public:
          ostream_format_target (std::ostream& os)
              : os_ (os)
          {
          }


        public:
          // I know, some of those consts are stupid. But that's what
          // Xerces folks put into their interfaces and VC-7.1 thinks
          // there are different signatures if one strips this fluff off.
          //
          virtual void
          writeChars (XMLByte const* const buf,
                      unsigned int const size,
                      xercesc::XMLFormatter* const)
          {
            os_.write (reinterpret_cast<char const*> (buf),
                       static_cast<std::streamsize> (size));
          }


          virtual void
          flush ()
          {
            os_.flush ();
          }

        private:
          std::ostream& os_;
        };


        //
        //
        template <typename C>
        struct list_stream
        {
          list_stream (std::basic_ostringstream<C>& os,
                       xml::dom::element<C> const& parent)
              : os_ (os), parent_ (parent)
          {
          }

          std::basic_ostringstream<C>& os_;
          xml::dom::element<C> const parent_;
        };

        // Serialization of basic types.
        //

        // enumerators
        //
        template <typename C>
        void
        operator<< (element<C>& e, C const* s)
        {
          e.value (s);
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, C const* s)
        {
          a.value (s);
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, C const* s)
        {
          ls.os_ << s;
        }


        // 8-bit
        //
        template <typename C>
        void
        operator<< (element<C>& e, signed char c)
        {
          std::basic_ostringstream<C> os;
          os << static_cast<short> (c);
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, signed char c)
        {
          std::basic_ostringstream<C> os;
          os << static_cast<short> (c);
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, signed char c)
        {
          ls.os_ << static_cast<short> (c);
        }

        template <typename C>
        void
        operator<< (element<C>& e, unsigned char c)
        {
          std::basic_ostringstream<C> os;
          os << static_cast<unsigned short> (c);
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, unsigned char c)
        {
          std::basic_ostringstream<C> os;
          os << static_cast<unsigned short> (c);
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, unsigned char c)
        {
          ls.os_ << static_cast<unsigned short> (c);
        }

        // 16-bit
        //
        template <typename C>
        void
        operator<< (element<C>& e, short s)
        {
          std::basic_ostringstream<C> os;
          os << s;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, short s)
        {
          std::basic_ostringstream<C> os;
          os << s;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, short s)
        {
          ls.os_ << s;
        }

        template <typename C>
        void
        operator<< (element<C>& e, unsigned short s)
        {
          std::basic_ostringstream<C> os;
          os << s;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, unsigned short s)
        {
          std::basic_ostringstream<C> os;
          os << s;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, unsigned short s)
        {
          ls.os_ << s;
        }

        // 32-bit
        //
        template <typename C>
        void
        operator<< (element<C>& e, int i)
        {
          std::basic_ostringstream<C> os;
          os << i;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, int i)
        {
          std::basic_ostringstream<C> os;
          os << i;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, int i)
        {
          ls.os_ << i;
        }

        template <typename C>
        void
        operator<< (element<C>& e, unsigned int i)
        {
          std::basic_ostringstream<C> os;
          os << i;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, unsigned int i)
        {
          std::basic_ostringstream<C> os;
          os << i;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, unsigned int i)
        {
          ls.os_ << i;
        }

        // 64-bit
        //
        template <typename C>
        void
        operator<< (element<C>& e, long long l)
        {
          std::basic_ostringstream<C> os;
          os << l;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, long long l)
        {
          std::basic_ostringstream<C> os;
          os << l;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, long long l)
        {
          ls.os_ << l;
        }

        template <typename C>
        void
        operator<< (element<C>& n, unsigned long long l)
        {
          std::basic_ostringstream<C> os;
          os << l;
          n.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, unsigned long long l)
        {
          std::basic_ostringstream<C> os;
          os << l;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, unsigned long long l)
        {
          ls.os_ << l;
        }


        // Boolean.
        //
        template <typename C>
        void
        operator<< (element<C>& e, bool b)
        {
          std::basic_ostringstream<C> os;
          os << std::boolalpha << b;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, bool b)
        {
          std::basic_ostringstream<C> os;
          os << std::boolalpha << b;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, bool b)
        {
          std::ios_base::fmtflags f (ls.os_.setf (std::ios_base::boolalpha));
          ls.os_ << b;
          ls.os_.setf (f);
        }

        // Floating-point types.
        //
        template <typename C>
        void
        operator<< (element<C>& e, float f)
        {
          std::basic_ostringstream<C> os;
          os << f;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, float f)
        {
          std::basic_ostringstream<C> os;
          os << f;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, float f)
        {
          ls.os_ << f;
        }

        template <typename C>
        void
        operator<< (element<C>& e, double d)
        {
          std::basic_ostringstream<C> os;
          os << d;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, double d)
        {
          std::basic_ostringstream<C> os;
          os << d;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, double d)
        {
          ls.os_ << d;
        }

        template <typename C>
        void
        operator<< (element<C>& e, long double d)
        {
          // xsd:decimal (which we currently map to long double)
          // can not be in scientific notation.
          //
          std::basic_ostringstream<C> os;
          os << std::fixed << d;
          e.value (os.str ());
        }

        template <typename C>
        void
        operator<< (attribute<C>& a, long double d)
        {
          // xsd:decimal (which we currently map to long double)
          // can not be in scientific notation.
          //
          std::basic_ostringstream<C> os;
          os << std::fixed << d;
          a.value (os.str ());
        }

        template <typename C>
        void
        operator<< (list_stream<C>& ls, long double d)
        {
          // xsd:decimal (which we currently map to long double)
          // can not be in scientific notation.
          //
          std::ios_base::fmtflags f (
            ls.os_.setf (std::ios_base::fixed, std::ios_base::floatfield));

          ls.os_ << d;

          ls.os_.setf (f, std::ios_base::floatfield);
        }
      }
    }
  }
}

#include <xsd/cxx/xml/dom/serialization.txx>

#endif  // XSD_CXX_XML_DOM_SERIALIZATION_HXX
