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

#ifndef LIBRARY_PARSER_HXX
#define LIBRARY_PARSER_HXX

#include "library.hxx"
#include "library-parser-templates.hxx"

namespace library
{
  namespace parser
  {
    //
    //
    typedef xml_schema::parser::unsigned_int isbn;


    // We would like to re-use the string parser in implementation
    // of the title parser. Since the return types of our post()
    // functions are not covariant, we will need to "rename" the
    // title::post function before we can mix the two implementation
    // together. For more information see the mix-in example.
    //
    struct title_base: templates::title<library::title,
                                        std::string> // lang
    {
      virtual library::title
      post_title () = 0;

      virtual library::title
      post ()
      {
        return post_title ();
      }
    };

    struct title: title_base,
                  xml_schema::parser::string
    {
      virtual void
      pre ()
      {
        title_.clear ();
        title_.lang ("");
      }

      virtual void
      lang (const std::string& lang)
      {
        title_.lang (lang);
      }

      virtual library::title
      post_title ()
      {
        title_.assign (xml_schema::parser::string::post ());
        return title_;
      }

    private:
      library::title title_;
    };


    //
    //
    struct genre: templates::genre<library::genre>
    {
      virtual void
      _characters (const std::string& v)
      {
        if (v == "romance") genre_ = romance; else
        if (v == "fiction") genre_ = fiction; else
        if (v == "horror") genre_ = horror; else
        if (v == "history") genre_ = history; else
        if (v == "philosophy") genre_ = philosophy;
      }

      virtual library::genre
      post ()
      {
        return genre_;
      }

    private:
      library::genre genre_;
    };


    //
    //
    struct person: templates::person<library::person,
                                     std::string, // name
                                     std::string, // born
                                     std::string> // died
    {
      virtual void
      pre ()
      {
        person_.name ("");
        person_.born ("");
        person_.died ("");
      }

      virtual void
      name (const std::string& name)
      {
        person_.name (name);
      }

      virtual void
      born (const std::string& born)
      {
        person_.born (born);
      }

      virtual void
      died (const std::string& died)
      {
        person_.died (died);
      }

      virtual library::person
      post ()
      {
        return person_;
      }

    private:
      library::person person_;
    };


    // We would like to re-use the person parser in implementation
    // of the author parser. Since the return types of our post()
    // functions are not covariant, we will need to "rename" the
    // author::post function before we can mix the two implementation
    // together. For more information see the mix-in example.
    //
    struct author_base: templates::author<library::author,
                                          std::string, // name
                                          std::string, // born
                                          std::string, // died
                                          std::string> // recommends
    {
      virtual library::author
      post_author () = 0;

      virtual library::author
      post ()
      {
        return post_author ();
      }
    };

    struct author: author_base,
                   person
    {
      virtual void
      pre ()
      {
        person::pre ();
        author_.recommends ("");
      }

      virtual void
      recommends (const std::string& recommends)
      {
        author_.recommends (recommends);
      }

      virtual library::author
      post_author ()
      {
        library::person p (person::post ());

        author_.name (p.name ());
        author_.born (p.born ());
        author_.died (p.died ());

        return author_;
      }

    private:
      library::author author_;
    };


    //
    //
    struct book: templates::book<library::book,
                                 library::isbn,   // isbn
                                 library::title,  // title
                                 library::genre,  // genre
                                 library::author, // author
                                 bool,            // available
                                 std::string>     // id
    {
      virtual void
      pre ()
      {
        book_.author ().clear ();
        book_.available (false);
        book_.id ("");
      }

      virtual void
      isbn (const library::isbn& isbn)
      {
        book_.isbn (isbn);
      }

      virtual void
      title (const library::title& title)
      {
        book_.title (title);
      }

      virtual void
      genre (const library::genre& genre)
      {
        book_.genre (genre);
      }

      virtual void
      author (const library::author& author)
      {
        book_.author ().push_back (author);
      }

      virtual void
      available (const bool& available)
      {
        book_.available (available);
      }

      virtual void
      id (const std::string& id)
      {
        book_.id (id);
      }

      virtual library::book
      post ()
      {
        return book_;
      }

    private:
      library::book book_;
    };


    //
    //
    struct catalog: templates::catalog<library::catalog,
                                       library::book>
    {
      virtual void
      pre ()
      {
        catalog_.clear ();
      }

      virtual void
      book (const library::book& book)
      {
        catalog_.push_back (book);
      }

      virtual library::catalog
      post ()
      {
        return catalog_;
      }

    private:
      library::catalog catalog_;
    };
  }
}

#endif // LIBRARY_PARSER_HXX
