#include "ptrmember_handler.h"

#include "sequence_handler.h"
#include "choice_handler.h"
#include "all_handler.h"
#include "simplecontent_handler.h"
#include "simpletype_handler.h"

#include "../classes/traits.h"
#include "../classes/membertype.h"

#include <cassert>

using namespace aka2;

ptrmember_handler::ptrmember_handler(const qname &tagname, 
				     void *e,
				     int depth,
				     const ptrmember_op &pop, 
				     const occurence &occ,
				     bool is_element,
				     parser_context &context) 
  : handler(context, depth, tagname), ptrmember_(e), 
    e_(0), pop_(pop), occurence_(occ), is_element_(is_element), appeared_(false) {
}


parse_result ptrmember_handler::query_element(const qname &tagname, const attribute_values &attrs, 
					      const global_attributes &gattrs) {
  
  if (is_element_)
    return parse_element(tagname, attrs, gattrs);
  else
    return find_particle(tagname, attrs, gattrs);
}

parse_result ptrmember_handler::parse_element(const qname &tagname, const attribute_values &attrs, 
					      const global_attributes &gattrs) {

  if (tagname != tagname_) {
    if (appeared_)
      return skip;
    return occurence_.in_range(0) ? skip : error;
  }

  const element_op &op = pop_.get_value_op();
  e_ = pop_.create_member(ptrmember_);

  handler *handler = 0;

  switch (op.get_schematype()) {
  case sequence_id:
  case choice_id:
  case all_id: {
    handler = create_particle_handler(tagname, e_, op, 
				      depth_ + 1, occurence_); // item element.
    return ok;
  }
  case simplecontent_id:
  case simpletype_id:
  case any_id : {
    handler = create_element_handler(tagname, e_, op, 
				     depth_ + 1, occurence_); // item element.
    return ok;
  }
  case array_id:
  case ptrmember_id:
  default:
    assert(!"Must not reach here.");
  }
  return error;
}

parse_result ptrmember_handler::find_particle(const qname &tagname, const attribute_values &attrs, 
					      const global_attributes &gattrs) {

  const element_op &op = pop_.get_value_op();
  e_ = op.create();

  handler *handler = 0;

  switch (op.get_schematype()) {
  case sequence_id:
  case choice_id: {
    handler = create_particle_handler(tagname, e_, op, depth_, occurence_);
    parse_result res = handler->query_element(tagname, attrs, gattrs);
    return res;
  }
  case all_id: 
  case simplecontent_id:
  case simpletype_id:
  case any_id : 
  case array_id: // array should not be under ptrmember.
  case ptrmember_id: // nested ptrmember has no meaning.
  default:
    assert(!"Must not reach here.");
  }
  return error;
}

parse_result ptrmember_handler::end_element(const qname &tagname) {
  if (appeared_)
    return ok;
  return occurence_.in_range(0) ? ok : error;
}


bool ptrmember_handler::parse_entity(const std::string &entity, 
				 const global_attributes &gattrs) {
  return true;
}

memberpair ptrmember_handler::get_element() {
  return memberpair(ptrmember_, pop_);
}

void ptrmember_handler::receive_child(const memberpair &mpair) {
  assert(&pop_.get_value_op() == &mpair.op_);
  assert(e_ == mpair.e_);
  appeared_ = true;
  e_ = 0;
}

bool ptrmember_handler::can_skip() {
  return occurence_.in_range(0);
}

void ptrmember_handler::abort() {
  pop_.get_value_op().destroy(e_);
  e_ = 0;
}
