#include <akaxiso/akaxiso.h>
#include <akaxiso/content_model.h>
#include <iostream>

#include <string>

namespace {

  typedef std::list<aka2::item> cho;

  struct seq {
    cho choice_;
  };


  std::string wrong_document = 
  "<?xml version='1.0' encoding='euc-jp' standalone='yes'?>\n"
  "<test>\n"
  "  <cho>\n"
  "    <str>test</str>\n"
  "  </cha>\n" // Should be </cho>
  "</test>\n";
  
}

namespace xiso {
  template<>
  struct leaf<cho> : public aka2::sequential_choice<cho> {
    void model() {
      item("str", xiso::leaf<std::string>());
    }
  };

  template<>
  struct leaf<seq> : public aka2::sequence<seq> {
    void model() {
      member("cho", &seq::choice_, 0, 10);
    }
  };

}


static seq create_root() {
  seq root;
  xiso::leaf<cho>::moc moc(root.choice_);
  moc.push_back(std::string("test"), "str");
  return root;
}


void instantiation() {
  for (int i = 0; i < 1000; ++i) {
#ifdef USE_XERCESC
      aka::use_xerces_transcoder(true);
    {
      aka2::xerces_parser p;
      aka2::xml_serializer s;
    }
    aka::use_xerces_transcoder(false);
#endif
    {
      aka2::yggxml_parser y;
      aka2::xml_serializer x;
    }
  }
}


void serialize() {
  for (int i = 0; i < 1000; ++i) {
    // Serialization test.
    seq root = create_root();
    aka::xml_serializer ser;
    std::ostringstream serialized;
    ser.serialize(root, "test", serialized);
    //std::cout << serialized.rdbuf()->str();
  }
}

void parse(aka::parser &parser) {
  for (int i = 0; i < 1000; ++i) {
    // Parser test.
    seq root = create_root();
    std::ostringstream serialized;
    aka::xml_serializer ser;
    ser.serialize(root, "test", serialized);

    try {
      aka::document doc = parser.parse(serialized.rdbuf()->str());
      assert(aka::document_of(doc, "test"));
    }
    catch ( ... ) {
      assert(!"Unexpected error."); 
    }
  }
}

void error_parse(aka::parser &parser) {
  for (int i = 0; i < 1000; ++i) {    // Parser error test.
    bool error = false;
    try {
      aka::document doc = parser.parse(wrong_document);
    }
    catch ( ... ) {
      error = true;
    }
    assert(error);

    error = false;
    try {
      aka::document doc = parser.parse_file("No file.");
    }
    catch ( ... ) {
      error = true;
    }
    assert(error);
  }
}


#ifdef USE_XERCESC
void xerces_test() {
  aka::use_xerces_transcoder(true);
  serialize();
  {
    aka2::xerces_parser parser;
    parse(parser);
  }
  {
    aka2::xerces_parser parser;
    error_parse(parser);
  }
  aka::use_xerces_transcoder(false);
}
#endif

void tricklib_test() {
  serialize();
  {
    aka2::yggxml_parser parser;
    parse(parser);
  }
  {
    aka2::yggxml_parser parser;
    error_parse(parser);
  }
}


#include <unistd.h>

int main() {
  aka::initialize();
  aka::doctype("test", xiso::leaf<seq>());

  while (true) {
    std::cerr << "Instantiation...";
    instantiation();
    std::cerr << "done." << std::endl;

#ifdef USE_XERCESC
    std::cerr << "Xerces...";
    xerces_test();
    std::cerr << "done." << std::endl;
#endif

    std::cerr << "TrickLib...";
    tricklib_test();
    std::cerr << "done." << std::endl;
  }

  while (true)
    usleep(0);

  aka::uninitialize();
  return 0;
}
