//
//  omNodeTests.cpp
//  OmUtil
//
//  Created by David Van Brink on 10/1/16.
//  Copyright (c) 2016 omino.com. All rights reserved.
//

#include "omNodeTests.h"
#include "OmAsserts.h"
#include "Om.h"

std::string qq(std::string s)
{
    s = replaceAll(s, "|", "\"");
    return s;
}

OMTEST(testToFromXml)
{
    std::string s = qq("<a b=|c|><d/></a>");
    
    OmNode *n = OmNodeXmlHandler::fromXmlString(s);
    std::string s2 = n->toXml();
    
    s2 = trim(s2);
    s2 = replaceAll(s2, "  ", " ");
    s2 = replaceAll(s2, "\n ", "");
    delete n;
    
    ASSERT_EQUALS_STRING("xml in and ou?", s, s2);
}

OMTEST(testPath1)
{
    std::string s = qq("<a b=|c|><d/> <d a=|23| b=|86| /><d a=|23| b=|99|/> <d a=|42| b=|808| /></a>");
    OmNode *n = OmNodeXmlHandler::fromXmlString(s);
    
    ASSERT_EQUALS_STRING("root node", "a", n->name);
    
    std::vector<OmNode *> ch1 = n->getChildren("d[a=23]");
    std::vector<OmNode *> ch2 = n->getChildren("d[a=23,b=86]");
    std::vector<OmNode *> ch3 = n->getChildren("d[a=23,b=noop]");
    
    ASSERT_EQUALS_INT("children", 2, ch1.size());
    ASSERT_EQUALS_INT("children", 1, ch2.size());
    ASSERT_EQUALS_INT("children", 0, ch3.size());
    delete n;
}

std::string show(std::string name, std::vector<OmNode *> nodes)
{
    std::string s;
    s += ssprintf("===========\n %s \n", name.c_str());
    int k = 0;
    for(auto node : nodes)
    {
        s += ssprintf("[%d] %s", k++, node->toXml().c_str());
    }
    printf("%s", s.c_str());
    return s;
}

OMTEST(testPath2)
{
    std::string s = qq("<a b=|c|>"
                        "<d/> "
                        "<ned/>"
                        "<d a=|23| b=|86| />"
                        "<d a=|23| b=|99|>"
                          "<e/>"
                          "<e z=|2|/>"
                          "<f z=|1| />"
                          "<f z=|2| />"
                        "</d>"
                       "<d a=|42| b=|808| />"
                       "<dna a=|440| b=|494| g=|784| />"
                       "</a>");
    OmNode *n = OmNodeXmlHandler::fromXmlString(s);
    
    ASSERT_EQUALS_STRING("root node", "a", n->name);
    
    std::vector<OmNode *> ch1 = n->getChildren("d");
    std::vector<OmNode *> ch1a = n->getChildren("d,ned");
    std::vector<OmNode *> ch2 = n->getChildren("d.e");
    std::vector<OmNode *> ch3 = n->getChildren("d.e,f");
    std::vector<OmNode *> ch4 = n->getChildren("d.f[z=1]");
    std::vector<OmNode *> ch5 = n->getChildren("d.e,f[z=1]");
    std::vector<OmNode *> ch6 = n->getChildren("d.f[z=2]");
    std::vector<OmNode *> ch7 = n->getChildren("d.e,f[z=2]");

    std::vector<OmNode *> ch8 = n->getChildren("*.*[z=*]");
    
    std::vector<OmNode *> ch9 = n->getChildren("d*");
    std::vector<OmNode *> chA = n->getChildren("d*[a=4*]");
    
#define CHSIZE(_n, _expectedSize) show(#_n, _n); ASSERT_EQUALS_INT("children " + show(#_n, _n), _expectedSize, _n.size());
    
    CHSIZE(ch1, 4);
    CHSIZE(ch1a, 5);
    CHSIZE(ch2, 2);
    CHSIZE(ch3, 4);
    CHSIZE(ch4, 1);
    CHSIZE(ch5, 1);
    CHSIZE(ch6, 1);
    CHSIZE(ch7, 2);
    CHSIZE(ch8, 3);
    CHSIZE(ch9, 5);
    CHSIZE(chA, 2);
    
    delete n;
}

OMTEST(testPath3)
{
    std::string s = qq("<a b=|c|>"
                       "<z1><z2 v=|A|/></z1>"
                       "<z1><z3 v=|A|/></z1>"
                       "<z1><z2 v=|B|/></z1>"
                       "<z1x><z3 v=|B|/></z1>"
                       "</a>");
    OmNode *n = OmNodeXmlHandler::fromXmlString(s);
    
    ASSERT_EQUALS_STRING("root node", "a", n->name);

#define GC(_findPattern, _filterPattern, _expectedChildCount) ch = n->getChildren(_findPattern, _filterPattern); CHSIZE(ch, _expectedChildCount);
    
    std::vector<OmNode *> ch;
    
    GC("z1", "z2", 2);
    ASSERT_EQUALS_STRING("top element", "z1", ch[0]->name);
    
    GC("*1*", "z3", 2);
    ASSERT_EQUALS_STRING("top element", "z1", ch[0]->name);
    ASSERT_EQUALS_STRING("top element", "z1x", ch[1]->name);

    
    GC("z1", "z2[v=A]", 1);
    ASSERT_EQUALS_STRING("top element", "z1", ch[0]->name);

    GC("z1", "z*[v=A]", 2);
    ASSERT_EQUALS_STRING("top element", "z1", ch[0]->name);
    ASSERT_EQUALS_STRING("top element", "z1", ch[1]->name);
    
//    GC("**", "", 8); not yet.
    
    delete n;
}

OMTEST(testPathValue1)
{
    std::string s = qq("<a b=|c|>"

                       "<obj ix=|1|>"
                       "<param name=|a| value = |1| />"
                       "<param name=|b| value = |2| />"
                       "<param name=|c| value = |3| />"
                       "</obj>"

                       "<obj ix=|2|>"
                       "<param name=|a| value = |1| />"
                       "<param name=|b| value = |4| />"
                       "<param name=|c| value = |5| />"
                       "</obj>"

                       "<obj ix=|1|>"
                       "<param name=|a| value = |6| />"
                       "<param name=|b| value = |7| />"
                       "</obj>"

                       "</a>");

    OmNode *n = OmNodeXmlHandler::fromXmlString(s);
    
    ASSERT_EQUALS_STRING("attr", "1", n->getValue("obj", "", "ix"));
    ASSERT_EQUALS_STRING("attr", "2", n->getValue("obj", "param[name=a]", "param[name=b].value"));
    ASSERT_EQUALS_STRING("attr", "7", n->getValue("obj", "param[name=a,value=6]", "param[name=b].value"));
    
    delete n;
}
OMTEST(testFromXmlQuellWhitespaceContent)
{
    std::string s = R"(
    <xml>
        <e1>this is it!</e1>
    </xml>
    )";

    OmNode *n = OmNodeXmlHandler::fromXmlString(s, false);
    ASSERT_EQUALS_INT("children, no __content__s", 1, n->children.size());
    std::string theContent = n->getValue("e1.__content__", "", "__content__");
    ASSERT_EQUALS_STRING("the content", "this is it!", theContent);
    
    std::string s2 = n->toXml();
    bool gotContent = contains(s2, "content");
    ASSERT_FALSE(ssprintf("xml should reencode content %s", s2.c_str()), gotContent);
    
    OmNode *n2 = OmNodeXmlHandler::fromXmlString(s, false);
    ASSERT_EQUALS_INT("children, no __content__s", 1, n2->children.size());
    std::string theContent2 = n2->getValue("e1.__content__", "", "__content__");
    ASSERT_EQUALS_STRING("the content", "this is it!", theContent2);

    delete n;
    delete n2;
}


void doNodeTests()
{
    testToFromXml();
    testPath1();
    testPath2();
    testPath3();
    testPathValue1();
    
    testFromXmlQuellWhitespaceContent();
}
