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

using namespace akaxiso;

void soxserializer::serialize(const document *doc, std::ostream &ostm) {
  indent_ = 0;
  ostm << "<?xml version=\"1.0\" encoding=\"" << encoding_ << "\" ?>" << std::endl
       << std::endl;

  const element *e = doc->get_root_element();
  open_beginning_tag(doc->get_tagname(), ostm);
  write_namespace_attributes(ostm); 
  close_beginning_tag(ostm);

  inc_indent_level();
  write_entity(e, ostm);
  dec_indent_level();
  new_line(ostm);
  write_ending_tag(doc->get_tagname(), ostm);
  ostm << std::endl;
}


void soxserizlier::write_namespace_attributes(ostream &ostm) {
  const tokenassociation &prefixes = namespace_prefixes();
  for (tokenassociation::const_iterator it = prefixes.begin();
    it != prefixes.end(); ++it) {
      string prefix = it->second;
      id_type namespace_id = it->first;
      new_line(ostm);
      ostm << " xmlns:" << prefix << "=\"" << namespaces().get_token(namespace_id) << "\"";
  }
}

void soxserizlier::write_element(const element *element, const string &tagname, ostream &ostm) {
  new_line(ostm);
  open_beginning_tag(tagname, ostm);
  close_beginning_tag(ostm);
  inc_indent_level();
  write_entity(element, ostm);
  dec_indent_level();
  new_line(ostm);
  write_ending_tag(tagname, ostm);
}


void soxserizlier::open_beginning_tag(const string &tagname, ostream &ostm) {
  ostm << "<" << tagname;
}

void soxserizlier::close_beginning_tag(ostream &ostm) {
  ostm << '>';
}


void soxserizlier::write_ending_tag(const string &tagname, ostream &ostm) {
  ostm << "</" << tagname << ">";
}

void soxserizlier::write_entity(const element* e, 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) {
      new_line(ostm);

      const member_operator &op = it->get_member_operator();
      if (op.get_baseclass_id() == simpletype_id) {
        open_beginning_tag(it->get_tagname(), ostm); close_beginning_tag(ostm);
        static_cast<const simpletype_member_type&>(op).write_text(*seq, ostm);
        write_ending_tag(it->get_tagname(), ostm);
      }
      else {
        open_beginning_tag(it->get_tagname(), ostm); close_beginning_tag(ostm);
        const element *memelm = 
          static_cast<const element_member_type&>(op).get_member_element(*seq);
        write_element(memelm, it->get_tagname(), ostm);
        new_line(ostm);
        write_ending_tag(it->get_tagname(), ostm);
      }
    }
  }
  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);
    }
  }
}


void soxserizlier::new_line(ostream &ostm) {
  ostm << std::endl;
  for (int i = indent_; i != 0; --i)
    ostm << "  ";

}
