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

using namespace aka2;


void aka2::element_copy(void *dest, const void *src, const element_op& op) {
  attributes_copy(dest, src, op);
  op.copy(dest, src);
}

void aka2::attributes_copy(void *dest, const void *src, const element_op &op) {

  if (op.get_attribute_types() != 0) {
    const attribute_types &attrtypes = *op.get_attribute_types();
    for (attribute_types::const_iterator it = attrtypes.begin();
	 it != attrtypes.end(); ++it)
      it->second.copy(dest, src);
  }

  if (op.get_anyattr_type() != 0) {
    const any_member &amem = *op.get_anyattr_type();
    const_memberpair srcpair = amem.get_member(src);
    memberpair destpair = amem.get_member(dest);
    assert(&srcpair.op_ == &destpair.op_);
    destpair.op_.copy(dest, src);
  }
}

void aka2::sequence_copy(void *dest, const void *src, const sequence_op &sop) {
  attributes_copy(dest, src, sop);

  const member_types &mtypes = sop.get_member_types();
  for (member_types::const_iterator it = mtypes.begin();
       it != mtypes.end(); ++it)
    it->copy(dest, src);
}


void aka2::choice_copy(void *dest, const void *src, const choice_op &cop) {
  assert(cop.get_attribute_types() == 0);

  if (!cop.empty(dest))
    throw internal_error();

  std::auto_ptr<item_iterator> itemit(cop.get_iterator(src));

  while (itemit->has_next()) {
    const item *itemsrc = itemit->next();
    void *deste = itemsrc->get_op().replicate(itemsrc->element());
    item destitem(itemsrc->get_name(),
		  deste,
		  itemsrc->get_op());
    cop.push(dest, destitem);
  }
}


void aka2::all_copy(void *dest, const void *src, const all_op &aop) {

  attributes_copy(dest, src, aop);

  const member_map &mmap = aop.get_member_map();
  for (member_map::const_iterator it = mmap.begin(); it != mmap.end(); ++it)
    it->second.copy(dest, src);
}

void aka2::simpletype_copy(void *dest, const void *src, const simpletype_op& op) {
  op.copy(dest, src);
}

void aka2::array_copy(void *dest, const void *src, 
			const array_op &aop, const element_op &vop) {

  if (!aop.empty(dest))
    throw internal_error();

  std::auto_ptr<array_iterator> itemit(aop.get_iterator(src));

  while (itemit->has_next()) {
    const void *srcitem = itemit->next();
    void *destitem = vop.replicate(srcitem);
    aop.push(dest, destitem);
  }
}

void aka2::simplecontent_copy(void *dest, const void *src, const simplecontent_op &sop) {
  attributes_copy(dest, src, sop);
  const member_type &mtype = sop.get_valuetype();
  mtype.copy(dest, src);
}

void aka2::ptrmember_copy(void *dest, const void *src, const ptrmember_op &pop) {
  if (!pop.is_null(dest))
    throw internal_error();

  // Both must be non-null value.
  const void *srcval = pop.dereference(src);
  if (srcval != 0) {
    void *destval = pop.create_member(dest);
    pop.get_value_op().copy(destval, srcval);
  }
}
