#include "soxserializer.h"
#include <iostream>

using namespace akaxiso;

void soxserializer::serialize(const document *doc, std::ostream &ostm) {
  indent_ = 0;

  indent_str_ = "\t";

  const element *e = doc->get_root_element();
  write_element_tag(doc->get_root_tagname().get_name(), ostm);
  write_namespace_attributes(ostm); 

  inc_indent_level();
  write_entity(e, ostm);
  dec_indent_level();
  new_line(ostm);
  ostm << std::endl;
}


void soxserializer::write_namespace_attributes(std::ostream &ostm) {
  const prefix_map &prefixes = system_global_attributes().get_prefix_map();
  inc_indent_level();
  for (prefix_map::const_iterator it = prefixes.begin();
    it != prefixes.end(); ++it) {
      const std::string &prefix = it->second;
      id_type namespace_id = it->first;
      new_line(ostm);
      ostm << "xmlns:" << prefix << "=\"" << namespaces().get_namespace_uri(namespace_id) << "\"";
  }
  dec_indent_level();
}

void soxserializer::write_element(const element *element, const std::string &tagname, std::ostream &ostm) {
  new_line(ostm);
  write_element_tag(tagname, ostm);
  inc_indent_level();
  write_entity(element, ostm);
  dec_indent_level();
}


void soxserializer::write_element_tag(const std::string &tagname, std::ostream &ostm) {
  ostm << tagname << '>';
}



void soxserializer::write_entity(const element* e, std::ostream &ostm) {

  if (e->get_baseclass_id() == sequence_id) {
    const sequence *seq = static_cast<const sequence*>(e);
    const sequence_info &info = seq->get_sequence_info();
    for (sequence_info::const_iterator it = info.begin(); it != info.end(); ++it) {
      const member_operator &op = it->get_member_operator();
      switch (op.get_baseclass_id()) {
        case simpletype_id:
        {
          new_line(ostm);
          write_element_tag(it->get_tagname(), ostm);
          inc_indent_level();
          new_line(ostm);
          static_cast<const simpletype_member_type&>(op).write_text(*seq, ostm, system_global_attributes());
          dec_indent_level();
          break;
        }
        case sequence_id:
        case choice_id:
        {
          const element *memelm = 
            static_cast<const element_member_type&>(op).get_member_element(*seq);
          write_element(memelm, it->get_tagname(), ostm);
          break;
        }
        default:
          throw internal_error();
      }
    }
  }
  else if (e->get_baseclass_id() == choice_id) {
    const choice *cho = static_cast<const choice*>(e);
    for (choice::const_iterator it = cho->begin(); it != cho->end(); ++it) {
      const element *e = it->get_element();
      write_element(e, it->get_tagname(), ostm);
    }
  }
}

