#include "choice_handler.h"

#include "sequence_handler.h"
#include "all_handler.h"
#include "simplecontent_handler.h"
#include "simpletype_handler.h"
#include "array_handler.h"
#include "../classes/item.h"
#include "any_handler.h"

#include <cassert>

using namespace aka2;
  
choice_handler::choice_handler(const qname &tagname, void *cho, int depth,
			       const choice_op &cop, const occurrence &occ,
			       parser_context &context) 
  : handler(context, depth, tagname), 
    cho_(cho), cop_(cop), occurrence_(occ), count_(0),
    error_(false),
    itypes_(cop_.get_itemtypes()){
  current_ = itypes_.end();
}

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


parse_result choice_handler::query_element(const qname &tagname, const attribute_values &attrs, 
					   const global_attributes &gattrs) {

  itemtypes::const_iterator it = itypes_.find(tagname);
  if (it != itypes_.end()) {
    current_ = it;
    return parse_element(attrs, gattrs);
  }

#if 0
  parse_result res = find_particle(tagname, attrs, gattrs);
  if (res == ok)
    return ok;
  //  if (res == skip)
#endif
  
  if (occurrence_.in_range(count_))
    return skip;

  context_.report("Element not found, or Wrong occurrence.");
  return error;
}


parse_result choice_handler::parse_element(const attribute_values &attrs,
					   const global_attributes &gattrs) {


  const element_op &iop = current_->second.get_op();
  const qname &tagname = current_->first;
  const itemtype &itype = current_->second;

  e_ = iop.create();

  handler *handler = 0;
  switch (iop.get_schematype()) {
  case sequence_id:
  case choice_id:
  case all_id: {
    handler = create_particle_handler(tagname, e_, iop, depth_ + 1, 
				      itype.get_occurrence());
    break;
  }
  case simplecontent_id:
  case simpletype_id: {
    handler = create_element_handler(tagname, e_, iop, depth_ + 1, 
				     itype.get_occurrence());
    break;
  }
  case array_id: {
    handler = create_array_handler(tagname, e_, 
				   static_cast<const array_op&>(iop), 
				   depth_, itype.get_occurrence(), true);
    parse_result res = handler->query_element(tagname, attrs, gattrs);
    assert(res == ok);
    break;
  } 
  case any_id:
  default:
    assert(!"Must not reach here.");
  }
  return ok;
}

parse_result choice_handler::find_particle(const qname &tagname, const attribute_values &attrs,
					   const global_attributes &gattrs) {
    assert(!"To be implemented.");
    return error; // !!!!!!!!!!!!!!!!!!
}


parse_result choice_handler::end_element(const qname &tagname) {
  if (occurrence_.in_range(count_))
    return ok;
  context_.report_wrong_occurrence("choice", occurrence_, count_);
  return error;
}


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

memberpair choice_handler::get_element() {
  return memberpair(cho_, cop_);
}

void choice_handler::receive_child(const memberpair &mpair) {
  assert(&mpair.op_ == &current_->second.get_op());
  item i(current_->first, mpair.e_, current_->second.get_op());
  cop_.push(cho_, i);
  ++count_; // occurrence increased.
  e_ = 0; // Item is passed to choice object.  Clear the pointer.
}

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

void choice_handler::abort() {
  if (current_ != itypes_.end()) {
    const element_op &iop = current_->second.get_op();
    iop.destroy(e_);
  }
  e_ = 0;
}
