#include "util/StringUtils.h"
#include "util/simpleobject/AgColor.h"
#include "util/simpleobject/AgString.h"
#include <sstream>
//#include <regex>
#include <iomanip>
#include <boost/algorithm/string/regex.hpp>
#include "IllegalArgumentException.h"


#define DEFAULT_COLLECTION_PRINT_SEPARATOR ", "

AgString int_to_hex(int i)
{
    std::stringbuf buf;
    std::ostream os(&buf);


    os << "0x" << std::setfill('0') << std::setw(sizeof(int) * 2)
       << std::hex << i;

    return buf.str().c_str();
}


const AgString StringUtils::byteToHexString(int i)
{
    AgString str = int_to_hex(i & 0xFF);
    if (str.length() == 1)
    {
        str = "0" + str;
    }
    return str;
}

ElementListPtr StringUtils::elements(const AgString &source, bool useVisibleSeparators)
{
    ElementListPtr res(new ElementList());

    AgChar elStart = useVisibleSeparators ? DataTableUtils::ELEMENT_VISIBLE_START : DataTableUtils::ELEMENT_START;
    AgChar elEnd = useVisibleSeparators ? DataTableUtils::ELEMENT_VISIBLE_END : DataTableUtils::ELEMENT_END;
    AgChar elNameValSep = useVisibleSeparators ? DataTableUtils::ELEMENT_VISIBLE_NAME_VALUE_SEPARATOR : DataTableUtils::ELEMENT_NAME_VALUE_SEPARATOR;

    int depth = 0;
    int startPos = -1;
    int nameValSepPos = -1;

    int len = source.length();

    for (int i = 0; i < len; i++)
    {
        AgChar c = source[i];

        if (c == elStart)
        {
            depth++;

            if (depth == 1)
            {
                startPos = i;
            }
        }

        if (c == elNameValSep)
        {
            if (depth == 1 && nameValSepPos == -1)
            {
                nameValSepPos = i;
            }
        }

        if (c == elEnd)
        {
            depth--;

            if (depth < 0)
            {
                int min = std::max<int>(0, i - 10);
                throw IllegalArgumentException("Invalid closing element at position " + AgString::fromInt(i) + " (" + AgString(source.substr(min, i - min)) + ")");
            }

            if (depth == 0)
            {
                AgString name;
                AgString value;

                if (nameValSepPos == -1)
                {
                    value = source.substr(startPos + 1, i - (startPos + 1));
                }
                else
                {
                    name = source.substr(startPos + 1, nameValSepPos - (startPos + 1));
                    value = source.substr(nameValSepPos + 1, i - (nameValSepPos + 1));
                }

                res->elements.push_back(new Element(name, value));

                nameValSepPos = -1;
            }
        }
    }

    if (depth >= 1)
    {
        throw IllegalArgumentException("Missing closing elements");
    }

    return res;
}

AgString StringUtils::print(std::list<AgString> col)
{
    AgString sep;
    sep = DEFAULT_COLLECTION_PRINT_SEPARATOR;
    return print(col, sep, false);
}

AgString StringUtils::print(std::list<AgString> col, const AgString &separator)
{
    return print(col, separator, false);
}

AgString StringUtils::print(std::set<AgString> col, const AgString &separator)
{
    UNUSED(col);
    UNUSED(separator);
    assert(0);
    return "";
}

AgString StringUtils::print(std::list<AgString> col, const AgString &separator, bool skipNullElements)
{
  return print(col, separator, "", skipNullElements);
}

AgString StringUtils::print(std::list<AgString> col, const AgString &separator, const AgString &escaper, bool skipNullElements)
{
    if (col.empty())
      return "null";

    AgString result;
    int i = 0;

    std::list<AgString>::iterator it;

    for (it = col.begin(); it != col.end(); ++it)
    {
        if (it->empty() && skipNullElements)
            continue;

        if (i++ > 0)
            result += separator;

        result = result + (!it->empty() ? !escaper.empty() ? escaper + it->toString() + escaper : it->toString() : "null");
    }


    return result;
}



AgString StringUtils::colorToString(AgColor &color)
{
    UNUSED(color);
    return "";
}

std::vector<AgString> StringUtils::split(const AgString &str, uint16_t ch)
{
    return split(str, ch, -1);
}

std::vector<AgString> StringUtils::split(const AgString &str, uint16_t ch, int limit)
{
    std::vector<AgString> res;

    unsigned int index = 0;
    int newindex = 0;

    bool finished = false;

    for (;;)
    {
        newindex = str.find(ch, index);

        if (newindex == -1)
        {
            finished = true;
            newindex = str.length();
        }

        res.push_back(str.substr(index, newindex - index));

        if (limit > -1 && (int)res.size() >= limit)
        {
            int m = std::min<int>(newindex + 1, str.length() - 1);
            res.push_back(str.substr(m));
            break;
        }

        if (finished)
        {
            break;
        }

        index = newindex + 1;

        if (index == str.length())
        {
            res.push_back("");
            break;
        }
    }
    return res;
}

std::vector<AgString> StringUtils::splitRegExp(const AgString &s, const AgString &delim)
{
    std::vector<std::string> splitVec;
    std::string str1 = s.toUtf8();
    std::string utf8str = delim.toUtf8();

    boost::algorithm::split_regex( splitVec, str1, boost::regex( utf8str ) ) ;

    std::vector<AgString> res;
    for (std::vector<std::string>::iterator it = splitVec.begin(); it != splitVec.end(); ++it)
    {
        AgString agStr((*it).c_str());
        res.push_back(agStr);
    }
    return res;
}

/*std::vector<std::string> StringUtils::splitRegExp(const std::string & s, std::string rgx_str)
{
    std::vector<std::string> elems;

    std::regex rgx (rgx_str);

    std::sregex_token_iterator iter(s.begin(), s.end(), rgx, -1);
    std::sregex_token_iterator end;

    while (iter != end)
    {
        elems.push_back(*iter);
        ++iter;
    }

    return elems;
}*/
