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

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

#include <akaxiso/content_model.h>

namespace {

  struct SeqSample {
    short test_;
  };

  struct SeqSampleLeaf : public aka::sequence<SeqSample, SeqSampleLeaf>{
  public:
    void model() {
      member("test", &SeqSample::test_);
    }
  };


  struct SeqSample1 {
    short test_;
  };

  struct SeqSample1Leaf : public aka::sequence<SeqSample1, SeqSample1Leaf>{
    void model() {
      member("test", &SeqSample1::test_);
    }
  };

  typedef std::list<SeqSample> Samples;
  typedef aka::sequential_array<Samples, SeqSampleLeaf> SamplesLeaf;

  struct MemberArraySample {
    Samples samples_;
  };

  struct MemberArraySampleLeaf : public aka::sequence<MemberArraySample, MemberArraySampleLeaf> {
    void model() {
      member("sample", &MemberArraySample::samples_, SamplesLeaf(), 1, 10);
    }
  };


  void initialize() {
    aka::doctype("arrayTest", MemberArraySampleLeaf());
  }

}

#include <akaxiso/akaxiso.h>


class arrayTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(arrayTest);
  //CUPPA:suite=+
  CPPUNIT_TEST(test_array_op);
  CPPUNIT_TEST(test_iterator);
  CPPUNIT_TEST(test_serialize);
  CPPUNIT_TEST(test_equals1);
  CPPUNIT_TEST(test_equals2);
  CPPUNIT_TEST(test_equals3);
  CPPUNIT_TEST(test_parse);
  CPPUNIT_TEST(test_empty_array);
  CPPUNIT_TEST(test_occurrence);
  CPPUNIT_TEST(test_occurrence1);
  CPPUNIT_TEST(test_occurrence2);
  //CUPPA:suite=-
  CPPUNIT_TEST_SUITE_END();
private:

  // your stuff...

public:

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

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

  static void setValue(MemberArraySample &ma, int numitems) {
    for (int i = 0; i < numitems; ++i) {
      SeqSample seq;
      seq.test_ = 10;
      ma.samples_.push_back(seq);
    }
  }


  //CUPPA:decl=+
  void test_array_op() {
    const aka::array_op & op = SamplesLeaf::dispatcher_;
    Samples samples;

    CPPUNIT_ASSERT_MESSAGE("array_op::empty() does not work.", op.empty(&samples));
    CPPUNIT_ASSERT_EQUAL(op.size(&samples), (size_t)0);

    samples.push_back(SeqSample());
    CPPUNIT_ASSERT_EQUAL(op.size(&samples), (size_t)1);

    samples.push_back(SeqSample());
    CPPUNIT_ASSERT_EQUAL(op.size(&samples), (size_t)2);
    
    samples.clear();
    CPPUNIT_ASSERT_MESSAGE("array_op::empty() does not work.", op.empty(&samples));
    CPPUNIT_ASSERT_EQUAL(op.size(&samples), (size_t)0);
  }

  void test_iterator() {
    const aka::array_op & op = SamplesLeaf::dispatcher_;
    Samples samples;

    samples.push_back(SeqSample());
    samples.push_back(SeqSample());

    std::auto_ptr<aka::array_iterator> ait(op.get_iterator(&samples));

    for (Samples::iterator it = samples.begin(); it != samples.end(); ++it) {
      CPPUNIT_ASSERT_MESSAGE("it->has_next() does not work.", ait->has_next()); 
      const void *s1 = &*it;
      const void *s2 = ait->next();
      CPPUNIT_ASSERT_MESSAGE("obtained item is not the same as that in container.",
			     s1 == s2 );
    }

  }

  void test_serialize() {
    MemberArraySample ma;
    SeqSample seq;
    seq.test_ = 0;
    ma.samples_.push_back(seq);
    
    std::ostringstream ostm;
    aka::xml_serializer ser;
    ser.serialize(ma, "arrayTest", ostm);

    //     std::cout << ostm.str();
  }

  void test_equals1() {
    MemberArraySample ma1;
    MemberArraySample ma2;
    setValue(ma1, 10);
    setValue(ma2, 10);

    bool is_equal = aka::equals(ma1, ma2, MemberArraySampleLeaf());
    CPPUNIT_ASSERT_MESSAGE("equals Failed.", is_equal);
  }


  void test_equals2() {
    MemberArraySample ma1;
    MemberArraySample ma2;
    setValue(ma1, 9);
    setValue(ma2, 10);

    bool is_equal = aka::equals(ma1, ma2, MemberArraySampleLeaf());
    CPPUNIT_ASSERT_MESSAGE("equals Failed.", !is_equal);

    is_equal = aka::equals(ma2, ma1, MemberArraySampleLeaf());
    CPPUNIT_ASSERT_MESSAGE("equals Failed.", !is_equal);
  }


  void test_equals3() {
    MemberArraySample ma1;
    MemberArraySample ma2;

    ma1.samples_.push_back(SeqSample());
    ma2.samples_.push_back(SeqSample());

    ma1.samples_.front().test_ = 0;
    ma2.samples_.front().test_ = 1;

    bool is_equal = aka::equals(ma1, ma2, MemberArraySampleLeaf());
    CPPUNIT_ASSERT_MESSAGE("equals Failed.", !is_equal);

    is_equal = aka::equals(ma2, ma1, MemberArraySampleLeaf());
    CPPUNIT_ASSERT_MESSAGE("equals Failed.", !is_equal);
  }


  void test_parse() {
    MemberArraySample ma;
    setValue(ma, 10);
    std::ostringstream ostm;
    aka::xml_serializer ser;

    ser.serialize(ma, "arrayTest", ostm);

    //     std::cout << ostm.str();

    aka::yggxml_parser parser;


    aka::document parsed;
    std::string errMsg;
    try {
      parsed = parser.parse(ostm.rdbuf()->str());
    }
    catch ( const std::exception &e) {
      errMsg = e.what();
    }

    CPPUNIT_ASSERT_MESSAGE(errMsg.c_str(), errMsg.empty());

    CPPUNIT_ASSERT_MESSAGE("Parsed document has wrong docname.", 
			   aka::document_of(parsed, "arrayTest"));

    MemberArraySample *parsed_root = 
      aka::root_cast<MemberArraySample>(parsed);

    bool is_equal = aka::equals(ma, *parsed_root, MemberArraySampleLeaf());

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

  void test_empty_array() {
    MemberArraySample ma;

    aka::member_types::iterator it = MemberArraySampleLeaf::member_types_.begin();
    it->set_occurrence(aka::occurrence(0, 10));

    std::ostringstream ostm;
    aka::xml_serializer ser;
    ser.serialize(ma, "arrayTest", ostm);

    aka::yggxml_parser parser;

    std::string errMsg;
    aka::document parsed;
    try {
      parsed = parser.parse(ostm.rdbuf()->str());
    }
    catch (const std::exception &e) {
      errMsg = e.what();
    }
    CPPUNIT_ASSERT_MESSAGE(errMsg.c_str(), errMsg.empty());
  }

  void test_occurrence() {
    
    MemberArraySample ma;
    setValue(ma, 10);

    std::ostringstream ostm;
    aka::xml_serializer ser;
    ser.serialize(ma, "arrayTest", ostm);

    aka::yggxml_parser parser;

    std::string errMsg;
    aka::document parsed;
    try {
      parsed = parser.parse(ostm.rdbuf()->str());
    }
    catch (const std::exception &e) {
      errMsg = e.what();
    }

    CPPUNIT_ASSERT_MESSAGE(errMsg.c_str(), errMsg.empty());
  }


  void test_occurrence1() {

    MemberArraySample ma;
    setValue(ma, 11);

    std::ostringstream ostm;
    aka::xml_serializer ser;

    ser.serialize(ma, "arrayTest", ostm);

    aka::yggxml_parser parser;

    std::string errMsg;
    aka::document parsed;
    try {
      parsed = parser.parse(ostm.rdbuf()->str());
    }
    catch (const std::exception &e) {
      errMsg = e.what();
    }
    CPPUNIT_ASSERT_MESSAGE("Occurence check does not work.", !errMsg.empty());
  }


  void test_occurrence2() {

    MemberArraySample ma;

    std::ostringstream ostm;
    aka::xml_serializer ser;

    ser.serialize(ma, "arrayTest", ostm);
    aka::yggxml_parser parser;

    std::string errMsg;
    aka::document parsed;
    try {
      parsed = parser.parse(ostm.rdbuf()->str());
    }
    catch (const std::exception &e) {
      errMsg = e.what();
    }
    CPPUNIT_ASSERT_MESSAGE("Occurence check does not work.", !errMsg.empty());
  }

  //CUPPA:decl=-
};

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

CPPUNIT_TEST_SUITE_REGISTRATION(arrayTest);
