#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 "array_handler.h"
#include "fixed_handler.h"
#include "../classes/construct.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){
  
  current_ = mmap_.find(tagname);
  if (current_ == mmap_.end()) {
    // element specified by tagname not found.
    if (can_skip()) 
      return skip;
    context_.report_no_element(tagname, __FILE__, __LINE__);
    return error;
  }
  const member_type &mtype = current_->second;
  assert(mtype.is_element());
  parse_result res = parse_element(mtype, attrs);
  return res;
}

parse_result all_handler::query_next(const qname &tagname, const attribute_values &attrs){

  current_ = mmap_.find(tagname);
  if (current_ == mmap_.end()) {
    // element specified by tagname not found.
    return can_skip() ? skip : error;
  }
  return ok;
}


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

  const element_op &memberop = mtype.op();
  cache_.set(all_, mtype.op(), mtype.getter());
  cache_.prepare(true); // members or members in members may have defaults.
  void *memelm = cache_.value();

  // Branch according to the member type.
  switch (mtype.get_schematype()) {
  case sequence_id:
  case choice_id:
  case all_id:  {
    create_particle_handler(mtype.get_name(), memelm, memberop, depth_ + 1, 
			    mtype);
    break;
  }
  case simpletype_id:
  case simplecontent_id: {
    create_simple_handler(mtype.get_name(), memelm, memberop, depth_ + 1, 
			   mtype);
    break;
  }
  case ptrmember_id: {
    handler *h = create_ptrmember_handler(mtype.get_name(), memelm, 
					  static_cast<const ptrmember_op&>(memberop),
					  depth_, mtype);
    parse_result res = h->query_element(mtype.get_name(), attrs);
    assert(res == ok);
    break;
  }
  case array_id: {
    handler *h = create_array_handler(mtype.get_name(), memelm, 
				      static_cast<const array_op&>(memberop),
				      depth_, mtype);
    parse_result res = h->query_element(mtype.get_name(), attrs);
    assert(res == ok);
    break;
  }
  case fixed_id: { // @fixed is always simpletype. (spec. restriction of akaxiso.)
    create_fixed_handler(mtype.get_name(), 0,
			 static_cast<const fixed_op&>(memberop), 
			 depth_ + 1, mtype);
    break;
  }
  case any_id:     // <xs:any> should not appear under <xs:all>.
  case any_array_id:
  case enclose_id: // use of enclose/disclose is restricted for sequence.
  case disclose_id: 
  case any_attribute_id: // attribute is not handled here.
    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;
  context_.report_no_element(tagname, __FILE__, __LINE__);
  return error;
}


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


node all_handler::get_node() {
  return node(all_, aop_);
}

void all_handler::receive_child(const node &child) {
  assert(&child.op() == &current_->second.op());
  cache_.flush();
  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() {
  cache_.clear();
}
