// file      : examples/cxx/parser/mix-in/driver.cxx
// author    : Boris Kolpackov <boris@codesynthesis.com>
// copyright : not copyrighted - public domain

#include <memory>
#include <iostream>

#include "schema-parser-templates.hxx"

using std::cerr;
using std::endl;
using std::auto_ptr;
using std::boolalpha;


// Data types.
//

struct base_type
{
  bool
  a () const
  {
    return a_;
  }

  void
  a (bool v)
  {
    a_ = v;
  }

private:
  bool a_;
};

struct derived_type: base_type
{
  int
  b () const
  {
    return b_;
  }

  void
  b (int v)
  {
    b_ = v;
  }

private:
  int b_;
};


// The following four examples show how to mix-in implementations of
// base parsers into derived parsers. The examples differ in the types
// that the post() functions return. They cover covariant return types,
// non-covariant return types, same return type, and no return (void).
//


//
//
namespace covariant
{
  struct base_parser: parser_templates::base<base_type*,
                                             bool> // a
  {
    virtual void
    pre ()
    {
      base_.reset (new base_type);
    }

    virtual void
    a (const bool& v)
    {
      base_->a (v);
    }

    virtual base_type*
    post ()
    {
      return base_.release ();
    }

  protected:
    auto_ptr<base_type> base_;
  };


  struct derived_parser: base_parser,
                         parser_templates::derived<derived_type*,
                                                   bool, // a
                                                   int>  // b
  {
    virtual void
    pre ()
    {
      derived_ = new derived_type;
      base_.reset (derived_);
    }

    virtual void
    b (const int& v)
    {
      derived_->b (v);
    }

    virtual derived_type*
    post ()
    {
      base_.release ();
      return derived_;
    }

  protected:
    derived_type* derived_;
  };
}


// In this case the return types of post() functions are not covariant,
// therefore we will need to "rename" the derived::post function before
// we can mix the two implementation together.
//
namespace non_covariant
{
  struct base_parser: parser_templates::base<base_type,
                                             bool> // a
  {
    virtual void
    pre ()
    {
      a_ = false;
    }

    virtual void
    a (const bool& v)
    {
      a_ = v;
    }

    virtual base_type
    post ()
    {
      base_type r;
      r.a (a_);
      return r;
    }

  protected:
    bool a_;
  };


  struct derived_parser_base: parser_templates::derived<derived_type,
                                                        bool, // a
                                                        int>  // b
  {
    virtual derived_type
    post_derived () = 0;

    virtual derived_type
    post ()
    {
      return post_derived ();
    }
  };


  struct derived_parser: base_parser,
                         derived_parser_base
  {
    virtual void
    pre ()
    {
      base_parser::pre ();
      b_ = 0;
    }

    virtual void
    b (const int& v)
    {
      b_ = v;
    }

    virtual derived_type
    post_derived ()
    {
      derived_type r;
      r.a (a_);
      r.b (b_);
      return r;
    }

  protected:
    int b_;
  };
}


//
//
namespace same
{
  struct base_parser: parser_templates::base<int,
                                             bool> // a
  {
    virtual void
    pre ()
    {
      n_ = 0;
    }

    virtual void
    a (const bool& v)
    {
      cerr << "a: " << boolalpha << v << endl;
      ++n_;
    }

    virtual int
    post ()
    {
      return n_;
    }

  protected:
    int n_;
  };


  struct derived_parser: base_parser,
                         parser_templates::derived<int,
                                                   bool, // a
                                                   int>  // b
  {
    // pre() from base_parser is good enough.
    //

    virtual void
    b (const int& v)
    {
      cerr << "b: " << v << endl;
      ++n_;
    }

    virtual int
    post ()
    {
      // We don't have to override post() here but we can if we need
      // to. This is just for illustration.
      //
      return base_parser::post ();
    }
  };
}


// This case is similar to the previous one except that there is a
// default implementation for void post() that does nothing. So we
// don't have to provide our own if we don't want to.
//
//
namespace void_
{
  struct base_parser: parser_templates::base<void,
                                             bool> // a
  {
    virtual void
    a (const bool& v)
    {
      cerr << "a: " << boolalpha << v << endl;
    }
  };


  struct derived_parser: base_parser,
                         parser_templates::derived<void,
                                                   bool, // a
                                                   int>  // b
  {
    virtual void
    b (const int& v)
    {
      cerr << "b: " << v << endl;
    }
  };
}


int
main (int argc, char* argv[])
{
  if (argc != 2)
  {
    cerr << "usage: " << argv[0] << " instance.xml" << endl;
    return 1;
  }

  try
  {
    // Construct the parser.
    //
    xml_schema::boolean bool_p;
    xml_schema::int_ int_p;

    using xml_schema::document;


    // Covariant types.
    //
    {
      using namespace covariant;

      derived_parser derived_p;
      derived_p.parsers (bool_p, int_p);

      document<derived_type*> doc_p (derived_p, "root");

      auto_ptr<derived_type> d (doc_p.parse (argv[1]));

      cerr << "a: " << boolalpha << d->a () << endl;
      cerr << "b: " << d->b () << endl;
    }

    // Non-covariant types.
    //
    {
      using namespace non_covariant;

      derived_parser derived_p;
      derived_p.parsers (bool_p, int_p);

      document<derived_type> doc_p (derived_p, "root");

      derived_type d (doc_p.parse (argv[1]));

      cerr << "a: " << boolalpha << d.a () << endl;
      cerr << "b: " << d.b () << endl;
    }

    // Same type.
    //
    {
      using namespace same;

      derived_parser derived_p;
      derived_p.parsers (bool_p, int_p);

      document<int> doc_p (derived_p, "root");

      int n (doc_p.parse (argv[1]));

      cerr << "total: " << n << endl;
    }


    // Void.
    //
    {
      using namespace void_;

      derived_parser derived_p;
      derived_p.parsers (bool_p, int_p);

      document<void> doc_p (derived_p, "root");

      doc_p.parse (argv[1]);
    }
  }
  catch (const xml_schema::exception& e)
  {
    cerr << e << endl;
    return 1;
  }
  catch (const std::ios_base::failure&)
  {
    cerr << "io failure" << endl;
    return 1;
  }
}
