/* -*- 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 <akaxiso/classes/any.h>

#include <stack>

namespace aka2 {

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

  struct handler;
  typedef shared_ptr<handler> handler_ptr;
  typedef std::stack<handler_ptr> handler_stack;
  class array_handler;
  class ptrmember_handler;
  class fixed_handler;

  struct parser_context {
    parser_context(global_attributes &gattrs) : 
      locator_(new locator()), source_name_("(not specified)"), gattrs_(&gattrs),
      silent_(false), ignore_any_(false) {}
    ~parser_context();

    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 set_source_name(const std::string &source_name) {
      source_name_ = source_name;
    }

    global_attributes &gattrs() const { return *gattrs_; }
    handler_stack get_stack() { return handlers_; }
    void set_stack(handler_stack &to_set) { handlers_ = to_set; }


    void report(const std::string &message, 
		const char *filename, const unsigned long linenum) const;
    void report_wrong_occurrence(const occurrence &occ, int actual,
				 const char *filename, const unsigned long linenum) const;
    void report_no_element(const qname &tagname, 
			   const char *filename, const unsigned long linenum) const ;

    void silent(bool val) { silent_ =val; }

    bool ignore_any() const { return ignore_any_; }
    void set_ignore_any(bool val) { ignore_any_ = val; }

  private:
    handler_stack handlers_;
    const locator *locator_;
    std::string source_name_;
    global_attributes *gattrs_;
    bool silent_;
    bool ignore_any_;
  };


  struct handler {
    virtual ~handler(){}
    virtual parse_result query_element(const qname &tagname, const attribute_values &attrs) = 0;
    virtual parse_result end_element(const qname &tagname) = 0;
    virtual parse_result query_next(const qname &tagname, const attribute_values &attrs) = 0;
    // Mainly used by simpletypes.
    virtual bool parse_entity(const std::string &entity) = 0;

    // Mainly used for choices.
    virtual node get_node() = 0;
    virtual void receive_child(const node &child) = 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);

    handler* create_particle_handler(const qname &tagname, void *e, const element_op &op,
				     int depth, const element_props &props);
    handler* create_simple_handler(const qname &tagname, void *e, const element_op &op,
				    int depth, const element_props &props);
    array_handler* create_array_handler(const qname &tagname, void *e, const array_op &op,
					int depth, const element_props &props, bool is_element);
    ptrmember_handler* create_ptrmember_handler(const qname &tagname, void *e, 
						const ptrmember_op &op,
						int depth, const element_props &props, 
						bool is_element);
    fixed_handler *create_fixed_handler(const qname &tagname,
					void *e,
					const fixed_op &op,
					int depth,
					const element_props &props);

    handler *create_any_handler(const qname &tagname, any &an, int depth);
    handler *create_any_array_handler(const qname &tagname, any_array &anys, 
				      int depth, const occurrence &occ);
    static handler* create_handler(const qname &tagname, void *e, const element_op &op,
				   int depth, const element_props &props, 
				   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){}

    bool seek_forward(const qname &tagname, const attribute_values &attrs);

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

} // namespace aka2

#endif /* AKAXISO_HANDLER_H__ */
