#include "membertype.h"
#include "item.h"
#include "model_check.h"
#include "membertype.h"
#include "item.h"

using namespace aka2;

namespace {

  bool check_occurs(const element_props &props, const element_op &op) {

    switch (op.get_schematype()) {
    case sequence_id: {
      if (props.is_element())
	return true;
      const sequence_op &sop = static_cast<const sequence_op&>(op);
      const member_types &mtypes = sop.get_member_types();
      for (member_types::const_iterator it = mtypes.begin();
	   it != mtypes.end(); ++it) {
	if (check_occurs(*it, it->op()))
	  return true;
      }
      return false;
    }
    case all_id: {
      if (props.is_element())
	return true; 
      const all_op &aop = static_cast<const all_op&>(op);
      const member_map &mtypes = aop.get_member_map();
      for (member_map::const_iterator it = mtypes.begin();
	   it != mtypes.end(); ++it) {
	if (it->second.get_occurrence().minOccurs_ > 0)
	  return true;
      }
      return false;
    }
    case choice_id: {
      if (props.is_element())
	return true;
      if (props.get_occurrence().minOccurs_ == 0)
	return false;
      const choice_op &cop = static_cast<const choice_op&>(op);
      const itemtypes &itypes = cop.get_itemtypes();
      for (itemtypes::const_iterator it = itypes.begin();
	   it != itypes.end(); ++it) {
	if (!check_occurs(it->second, it->second.op()))
	  return false;
      }
      return true;
    }
    case array_id: {
      if (props.get_occurrence().minOccurs_ == 0)
	return false;
      const array_op &pop = static_cast<const array_op&>(props.op());
      return check_occurs(props, pop.get_item_op());
    }
    case ptrmember_id: {
      if (props.get_occurrence().minOccurs_ == 0)
	return false;
      const ptrmember_op &pop = static_cast<const ptrmember_op&>(props.op());
      return check_occurs(props, pop.get_value_op());
    }
    case any_array_id:
      return props.get_occurrence().minOccurs_ != 0;
    case any_id:
      return true;
    case simpletype_id:
    case simplecontent_id:
    case enclose_id:
    case disclose_id:
    case any_attribute_id:
    case fixed_id: // fixed should be always an element.  akaxiso restriction.!!!!!
      assert(props.is_element());
      return true;
    }
    assert(!"Must not reach here.");
    return false;
  }
}

void aka2::correct_item_occurrence(itemtypes &itypes) {

  for (itemtypes::iterator it = itypes.begin();
       it != itypes.end(); ++it) {
    element_props &props = it->second;
    // Guard condition.
    // If corrected, minOccurs_ == 0. If correction may be needed, minOccurs_ != 0.
    if (props.get_occurrence().minOccurs_ == 0)
      continue;
    bool res = check_occurs(props, props.op());
    if (!res)
      props.set_occurrence(0, props.get_occurrence().maxOccurs_);
  }

}


void aka2::correct_member_occurrence(member_types &mtypes) {

  for (member_types::iterator it = mtypes.begin();
       it != mtypes.end(); ++it) {
    element_props &props = *it;
    // Guard condition.
    // If corrected, minOccurs_ == 0. If correction may be needed, minOccurs_ != 0.
    if (props.get_occurrence().minOccurs_ == 0)
      continue;
    bool res = check_occurs(props, props.op());
    if (!res)
      props.set_occurrence(0, props.get_occurrence().maxOccurs_);
  }
}

bool aka2::check_occurrence(schematype_id id, const aka::occurrence &occ) {
  if (id == array_id)
    return true;
  if (id == choice_id)
    return true;
  if (id == ptrmember_id)
    return is_ptrmember_occurrence(occ);
  if (!occ.is_array())
    return true;
  return false;
}

bool aka2::check_has_default(schematype_id id) {
  return  (id == simpletype_id) || (id == fixed_id);
}

bool aka2::is_ptrmember_occurrence(const aka::occurrence &occ) {
  return ((occ.minOccurs_ == 0) || (occ.minOccurs_ == 1))
    && (occ.maxOccurs_ == 1);
}

bool aka2::is_all_occurrence(const aka::occurrence &occ) {
  return ((occ.minOccurs_ == 0) || (occ.minOccurs_ == 1))
    && (occ.maxOccurs_ == 1);
}
