#include "all_handler.h"

#include "sequence_handler.h"
#include "choice_handler.h"
#include "simpletype_handler.h"
#include "simplecontent_handler.h"
#include "ptrmember_handler.h"
#include "../classes/construct.h"
#include "../classes/destruct.h"

#include <cassert>

using namespace aka2;

all_handler::all_handler(const qname &tagname, void *all, int depth,
			 const all_op &aop,
			 parser_context &context)  
  : handler(context, depth, tagname) , all_(all), aop_(aop) {
  mmap_ = aop.get_member_map();
  all_construct(all, aop);
}


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

  current_ = mmap_.find(tagname);
  if (current_ == mmap_.end())
    return error; // element specified by tagname not found.

  const member_type &mtype = current_->second;
  assert(mtype.is_element());
  parse_result res = parse_element(mtype, attrs, gattrs);
  return res;
}


parse_result all_handler::parse_element(const member_type &mtype, const attribute_values &attrs, 
  const global_attributes &gattrs) {

  memberpair mpair = mtype.get_member(all_); 
  schematype_id id = mpair.op_.get_schematype();
  void *memelm = mpair.e_;
  const element_op *memberop = &mpair.op_;

  // Branch according to the member type.
  switch (id) {
  case sequence_id:
  case choice_id:
  case all_id:  {
    create_particle_handler(mtype.get_name(), memelm, *memberop, depth_ + 1, 
			    mtype.get_occurrence());
    break;
  }
  case simpletype_id:
  case simplecontent_id: {
    mtype.set_member_to_default(all_);
    create_element_handler(mtype.get_name(), memelm, *memberop, depth_ + 1, 
			   mtype.get_occurrence());
    break;
  }
  case ptrmember_id: {
    handler *h = create_ptrmember_handler(mtype.get_name(), memelm, 
					  static_cast<const ptrmember_op&>(*memberop),
					  depth_, mtype.get_occurrence(), true);
    parse_result res = h->query_element(mtype.get_name(), attrs, gattrs);
    assert(res == ok);
    break;
  }
  case array_id:
  case any_id:
  case enclose_id: 
  case disclose_id:
  default:
    assert(!"Internal error.  Must not reach here.");
  }
  return ok;
}


parse_result all_handler::end_element(const qname &tagname){
  // No element left.  OK to end parse. 
  if (can_skip())
    return ok;
  return error;
}


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


memberpair all_handler::get_element() {
  return memberpair(all_, aop_);
}

void all_handler::receive_child(const memberpair &mpair) {
  //  assert(&mpair.op_ == &current_->second.get_member(all_).op_);
  mmap_.erase(current_->first);
  current_ = mmap_.end();
}

bool all_handler::can_skip() {

  for (member_map::const_iterator it = mmap_.begin();
       it != mmap_.end(); ++it) {
    const member_type &mtype = it->second;
    if (!mtype.get_occurrence().in_range(0))
      return false;
  }
  return true;
}

void all_handler::abort() {
  all_destruct(all_, aop_);
}
