// file      : xsd/cxx/tree/serialization.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_TREE_SERIALIZATION_HXX
#define XSD_CXX_TREE_SERIALIZATION_HXX

#include <sstream>

#include <xsd/cxx/xml/dom/elements.hxx>
#include <xsd/cxx/xml/dom/serialization.hxx>

#include <xsd/cxx/tree/types.hxx>

namespace xsd
{
  namespace cxx
  {
    namespace tree
    {
      // Insertion operators for type.
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>&, type const&)
      {
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>&, type const&)
      {
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>&, type const&)
      {
      }

      // Insertion operators for simple_type.
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>&, simple_type const&)
      {
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>&, simple_type const&)
      {
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>&, simple_type const&)
      {
      }

      // Insertion operators for sequence.
      //
      template <typename C, typename X, bool fund>
      void
      operator<< (xml::dom::element<C>& e, sequence<X, fund> const& v)
      {
        std::basic_ostringstream<C> os;
        xml::dom::list_stream<C> ls (os, e);

        ls << v;

        e.value (os.str ());
      }

      template <typename C, typename X, bool fund>
      void
      operator<< (xml::dom::attribute<C>& a, sequence<X, fund> const& v)
      {
        std::basic_ostringstream<C> os;
        xml::dom::list_stream<C> ls (os, a.element ());

        ls << v;

        a.value (os.str ());
      }

      template <typename C, typename X, bool fund>
      void
      operator<< (xml::dom::list_stream<C>& ls, sequence<X, fund> const& v)
      {
        for (typename sequence<X, fund>::const_iterator
               b (v.begin ()), e (v.end ()), i (b); i != e; ++i)
        {
          if (i != b)
            ls.os_ << C (' ');

          ls << *i;
        }
      }


      // Insertion operators for fundamental_base.
      //
      template <typename X, typename C>
      void
      operator<< (xml::dom::element<C>& e, fundamental_base<X> const& x)
      {
        X const& r (x);
        e << r;
      }

      template <typename X, typename C>
      void
      operator<< (xml::dom::attribute<C>& a, fundamental_base<X> const& x)
      {
        X const& r (x);
        a << r;
      }

      template <typename X, typename C>
      void
      operator<< (xml::dom::list_stream<C>& ls, fundamental_base<X> const& x)
      {
        X const& r (x);
        ls << r;
      }


      // Insertion operators for built-in types.
      //


      namespace bits
      {
        template <typename X, typename C>
        void
        insert (xml::dom::element<C>& e, X const& x)
        {
          std::basic_ostringstream<C> os;
          os << x;
          e.value (os.str ());
        }

        template <typename X, typename C>
        void
        insert (xml::dom::attribute<C>& a, X const& x)
        {
          std::basic_ostringstream<C> os;
          os << x;
          a.value (os.str ());
        }
      }


      // string
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, string_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, string_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, string_template<C> const& x)
      {
        ls.os_ << x;
      }


      // normalized_string
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e,
                  normalized_string_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a,
                  normalized_string_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls,
                  normalized_string_template<C> const& x)
      {
        ls.os_ << x;
      }


      // token
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, token_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, token_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, token_template<C> const& x)
      {
        ls.os_ << x;
      }


      // nmtoken
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, nmtoken_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, nmtoken_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, nmtoken_template<C> const& x)
      {
        ls.os_ << x;
      }


      // nmtokens
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, nmtokens_template<C> const& v)
      {
        sequence<nmtoken_template<C> > const& r (v);
        e << r;
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, nmtokens_template<C> const& v)
      {
        sequence<nmtoken_template<C> > const& r (v);
        a << r;
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, nmtokens_template<C> const& v)
      {
        sequence<nmtoken_template<C> > const& r (v);
        ls << r;
      }


      // name
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, name_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, name_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, name_template<C> const& x)
      {
        ls.os_ << x;
      }


      // ncname
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, ncname_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, ncname_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, ncname_template<C> const& x)
      {
        ls.os_ << x;
      }


      // language
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, language_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, language_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, language_template<C> const& x)
      {
        ls.os_ << x;
      }


      // id
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, id_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, id_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, id_template<C> const& x)
      {
        ls.os_ << x;
      }


      // idref
      //
      template <typename X, typename C>
      inline void
      operator<< (xml::dom::element<C>& e, idref_template<X, C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename X, typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, idref_template<X, C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename X, typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, idref_template<X, C> const& x)
      {
        ls.os_ << x;
      }


      // idrefs
      //
      template <typename X, typename C>
      inline void
      operator<< (xml::dom::element<C>& e, idrefs_template<X, C> const& v)
      {
        sequence<idref_template<X, C> > const& r (v);
        e << r;
      }

      template <typename X, typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, idrefs_template<X, C> const& v)
      {
        sequence<idref_template<X, C> > const& r (v);
        a << r;
      }

      template <typename X, typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls,
                  idrefs_template<X, C> const& v)
      {
        sequence<idref_template<X, C> > const& r (v);
        ls << r;
      }


      // uri
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, uri_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, uri_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, uri_template<C> const& x)
      {
        ls.os_ << x;
      }


      // qname
      //
      template <typename C>
      void
      operator<< (xml::dom::element<C>& e, qname_template<C> const& x)
      {
        std::basic_ostringstream<C> os;
        std::basic_string<C> p (xml::dom::prefix<C> (x.namespace_ (), e));

        if (!p.empty ())
          os << p << C (':');

        os << x.name ();

        e.value (os.str ());
      }

      template <typename C>
      void
      operator<< (xml::dom::attribute<C>& a, qname_template<C> const& x)
      {
        std::basic_ostringstream<C> os;
        std::basic_string<C> p (
          xml::dom::prefix<C> (x.namespace_ (), a.element ()));

        if (!p.empty ())
          os << p << C (':');

        os << x.name ();

        a.value (os.str ());
      }

      template <typename X, typename C>
      void
      operator<< (xml::dom::list_stream<C>& ls, qname_template<C> const& x)
      {
        std::basic_string<C> p (
          xml::dom::prefix<C> (x.namespace_ (), ls.parent));

        if (!p.empty ())
          ls.os_ << p << C (':');

        ls.os_ << x.name ();
      }


      // base64_binary
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e,
                  base64_binary_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a,
                  base64_binary_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls,
                  base64_binary_template<C> const& x)
      {
        ls.os_ << x;
      }


      // hex_binary
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, hex_binary_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, hex_binary_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls,
                  hex_binary_template<C> const& x)
      {
        ls.os_ << x;
      }


      // date
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, date_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, date_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, date_template<C> const& x)
      {
        ls.os_ << x;
      }


      // date_time
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, date_time_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, date_time_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, date_time_template<C> const& x)
      {
        ls.os_ << x;
      }


      // duration
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, duration_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, duration_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, duration_template<C> const& x)
      {
        ls.os_ << x;
      }


      // day
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, day_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, day_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, day_template<C> const& x)
      {
        ls.os_ << x;
      }


      // month
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, month_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, month_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, month_template<C> const& x)
      {
        ls.os_ << x;
      }


      // month_day
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, month_day_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, month_day_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, month_day_template<C> const& x)
      {
        ls.os_ << x;
      }


      // year
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, year_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, year_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, year_template<C> const& x)
      {
        ls.os_ << x;
      }


      // year_month
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, year_month_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, year_month_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls,
                  year_month_template<C> const& x)
      {
        ls.os_ << x;
      }


      // time
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, time_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, time_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, time_template<C> const& x)
      {
        ls.os_ << x;
      }


      // entity
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, entity_template<C> const& x)
      {
        bits::insert (e, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, entity_template<C> const& x)
      {
        bits::insert (a, x);
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, entity_template<C> const& x)
      {
        ls.os_ << x;
      }


      // entities
      //
      template <typename C>
      inline void
      operator<< (xml::dom::element<C>& e, entities_template<C> const& v)
      {
        sequence<entity_template<C> > const& r (v);
        e << r;
      }

      template <typename C>
      inline void
      operator<< (xml::dom::attribute<C>& a, entities_template<C> const& v)
      {
        sequence<entity_template<C> > const& r (v);
        a << r;
      }

      template <typename C>
      inline void
      operator<< (xml::dom::list_stream<C>& ls, entities_template<C> const& v)
      {
        sequence<entity_template<C> > const& r (v);
        ls << r;
      }
    }
  }
}

#endif  // XSD_CXX_TREE_SERIALIZATION_HXX
