/* -*- c++ -*- */
#ifndef AKAXISO_HANDLER_H__
#define AKAXISO_HANDLER_H__

#include <akaxiso/classes/types.h>
#include <akaxiso/classes/qname.h>
#include <akaxiso/classes/global_attributes.h>
#include <akaxiso/parser/locator.h>
#include <akaxiso/classes/traits.h>
#include <akaxiso/classes/member.h>
#include <akaxiso/classes/membertype.h>

#include <stack>

namespace aka2 {

  enum parse_result {
    ok = 0,
    skip = 1,
    error = 2
  };

  struct handler;
  typedef shared_ptr<handler> handler_ptr;
  class array_handler;
  class ptrmember_handler;

  struct parser_context {
    typedef std::stack<handler_ptr> handlers;
    parser_context() : 
      locator_(new locator()), source_name_("(not specified)"){}
    ~parser_context() { delete locator_; }

    void push(handler* h) { handlers_.push(handler_ptr(h)); }
    handler_ptr top() { return handlers_.top(); }
    void pop() { handlers_.pop(); }
    bool empty() const { return handlers_.empty(); }

    const locator* get_locator() const { return locator_; }
    void set_locator(const locator *loc) {
      delete locator_;
      locator_ = loc;
    }
    void report(const std::string &message) const;
    void set_source_name(const std::string &source_name) {
      source_name_ = source_name;
    }
    void raise_error(const std::string &message, 
		     const char *filename, const unsigned long linenum);
    void report_wrong_occurrence(const std::string &message, const occurrence &occ, int actual);
  private:
    handlers handlers_;
    const locator *locator_;
    std::string source_name_;
  };


  struct handler {
    virtual ~handler(){}
    virtual parse_result query_element(const qname &tagname, const attribute_values &attrs, 
				       const global_attributes &gattrs) = 0;
    virtual parse_result end_element(const qname &tagname) = 0;

    // Mainly used by simpletypes.
    virtual bool parse_entity(const std::string &entity, const global_attributes &gattrs) = 0;

    // Mainly used for choices.
    virtual memberpair get_element() = 0;
    virtual void receive_child(const memberpair &mpair) = 0;
    virtual bool can_skip() = 0;
    virtual void abort() = 0; 

    const qname &get_tagname() const { return tagname_; }
    int get_depth() const { return depth_; }

    void parse_attributes(void *e, const element_op &op, attribute_values &attrs, 
				 const global_attributes &gattrs);

    handler* create_particle_handler(const qname &tagname, void *e, const element_op &op,
				     int depth, const occurrence &occ);
    handler* create_element_handler(const qname &tagname, void *e, const element_op &op,
				    int depth, const occurrence &occ);
    array_handler* create_array_handler(const qname &tagname, void *e, const array_op &op,
					int depth, const occurrence &occ, bool is_element);
    ptrmember_handler* create_ptrmember_handler(const qname &tagname, void *e, 
						const ptrmember_op &op,
						int depth, const occurrence &occ, bool is_element);
    handler *create_fixed_handler(const qname &tagname, int depth, const member_type &mtype);
    handler *create_fixed_array_handler(const qname &tagname, int depth, const member_type &mtype);


    static handler *create_root_handler(const qname &tagname, void *e, const element_op &op,
					const occurrence &occ, 
					parser_context &context);

 protected:
    handler(parser_context &context, int depth, const qname &tagname) 
      : context_(context), depth_(depth), tagname_(tagname){}
    handler(const handler &h, int depth, const qname &tagname) : 
      context_(h.context_), depth_(depth), tagname_(tagname){}

    static handler* create_handler(const qname &tagname, void *e, const element_op &op,
				   int depth, const occurrence &occ, 
				   parser_context &context);

    parser_context &context_;
    int depth_;
    const qname tagname_;
  };

} // namespace aka2

#endif /* AKAXISO_HANDLER_H__ */
