//CUPPA:include=+
//CUPPA:include=-
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestAssert.h>

//CUPPA:namespace=+
//CUPPA:namespace=-

#include <xercesc/util/PlatformUtils.hpp>
#include <akaxiso/akaxiso.h>

#include <akaxiso/xerces/parser.h>

namespace {

  class SeqSample : public akaxiso::sequence_impl<SeqSample>{
  public:
    static void initialize_types() {
      static_typeinfo().set_typename("seq_sample");
      define_member("test", &SeqSample::test_);
    }
    short test_;
  };


  class SeqSample1 : public akaxiso::sequence_impl<SeqSample1>{
  public:
    static void initialize_types() {
      static_typeinfo().set_typename("seq_sample1");
      define_member("test", &SeqSample1::test_);
    }
    short test_;
  };

  class ChoiceSample : public akaxiso::choice_impl<ChoiceSample> {
  public:
    static void initialize_types() {
      static_typeinfo().set_typename("choice_sample");
      define_item(sample_sequence());
    }
    struct sample_sequence : public akaxiso::itemtype_impl<sample_sequence, SeqSample> {
      const char *get_tagname() const { return "sample_sequence"; }
    };
  };

//    class DummyTokens : public adom::ChoiceImpl<DummyTokens> {
//    public:
//      DECLARE_ELEMENT("dummytokens")
//        ITEM(dummytoken);
//      DECLARE_ELEMENT_END;

//      DECLARE_ITEMTYPES()
//        DECLARE_ITEM(dummytoken, sample::Token);
//      DECLARE_ITEMTYPES_END;
//    };

  class MyDoc : public akaxiso::document_impl<MyDoc, ChoiceSample> {
  public:
    static void initialize_types() {
      define_document("mydoc");
    }
  };

}



class choiceTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(choiceTest);
//CUPPA:suite=+
  CPPUNIT_TEST(test_appendElement);
  CPPUNIT_TEST(test_appendWrongElement);
  CPPUNIT_TEST(test_equality);
  CPPUNIT_TEST(test_equalityNotEqual1);
  CPPUNIT_TEST(test_equalityNotEqual2);
  CPPUNIT_TEST(test_copy);
  CPPUNIT_TEST(test_replicate); 
  CPPUNIT_TEST(test_serialize);
  CPPUNIT_TEST(test_parse);
//    CPPUNIT_TEST_EXCEPTION(test_occurence, adom::parseexception);
//    CPPUNIT_TEST(test_occurence1);
//    CPPUNIT_TEST_EXCEPTION(test_occurence2, adom::parseexception);
//    CPPUNIT_TEST_EXCEPTION(test_wrongDocument, adom::parseexception);
//CUPPA:suite=-
  CPPUNIT_TEST_SUITE_END();
private:

  // your stuff...
  MyDoc *doc_;
  MyDoc *doc1_;

public:

  virtual void setUp() {
//     XMLPlatformUtils::Initialize();
    akaxiso::initialize();
  }

  virtual void tearDown(){
    akaxiso::uninitialize();
//     XMLPlatformUtils::Terminate();
  }

  static void setValue(ChoiceSample *cho, int numitems) {
    for (int i = 0; i < numitems; ++i) {
      SeqSample *seq = SeqSample::create();
      seq->test_ = 10;
      cho->push_back(seq, "sample_sequence");
    }
  }

  static ChoiceSample* createSample(int numitems) {
    ChoiceSample *tks = ChoiceSample::create();
    setValue(tks, numitems);
    return tks;
  }


//CUPPA:decl=+
  void test_appendElement() {
    ChoiceSample *cho = createSample(0);
    SeqSample *seq = SeqSample::create();
//      adom::TokenID tokenid = adom::TokenMap::getTokenID("token"); // Wrong
//      CPPUNIT_ASSERT_MESSAGE("Wrong token", tokenid != adom::TokenMap::INVALID_TOKEN);

    cho->push_back(seq, "sample_sequence");
//      adom::Choice::iterator it = tks1->appendElement(tkn, tokenid);

//      CPPUNIT_ASSERT_MESSAGE("Append of element failed.", it != tks1->end());
//      delete tkn;
//      delete tks1;

    delete cho;
  }

  void test_appendWrongElement() {
    ChoiceSample *cho1 = createSample(0);
    SeqSample1 *seq = SeqSample1::create();


    bool exception_caught = false;
    try {
      cho1->choice::push_back(seq, std::string("sample_sequence"));
    }
    catch (...) {
      exception_caught = true;
    }

    delete cho1;
    delete seq;

    CPPUNIT_ASSERT_MESSAGE("Append of wrong element unexpectedly-succeeded.", exception_caught);
  }


  void test_equality() {
    ChoiceSample *cho1 = createSample(10);
    ChoiceSample *cho2 = createSample(10);
    bool isEqual = cho1->is_equal_to(cho2);
    delete cho1;
    delete cho2;

    CPPUNIT_ASSERT_MESSAGE("is_equal_to() failed.", isEqual);
  }

  void test_equalityNotEqual1() {
    ChoiceSample *cho1 = createSample(10);
    ChoiceSample *cho2 = createSample(9);
    bool isEqual = cho1->is_equal_to(cho2);
    delete cho1;
    delete cho2;

    CPPUNIT_ASSERT_MESSAGE("isEqualTo failed.", !isEqual);
  }

  void test_equalityNotEqual2() {
    ChoiceSample *cho1 = createSample(10);
    ChoiceSample *cho2 = createSample(10);

    ChoiceSample::iterator it = cho1->begin();
    static_cast<SeqSample*>(it->get_element())->test_ = 1000;

    bool isEqual = cho1->is_equal_to(cho2);
    delete cho1;
    delete cho2;

    CPPUNIT_ASSERT_MESSAGE("isEqualTo failed.", !isEqual);
  }


  void test_copy() {
    ChoiceSample *cho1 = createSample(10);
    ChoiceSample *cho2 = createSample(0);
    cho1->copy_to(cho2);
    bool isEqual = cho1->is_equal_to(cho2);
    delete cho1;
    delete cho2;

    CPPUNIT_ASSERT_MESSAGE("isEqualTo failed.", isEqual);
  }

  void test_replicate() {
    ChoiceSample *cho1 = createSample(10);
    ChoiceSample *cho2 = cho1->replicate();
    bool isEqual = cho1->is_equal_to(cho2);
    delete cho1;
    delete cho2;

    CPPUNIT_ASSERT_MESSAGE("isEqualTo failed.", isEqual);
  }

  void test_serialize() {
    doc_ = MyDoc::create();
    SeqSample *seq = SeqSample::create();
    doc_->get_root()->push_back(seq, "sample_sequence");
    seq->test_ = 0;
    
    std::ostringstream ostm;
    akaxiso::xmlserializer ser;

    ser.serialize(doc_, ostm);
  }

  void test_parse() {
    doc_ = MyDoc::create();

    setValue(doc_->get_root(), 10);
    
    std::ostringstream ostm;
    akaxiso::xmlserializer ser;
    ser.serialize(doc_, ostm);

    akaxiso::yggxml_parser parser;
    doc1_ = static_cast<MyDoc*>(parser.parse(ostm.rdbuf()->str()));

    bool is_equal = doc_->get_root()->is_equal_to(doc1_->get_root());

    if (!is_equal) {
      if (doc1_)
      ser.serialize(doc1_, ostm);
      std::cout << ostm.rdbuf()->str();
    }

    CPPUNIT_ASSERT_MESSAGE("isEqualTo Failed.", is_equal);
   }

//    void test_occurence() {
//      doc_ = MyDoc::createInstance();
    
//      setValue(doc_->getDocumentElement(), 30);

//      adom::ostringstream ostm;
//      adom::XMLSerializer ser;
//      ser.serialize(doc_, ostm);

//      adom::XMLParser parser;

//      // Must throw excetption.
//      doc1_ = static_cast<MyDoc*>(parser.parse(ostm.rdbuf()->str()));
//    }


//    void test_occurence1() {
//      doc_ = MyDoc::createInstance();

//      setValue(doc_->getDocumentElement(), 25);

//      adom::ostringstream ostm;
//      adom::XMLSerializer ser;
//      ser.serialize(doc_, ostm);

//      adom::XMLParser parser;

//      // Must NOT throw excetption.
//      doc1_ = static_cast<MyDoc*>(parser.parse(ostm.rdbuf()->str()));
//    }


//    void test_occurence2() {
//      doc_ = MyDoc::createInstance();

//      adom::ostringstream ostm;
//      adom::XMLSerializer ser;
//      ser.serialize(doc_, ostm);

//      adom::XMLParser parser;

//      // Must NOT throw excetption.
//      doc1_ = static_cast<MyDoc*>(parser.parse(ostm.rdbuf()->str()));
//    }

//    void test_wrongDocument() {
//      adom::string doc =
//        "<?xml version=\"1.0\"?>"
//        "<mydoc>"
//        "  <dummytoken>token</dummytoken>"
//        "</mydoc>";

//      adom::XMLParser parser;
//      doc_ = static_cast<MyDoc*>(parser.parse(doc));
//    }

//CUPPA:decl=-
};

//CUPPA:impl=+
//CUPPA:impl=-

CPPUNIT_TEST_SUITE_REGISTRATION(choiceTest);
