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

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

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

namespace {

  /** testing <xs:any> */

  struct any_test {
    std::string member1_;
    aka2::any any_;
    std::string member2_;
  };

  struct any_array_test {
    aka2::any_array array1_;
    std::string value_;
    aka2::any_array array2_;
  };

  typedef std::vector<aka2::item> any_choice;
  typedef std::vector<aka2::item> any_array_choice;
  typedef std::vector<aka2::item> anyType_choice;

  struct any_choice_leaf : aka2::sequential_choice<any_choice, any_choice_leaf> {
    void model() {
      occurrence(0, aka::unbounded);
      any("&any");
      item("value", xiso::leaf<std::string>());
    }
  };


  struct any_array_choice_leaf : aka2::sequential_choice<any_array_choice, any_array_choice_leaf> {
    void model() {
      occurrence(0, aka2::unbounded);
      any("&any", 0, aka2::unbounded);
      item("value", xiso::leaf<std::string>());
    }
  };

  struct anyType_choice_leaf : aka2::sequential_choice<anyType_choice, anyType_choice_leaf> {
    void model() {
      occurrence(0, aka2::unbounded);
      item("value", xiso::leaf<std::string>());
      any("any");
      any("any_array", 0, aka2::unbounded);
    }
  };

  struct anyType_test {
    std::string value1_;
    aka::any any_;
    std::string value2_;
    aka::any_array anys_;
    std::string value3_;
  };

}
namespace xiso {

  template<>
  struct leaf<any_test> : aka2::sequence<any_test> {
    void model() {
      member("member1", &any_test::member1_);
      any("&any", &any_test::any_);
      member("member2", &any_test::member2_);
    }
  };


  template<>
  struct leaf<any_array_test> : aka2::sequence<any_array_test> {
    void model() {
      any("&any[]", &any_array_test::array1_, 0, aka2::unbounded);
      member("value", &any_array_test::value_);
      any("&any[]", &any_array_test::array2_, 0, aka2::unbounded);
    }
  };


  template<>
  struct leaf<anyType_test> : aka2::sequence<anyType_test> {
    void model() {
      member("value1", &anyType_test::value1_);
      any("any_node", &anyType_test::any_);
      member("value2", &anyType_test::value2_);
      any("any_node_array", &anyType_test::anys_, 0, aka::unbounded);
      member("value3", &anyType_test::value3_);
    }
  };

  

}


class anyTest : public CppUnit::TestFixture {
  CPPUNIT_TEST_SUITE(anyTest);
//CUPPA:suite=+
  CPPUNIT_TEST(test_serialize);
  CPPUNIT_TEST(test_parse);
  CPPUNIT_TEST(test_serialize_array);
  CPPUNIT_TEST(test_parse_array);
  CPPUNIT_TEST(test_serialize_choice);
  CPPUNIT_TEST(test_parse_choice);
  CPPUNIT_TEST(test_serialize_array_choice);
  CPPUNIT_TEST(test_parse_array_choice);
  CPPUNIT_TEST(test_ur_doc);
  CPPUNIT_TEST(test_anyType);
  CPPUNIT_TEST(test_anyType_error);
  CPPUNIT_TEST(test_anyTypeArray_error);
  CPPUNIT_TEST(test_anyType_choice);
//CUPPA:suite=-
  CPPUNIT_TEST_SUITE_END();
private:

  // your stuff...

public:

  virtual void setUp() {
    aka2::initialize();
    aka2::doctype("any_test", xiso::leaf<any_test>());
    aka2::doctype("any_array_test", xiso::leaf<any_array_test>());
    aka2::doctype("any_choice", any_choice_leaf());
    aka2::doctype("any_array_choice", any_array_choice_leaf());
    aka2::doctype("ur_doc");
    aka2::doctype("anyType_test", xiso::leaf<anyType_test>());
    aka2::doctype("anyType_choice_test", anyType_choice_leaf());
  }
  virtual void tearDown() { 
    aka2::uninitialize();
  }

  any_test create_root() {
    any_test root;
    root.member1_ = "member1";
    root.member2_ = "member2";

    root.any_.name_ = aka2::qname("any_element");
    root.any_.value_ = "any's value.";

    root.any_.attributes_.push_back(aka2::any_attribute(aka2::qname("test"), "value"));


    aka2::any child;
    child.name_ = aka2::qname("child_node");
    root.any_.children_.push_back(child);

    return root;
  }

//CUPPA:decl=+
  void test_serialize() {
    any_test root = create_root();
    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_test", ostm);
  }

  void test_serialize_array() {
    any_array_test root;
    root.value_ = "value";
    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_array_test", ostm);
    //std::cout << ostm.rdbuf()->str() << std::endl;
  }


  void test_serialize_choice() {
    any_choice root;
    any_choice_leaf::moc moc(root);

    moc.push_back(std::string("test"), "value");
    aka2::any an;
    an.name_ = aka2::qname("test");
    moc.push_back(an, "&any");

    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_choice", ostm);

    //std::cout << ostm.rdbuf()->str() << std::endl;
  }



  void test_parse_choice() {
    any_choice root;
    any_choice_leaf::moc moc(root);

    moc.push_back(std::string("test"), "value");
    aka2::any an;
    an.name_ = aka2::qname("test");
    moc.push_back(an, "&any");

    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_choice", ostm);

    aka2::xml_parser parser;
    aka2::document doc = parser.parse(ostm.rdbuf()->str());

  }


  void test_parse() {
    any_test root = create_root();
    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_test", ostm);

    aka2::xml_parser parser;
    aka2::document doc = parser.parse(ostm.rdbuf()->str());
  }


  void test_parse_array() {
    any_array_test root;

    aka2::any an;
    an.name_ = aka2::qname("test1");
    //root.array1_.push_back(an);
    //root.array1_.push_back(an);

    root.value_ = "value";

    an.name_ = aka2::qname("test2");
    root.array2_.push_back(an);
    root.array2_.push_back(an);

    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_array_test", ostm);
    //std::cout << ostm.rdbuf()->str() << std::endl;
    aka2::xml_parser parser;
    aka2::document doc = parser.parse(ostm.rdbuf()->str());

    //ser.serialize(doc, std::cout);
  }



  void test_serialize_array_choice() {
    any_array_choice root;
    any_array_choice_leaf::moc moc(root);

    aka2::any_array ar;
    aka2::any an;
    an.name_ = aka2::qname("any_array_item");
    ar.push_back(an);

    moc.push_back(ar, "&any");
    moc.push_back(std::string("test"), "value");

    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_array_choice", ostm);

    //std::cout << ostm.rdbuf()->str() << std::endl;
  }


  void test_parse_array_choice() {
    any_array_choice root;
    any_array_choice_leaf::moc moc(root);

    aka2::any_array ar;
    aka2::any an;
    an.name_ = aka2::qname("any_array_item");
    ar.push_back(an);

    moc.push_back(ar, "&any");
    moc.push_back(std::string("test"), "value");

    aka2::xml_serializer ser;
    std::ostringstream ostm;
    ser.serialize(root, "any_array_choice", ostm);

    //std::cout << ostm.rdbuf()->str() << std::endl;

    aka2::xml_parser parser;
    aka2::document doc = parser.parse(ostm.rdbuf()->str());
    //ser.serialize(doc, std::cout);

  }


  void test_ur_doc() {
    const char *urdoc = 
      "<?xml version=\"1.0\"?>"
      "<ur_doc fake_attr=\"test\">test<ur_elm>test1</ur_elm></ur_doc>";
    aka2::xml_parser parser;
    aka2::document doc = parser.parse(urdoc);
  }


  void test_anyType() {
    const char *urdoc = 
      "<?xml version=\"1.0\"?>"
      "<anyType_test>"
      "<value1>ss</value1>"
      "<any_node fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node>"
      "<value2>ss</value2>"
      "<any_node_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_array>"
      "<any_node_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_array>"
      "<value3>ss</value3>"
      "</anyType_test>";

    aka2::xml_parser parser;
    aka2::document doc = parser.parse(urdoc);

//     aka2::xml_serializer ser;
//     ser.serialize(doc, std::cout);
  }

  void test_anyType_error() {
    const char *urdoc = 
      "<?xml version=\"1.0\"?>"
      "<anyType_test>"
      "<value1>ss</value1>"
      "<any_node_wrong fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_wrong>"  // Wrong tagname
      "<value2>ss</value2>"
      "<any_node_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_array>"
      "<any_node_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_array>"
      "<value3>ss</value3>"
      "</anyType_test>";
    
    bool raised = false;
    try {
      aka2::xml_parser parser;
      aka2::document doc = parser.parse(urdoc);
      //     aka2::xml_serializer ser;
      //     ser.serialize(doc, std::cout);
    }
    catch (const std::exception &) {
      raised = true;
    }
    CPPUNIT_ASSERT_MESSAGE("ERROR", raised);
  }


  void test_anyTypeArray_error() {
    const char *urdoc = 
      "<?xml version=\"1.0\"?>"
      "<anyType_test>"
      "<value1>ss</value1>"
      "<any_node fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node>"
      "<value2>ss</value2>"

      // Wrong tagname any_node_array -> any_node_array_wrong
      "<any_node_array_wrong fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_array_wrong>"
      "<any_node_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_node_array>"
      "<value3>ss</value3>"
      "</anyType_test>";
    
    bool raised = false;
    try {
      aka2::xml_parser parser;
      aka2::document doc = parser.parse(urdoc);
      //     aka2::xml_serializer ser;
      //     ser.serialize(doc, std::cout);
    }
    catch (const std::exception &) {
      raised = true;
    }
    CPPUNIT_ASSERT_MESSAGE("ERROR", raised);
  }


  void test_anyType_choice() {
    const char *urdoc = 
      "<?xml version=\"1.0\"?>"
      "<anyType_choice_test>"
      "<value>ss</value>"
      "<any fake_attr=\"attr\">test1<ur_node>test</ur_node></any>"
      "<value>ss</value>"
      "<any_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_array>"
      "<any_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_array>"
      "<value>ss</value>"
      "<any_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_array>"
      "<any_array fake_attr=\"attr\">test1<ur_node>test</ur_node></any_array>"
      "</anyType_choice_test>";

    aka2::xml_parser parser;
    aka2::document doc = parser.parse(urdoc);

//     aka2::xml_serializer ser;
//     ser.serialize(doc, std::cout);
  }


//CUPPA:decl=-
};

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

CPPUNIT_TEST_SUITE_REGISTRATION(anyTest);
