// file      : xsd/cxx/tree/functors.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_FUNCTORS_HXX
#define XSD_CXX_TREE_FUNCTORS_HXX

#include <memory> // std::auto_ptr

#include <xsd/cxx/tree/elements.hxx>
#include <xsd/cxx/tree/traits.hxx>

namespace xsd
{
  namespace cxx
  {
    namespace tree
    {
      //
      //
      template<typename X>
      class one_functor
      {
      public:
        one_functor (flags f, type* container)
            : flags_ (f), container_ (container)
        {
        }

        one_functor (X const& y, flags f, type* container)
            : flags_ (f), container_ (container)
        {
          operator() (y);
        }

        one_functor (one_functor<X> const& y, flags f, type* container)
            : flags_ (f), container_ (container)
        {
          operator() (y ());
        }

        one_functor<X>&
        operator= (one_functor<X> const& y)
        {
          if (this == &y)
            return *this;

          operator() (y ());

          return *this;
        }

      public:
        X const&
        operator() () const
        {
          return *x_;
        }

        X&
        operator() ()
        {
          return *x_;
        }

        void
        operator() (X const& y)
        {
          // We always do a fresh copy because X may not be y's
          // dynamic type.
          //
          x_ = traits<X>::clone (y, flags_, container_);
        }

        void
        operator () (std::auto_ptr<X> y)
        {
          if (traits<X>::same_container (*y, container_))
            x_ = y;
          else
            operator() (*y);
        }

        // Internal interface - subject to change.
        //
      public:
        bool
        _present () const
        {
          return x_.get () != 0;
        }

      protected:
        flags flags_;
        type* container_;
        std::auto_ptr<X> x_;
      };


      //
      //
      template<typename X>
      class optional_functor
      {
      public:

      public:
        optional_functor (flags f, type* container)
            : x_ (f, container)
        {
        }

        optional_functor (optional_functor<X> const& y,
                          flags f,
                          type* container)
            : x_ (y.x_, f, container)
        {
        }

        optional_functor<X>&
        operator= (optional_functor<X> const& y)
        {
          x_ = y.x_;
          return *this;
        }

      public:
        optional<X> const&
        operator() () const
        {
          return x_;
        }

        optional<X>&
        operator() ()
        {
          return x_;
        }

        void
        operator() (X const& y)
        {
          x_.set (y);
        }

        void
        operator() (optional<X> const& y)
        {
          x_ = y;
        }

        void
        operator () (std::auto_ptr<X> y)
        {
          x_.set (y);
        }

      protected:
        optional<X> x_;
      };


      //
      //
      template<typename X>
      class sequence_functor
      {
      public:
        sequence_functor (flags f, type* container)
            : v_ (f, container)
        {
        }

        sequence_functor (sequence_functor<X> const& y,
                          flags f,
                          type* container)
            : v_ (y.v_, f, container)
        {
        }

        sequence_functor<X>&
        operator= (sequence_functor<X> const& y)
        {
          v_ = y.v_;

          return *this;
        }

      public:
        sequence<X> const&
        operator() () const
        {
          return v_;
        }

        sequence<X>&
        operator() ()
        {
          return v_;
        }

        void
        operator() (sequence<X> const& y)
        {
          v_ = y;
        }

      protected:
        sequence<X> v_;
      };
    }
  }
}

#endif  // XSD_CXX_TREE_FUNCTORS_HXX
