#include "equals.h"
#include "membertype.h"
#include <memory>

using namespace aka2;


bool aka2::element_equals(const void *lhs, const void *rhs, const element_op& op) {
  if (!attributes_equals(lhs, rhs, op.get_attribute_types()))
    return false;
  return op.equals(lhs, rhs);
}

bool aka2::attributes_equals(const void *lhs, const void *rhs, const attribute_types *attrtypes) {
  if (attrtypes == 0)
    return true;

  for (attribute_types::const_iterator it = attrtypes->begin();
       it != attrtypes->end(); ++it) {
    if (!it->second.equals(lhs, rhs))
      return false;
  }
  return true;
}

bool aka2::sequence_equals(const void *lhs, const void *rhs, const sequence_op &sop) {
  if (!attributes_equals(lhs, rhs, sop.get_attribute_types()))
    return false;

  const member_types &mtypes = sop.get_member_types();
  for (member_types::const_iterator it = mtypes.begin();
       it != mtypes.end(); ++it) {
    if (!it->equals(lhs, rhs))
      return false;
  }
  return true;
}


bool aka2::choice_equals(const void *lhs, const void *rhs, const choice_op &cop) {
  assert(cop.get_attribute_types() == 0);

  if (cop.size(lhs) != cop.size(rhs))
    return false;

  std::auto_ptr<item_iterator> lhsit(cop.get_iterator(lhs));
  std::auto_ptr<item_iterator> rhsit(cop.get_iterator(rhs));

  while (lhsit->has_next() && rhsit->has_next()) {
    const item *lhsitem = lhsit->next();
    const item *rhsitem = rhsit->next();

    if (&lhsitem->get_op() != &rhsitem->get_op())
      return false;

    if (!lhsitem->get_op().equals(lhsitem, rhsitem))
      return false;
  }
  return true;
}


bool aka2::all_equals(const void *lhs, const void *rhs, const all_op &aop) {

  if (!attributes_equals(lhs, rhs, aop.get_attribute_types()))
    return false;

  const member_map &mmap = aop.get_member_map();
  for (member_map::const_iterator it = mmap.begin(); it != mmap.end(); ++it) {
    if (!it->second.equals(lhs, rhs))
      return false;
  }
  return true;
}

bool aka2::simpletype_equals(const void *lhs, const void *rhs, const simpletype_op& op) {
  return op.equals(lhs, rhs);
}

bool aka2::array_equals(const void *lhs, const void *rhs, 
			const array_op &aop, const element_op &vop) {

  if (aop.empty(lhs) && aop.empty(rhs))
    return true;

  if (aop.size(lhs) != aop.size(rhs))
    return false;

  std::auto_ptr<array_iterator> lhsit(aop.get_iterator(lhs));
  std::auto_ptr<array_iterator> rhsit(aop.get_iterator(rhs));

  while (lhsit->has_next() && rhsit->has_next()) {
    const void *lhsitem = lhsit->next();
    const void *rhsitem = rhsit->next();
    if (!vop.equals(lhsitem, rhsitem))
      return false;
  }
  return true;
}

bool aka2::simplecontent_equals(const void *lhs, const void *rhs, const simplecontent_op &sop) {
  if (!attributes_equals(lhs, rhs, sop.get_attribute_types()))
    return false;
  const member_type &mtype = sop.get_valuetype();
  return mtype.equals(lhs, rhs);
}

bool aka2::ptrmember_equals(const void *lhs, const void *rhs, const ptrmember_op &pop) {
  if (pop.is_null(lhs) && pop.is_null(rhs))
    return true;
  if (pop.is_null(lhs) || pop.is_null(rhs))
    return false;

  // Both must be non-null value.
  const void *lhsval = pop.dereference(lhs);
  const void *rhsval = pop.dereference(rhs);
  return pop.get_value_op().equals(lhsval, rhsval);
}
