/* -*- c++ -*- */
#include "serializer.h"
#include "formatter.h"

namespace aka2 {

serializer::serializer(int tab, const std::string &encoding)
  : indent_str_(tab, ' '), encoding_(encoding), formatter_(0) {}

serializer::~serializer() {}

void serializer::serialize(const document &doc, std::ostream &ostm) {
  create_formatter(ostm);
  serialize_internal(doc.get_root(), doc.get_name(), doc.get_op());
  formatter_.reset();
}

void serializer::create_formatter(std::ostream& ostm) {
#ifdef USE_XERCESC
  if (formatter::use_xerces_transcoder_)
    formatter_.reset(new xerces_formatter(ostm));
  else
#endif
    formatter_.reset(new babel_formatter(ostm));

  try {
    formatter_->prepare(encoding_);
  }
  catch (...) {
    formatter_.reset();
    throw internal_error();
  }
}

void serializer::new_line() {
  std::string line = "\n";
  for (int i = indent_; i != 0; --i)
    line += indent_str_;
  formatter_->write(line);
}

bool serializer::is_sequence_empty(const void *e, const member_types &mtypes) {
  for (member_types::const_iterator it = mtypes.begin();
       it != mtypes.end(); ++it) {
    if (!is_member_empty(e, *it))
      return false;
  }
  return true;
}

bool serializer::is_all_empty(const void *e, const member_map &mmap) {
  for (member_map::const_iterator it = mmap.begin();
       it != mmap.end(); ++it) {
    if (!is_member_empty(e, it->second))
      return false;
  }
  return true;
}

bool serializer::is_member_empty(const void *e, const member_type &mtype) {
  const_memberpair mpair = mtype.get_member(e);

  switch (mtype.get_schematype()) {
    case simpletype_id:
    case simplecontent_id:
      return false;
    case array_id: {
      const array_op &aop = static_cast<const array_op&>(mpair.op_);
      if (aop.size(mpair.e_) != 0)
        return false;
      break;
    }
    case sequence_id: {
      if (mtype.is_element())
	return false;
      const sequence_op &sop = static_cast<const sequence_op&>(mpair.op_);
      if (!is_sequence_empty(mpair.e_, sop.get_member_types()))
        return false;
      break;
    }
    case choice_id: {
      if (mtype.is_element())
	return false;
      const choice_op &cop = static_cast<const choice_op&>(mpair.op_);
      if (cop.size(mpair.e_) != 0)
        return false;
      break;
    }
    case all_id: {
      if (mtype.is_element())
	return false;
      const all_op &aop = static_cast<const all_op&>(mpair.op_);
      if (!is_all_empty(mpair.e_, aop.get_member_map()))
        return false;
      break;
    }
    case ptrmember_id: {
      const ptrmember_op &pop = static_cast<const ptrmember_op&>(mpair.op_);
      if (!pop.is_null(mpair.e_))
        return false;
      break;
    }
    default:
      assert(!"Must not reach here.");
  }
  return true;
}

} // namespace aka2
