/* -*- c++ -*- */
#include "platform.h"
#include "classcontents.h"
#include "exception.h"
#include <assert.h>
#include "type_registry.h"

using namespace osixaka;

bool sequence_class::push_member(const aka::qname &name, const aka::qname &type,
				 const aka::occurrence &occ) {

  // complexType and simpleType is acceptable.
  if (type_exists(type)) {
    sequence_member sm;
    sm.occ_ = occ;
    sm.name_ = name;
    sm.type_ = type;
    members_.push_back(sm);
    return true;
  }
  return false;
}

bool sequence_class::is_resolved(const qname_set &resolved) const {
  if (!attribute_contents::is_resolved())
    return false;

  for (sequence_members::const_iterator it = members_.begin();
       it != members_.end(); ++it) {
    if (builtinTypes_.exists(it->type_))
      continue;
    qname_set::const_iterator res = resolved.find(it->type_);
    if (res == resolved.end()) // Non-resolved class found.
      return false;
  }
  return true;
}

bool attribute_contents::push_attribute(const aka2::qname &name, const aka2::qname &type) {

  // complexType and simpleType is acceptable.
  if (builtinTypes_.exists(type)) {
    attribute_member am;
    am.name_ = name;
    am.type_ = type;
    attributes_.push_back(am);
    return true;
  }
  return false;
}

bool attribute_contents::is_resolved() const {
  for (attribute_members::const_iterator it = attributes_.begin();
       it != attributes_.end(); ++it) {
    if (!builtinTypes_.exists(it->type_))
      return false;
  }
  return true;
}


void attribute_contents::write_attributes_header(const attribute_members &members,
						 std::ostream &ostm) const {
  for (attribute_members::const_iterator ait = attributes_.begin();
       ait != attributes_.end(); ++ait)
    ostm << "  " << get_cpptype(ait->type_) << " " << ait->name_ << "_;" << std::endl;
}

void attribute_contents::write_attributes_leaf(const attribute_members &members,
					       const cppname &type, std::ostream &ostm) const {
  for (attribute_members::const_iterator ait = attributes_.begin();
       ait != attributes_.end(); ++ait)
    ostm << "    attribute(\"" << ait->name_ << "\", &::" << type
	 << "::" << ait->name_.local() << "_, "
	 << get_leaf_name(ait->type_) << "());" << std::endl;
}


void simplecontent_class::generate_element(std::ostream &ostm) const {
  const std::string &classname = name_.qualified();

  ostm << "/** " << classname << " */" << std::endl;

  ostm << "struct " << classname << " {" << std::endl
       << "  " << get_cpptype(value_type_) << " " << "value_;" << std::endl;

  write_attributes_header(attributes_, ostm);

  ostm << "};" << std::endl
       << std::endl;
}

void simplecontent_class::generate_xiso(std::ostream &ostm) const {

  const std::string &classname = name_.qualified();

  ostm << "  struct leaf<" << classname << "> : public aka::simplecontent<"
       << classname << "> {" << std::endl
       << "    void model() {" << std::endl
       << "                     value(&" << classname << "::value_);" << std::endl;
  write_attributes_leaf(attributes_, get_cpptype(name_), ostm);
  ostm << "  }" << std::endl
       << std::endl;
}

void simplecontent_class::generate_xiso_impl(std::ostream &ostm) const {
}


bool simplecontent_class::is_resolved(const qname_set &resolved) const {
  if (!attribute_contents::is_resolved())
    return false;
  return builtinTypes_.exists(value_type_);
}

void sequence_class::generate_element(std::ostream &ostm) const {

  const std::string &classname = name_.qualified();
  ostm << "struct " << classname << " {" << std::endl;

  for (sequence_members::const_iterator it = members_.begin();
       it != members_.end(); ++it) {
    if (!xs::is_array(it->occ_)) {
      ostm << "  " << get_cpptype(it->type_) << " "
	   << it->name_ << "_;" << std::endl;
    }
    else {
      ostm << "  " << get_cpptype(it->type_) << " "
	   << it->name_ << "s_;" << std::endl;
    }
  }

  write_attributes_header(attributes_, ostm);

  ostm << "};" << std::endl
       << std::endl;
}


void sequence_class::generate_xiso(std::ostream &ostm) const {

  const cppname &classname = get_cpptype(name_);
  ostm << "struct " << classname << "_leaf : public aka::sequence<" << classname << ", "
       << classname << "_leaf> {" << std::endl
       << "public:" << std::endl
       << "  void model() {" << std::endl;

  for (sequence_members::const_iterator it = members_.begin(); it != members_.end(); ++it)
    if (!xs::is_array(it->occ_))
      ostm << "    member(\"" << it->name_ << "\", "
	   << "&::" << classname << "::" << it->name_ << "_, "
	   << get_leaf_name(it->type_) << "());" << std::endl;
    else {
      ostm << "    member(\"" << it->name_ << "\", &::" << classname << "::" << it->name_ 
	   << "s_, " 
	   << get_leaf_name(it->type_) << "()," << std::endl;
      write_occurrence(it->occ_, ostm);
      ostm << ");" << std::endl;
    }

  write_attributes_leaf(attributes_, get_cpptype(name_), ostm);

  ostm << "  }" << std::endl
       << "};" << std::endl
       << std::endl;

}

void sequence_class::generate_xiso_impl(std::ostream &ostm) const {}

bool choice_class::push_item(const aka::qname &name, const aka::qname &xmltype,
			     const aka::occurrence &occ) {

  // complexType or simpleType is acceptable.
  if (type_exists(xmltype)) {
    choice_item item;
    item.occ_ = occ;
    item.name_ = name;
    item.type_ = xmltype;
    items_.push_back(item);
    return true;
  }
  return false;
}

bool choice_class::is_resolved(const qname_set &resolved) const {

  for (choice_items::const_iterator it = items_.begin();
       it != items_.end(); ++it) {
    if (builtinTypes_.exists(it->type_))
      continue;
    qname_set::const_iterator res = resolved.find(it->type_);
    if (res == resolved.end()) // Non-resolved class found.
      return false;
  }
  return true;
}

void choice_class::generate_element(std::ostream &ostm) const {

  ostm << "typedef std::list<aka::item> " << name_ << ";" << std::endl
       << std::endl;

}

void choice_class::generate_xiso(std::ostream &ostm) const {

  const std::string &classname = name_.qualified();
  ostm << "struct " << classname << "_leaf : public aka::sequential_choice<"
       << get_cpptype(name_) << ", " << get_leaf_name(name_) << "> {" << std::endl
       << "  void model() {" << std::endl;

  if (occ_.is_array()) {
    ostm << "    occurrence(";
    write_occurrence(occ_, ostm);
    ostm << ");" << std::endl;
  }

  for (choice_items::const_iterator it = items_.begin(); it != items_.end(); ++it)
    ostm << "    item(\"" << it->name_ << "\", "
	 << get_leaf_name(it->type_) << "());" << std::endl;

  ostm << "  }" << std::endl
       << "};" << std::endl
       << std::endl;

}

void choice_class::generate_xiso_impl(std::ostream &ostm) const { }


void array_class::generate_element(std::ostream &ostm) const {
  ostm << "typedef std::vector<" << get_cpptype(item_type_) << "> "
       << get_cpptype(name_) << ';' << std::endl
       << std::endl;
}

void array_class::generate_xiso(std::ostream &ostm) const {
  ostm << "typedef aka::sequential_array<" << get_cpptype(name_) << ", "
       << get_leaf_name(item_type_) << " > "
       << get_leaf_name(name_) << ";" << std::endl
       << std::endl;
}

void array_class::generate_xiso_impl(std::ostream &ostm) const {
}

bool array_class::is_resolved(const qname_set &resolved) const {
  if (builtinTypes_.exists(item_type_))
    return true;
  qname_set::const_iterator res = resolved.find(item_type_);
  return res != resolved.end();
}

void osixaka::write_occurrence(const aka::occurrence &occ, std::ostream &ostm) {
  ostm << occ.minOccurs_ << ", ";
  if (occ.maxOccurs_ == aka::unbounded)
    ostm << "aka::unbounded";
  else
    ostm << occ.maxOccurs_;
}
