/* -*- c++ -*- */
#include "array_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>

namespace aka2 {

array_handler::array_handler(const qname &tagname, 
			     void *e,
			     int depth,
			     const array_op &aop, 
			     const occurrence &occ,
			     bool is_element,
			     parser_context &context) 
  : handler(context, depth, tagname), array_(e), 
    e_(0), aop_(aop), occurrence_(occ), is_element_(is_element), count_(0) {
}

array_handler::~array_handler() {
  if (e_ != 0)
    abort();
}


parse_result array_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 array_handler::parse_element(const qname &tagname, const attribute_values &attrs, 
					  const global_attributes &gattrs) {

  if (tagname != tagname_)
    return occurrence_.in_range(count_) ? skip : error;

  const element_op &op = aop_.get_item_op();
  e_ = op.create();

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

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

  const element_op &op = aop_.get_item_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_, occurrence_);
    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: // nested array does not have any meaning. !!!!!
  default:
    assert(!"Must not reach here.");
  }
  return error;
}

parse_result array_handler::end_element(const qname &tagname) {
  return occurrence_.in_range(count_) ? ok : error;
}


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

memberpair array_handler::get_element() {
  return memberpair(array_, aop_);
}

void array_handler::receive_child(const memberpair &mpair) {
  assert(&aop_.get_item_op() == &mpair.op_);
  assert(e_ == mpair.e_);
  aop_.push(array_, mpair.e_);
  aop_.get_item_op().destroy(mpair.e_);
  ++count_; // Increase occurrence count.
  e_ = 0;
}

bool array_handler::can_skip() {
  return occurrence_.in_range(count_);
}

void array_handler::abort() {
  aop_.get_item_op().destroy(e_);
  e_ = 0;
}

} // namespace aka2
