#include "ygg_handler.h"
#include "../classes/document.h"
#include "../parser/sequence_handler.h"
#include "../parser/choice_handler.h"


using namespace aka2;
namespace ygg = yggdrasil; 

#ifdef _MSC_VER
#include <malloc.h>
#endif


namespace {
  std::string trim(const std::string &str) {
    std::string::size_type begin_pos = str.find_first_not_of(' ');
    std::string::size_type end_pos = str.find_last_not_of(' ');
    return str.substr(begin_pos, end_pos - begin_pos + 1);
  }
  
  std::string trim_left(const std::string &str) {
    std::string::size_type begin_pos = str.find_first_not_of(' ');
    if (begin_pos == std::string::npos)
      return str;
    else
      return str.substr(begin_pos);
  }
  
}


void ns_stack::inc_depth() {
  prefixes_stack_.push(prefixes());
}

void ns_stack::dec_depth() {
  prefixes_stack_.pop();
}

const ns_stack::prefixes &ns_stack::get_current_prefixes() const {
  return prefixes_stack_.top();
}

bool ns_stack::process_namespace_attribute(const ygg::ygg_node &node, const nsdecl *&decl) {
  std::string prefix;
  std::string ns_prefix;
  std::string value;
  
  std::string attrname = trim(node.get_name());
  std::string::size_type pos = attrname.find_first_of(':');

  if (pos == std::string::npos)
    return false;

  prefix = attrname.substr(0, pos);
  if (prefix != "xmlns")
    return false;
  
  ns_prefix = attrname.substr(pos + 1);

  std::string uri = node.get_value().c_str();
  if ((uri.at(0) == '"') && (uri.at(uri.size() - 1) == '"')){
    uri.erase(0, 1);                // remove ""
    uri.erase(uri.length() - 1, 1);
  }

  nsdecl newentry;
  newentry.prefix_ = ns_prefix;
  newentry.uri_ = uri;
  prefixes_stack_.top().push_back(newentry);
  decl = &prefixes_stack_.top().back();
  return true;
}



ygg_handler::ygg_handler() {
}


void ygg_handler::process_attributes(const yggdrasil::ygg_node &elm, attribute_values &attrs) {

  // Check prefix
  ygg::ygg_node yattrs = elm["@*"];
  
  for (int i = 0; i < yattrs.get_size(); ++i) {
    const nsdecl *decl = 0; 
    ygg::ygg_node node = yattrs[i];
    if (ns_.process_namespace_attribute(node, decl))
      start_prefix_mapping(decl->prefix_, decl->uri_);
    else {
      qname name;
      name.set(node.get_name(), handler_.get_global_attributes());
      attrs.insert(attribute_values::value_type(name.local(), node.get_value()));
    }
  }
}


void ygg_handler::start_element(ygg::ygg_node elm) {

  std::string uri;
  qname name;
  attribute_values xattrs;

  ns_.inc_depth();

  if (handler_.get_context().empty()) {
    if (elm.get_name() == "?xml")
      return;
    process_attributes(elm, xattrs);
    name.set(elm.get_name(), handler_.get_global_attributes());
    handler_.startElement(name, xattrs);
    return;
  }

  process_attributes(elm, xattrs);
  name.set(trim(elm.get_name()), handler_.get_global_attributes());
  handler_.startElement(name, xattrs);

}


void ygg_handler::end_element(ygg::ygg_node node){

  qname name;
  std::string tagname = trim(node.get_name());
  name.set(tagname, handler_.get_global_attributes());
  if (tagname == "?xml")
    return;

  std::string chars = trim_left(node.get_value());
  handler_.characters(chars.c_str(), chars.size());

  handler_.endElement(name);

  const ns_stack::prefixes &prefixes = ns_.get_current_prefixes();
  for (ns_stack::prefixes::const_iterator it = prefixes.begin(); it != prefixes.end(); ++it)
    end_prefix_mapping(it->prefix_);

  ns_.dec_depth();

}

void ygg_handler::on_error(ygg::ygg_error* parse_error) {
  throw parse_exception(__FILE__, __LINE__, parse_error->get_message());
}

document ygg_handler::get_document(){
  return handler_.get_document();
}

void ygg_handler::start_prefix_mapping(const std::string &prefix, const std::string &uri) {
  handler_.start_prefix_mapping(prefix, uri);
}

void ygg_handler::end_prefix_mapping(const std::string &prefix){
  handler_.end_prefix_mapping(prefix);
}
