// 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
      {
      public:
        one (type* container)
            : container_ (container)
        {
        }

        one (X const& y, type* container)
            : container_ (container)
        {
          operator() (y);
        }

        one (one<X> const& y, type* container)
            : container_ (container)
        {
          operator() (y ());
        }

        one<X>&
        operator= (one<X> const& y)
        {
          if (x_.get () == y.x_.get ())
            return *this;

          operator() (y ());

          return *this;
        }

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

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

        void
        operator() (X const& y)
        {
          if (x_.get () != 0)
            *x_ = y;
          else
            x_ = std::auto_ptr<X> (new X (y));

          traits<X>::set_container (*x_, container_);
        }

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


      //
      //
      template<typename X>
      class optional
      {
      public:
        optional (type* container)
            : container_ (container)
        {
        }

        optional (optional<X> const& y, type* container)
            : container_ (container)
        {
          if (y.present ())
            operator() (y ());
        }

        optional<X>&
        operator= (optional<X> const& y)
        {
          if (x_.get () == y.x_.get ())
            return *this;

          if (y.present ())
            operator() (y ());
          else
            reset ();

          return *this;
        }

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

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

        void
        operator() (X const& y)
        {
          if (present ())
            *x_ = y;
          else
            x_ = std::auto_ptr<X> (new X (y));

          traits<X>::set_container (*x_, container_);
        }

        bool
        present () const
        {
          return x_.get () != 0;
        }

        void
        reset ()
        {
          x_.reset ();
        }

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


      //
      //
      template<typename X>
      class sequence
      {
      public:
        sequence (type* container)
            : container_ (container), v_ (container)
        {
        }

        sequence (sequence<X> const& y, type* container)
            : container_ (container), v_ (y.v_, container)
        {
        }

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

          return *this;
        }

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

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

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

      protected:
        type* container_;
        vector<X> v_;
      };
    }
  }
}

#endif  // XSD_CXX_TREE_FUNCTORS_HXX
