#include <algorithm>
#include <Windows.h>
#include "utils.h"


//@brief:delete the space in the head and end
std::string StringTrim(std::string str)
{
	if (str.empty())
	{
		return str;
	}

	str.erase(0, str.find_first_not_of(" "));
	str.erase(str.find_last_not_of(" ") + 1);

	return str;
}

//@brief:Turn the string lowercase
std::string StringLower(std::string str)
{
	if (str.empty()) return str;

	std::transform(str.begin(), str.end(), str.begin(), ::tolower);

	return str;
}

std::string toISO8601Time(std::time_t& time) {
	char buffer[32];
	strftime(buffer, sizeof(buffer), "%Y%m%dT%H%M%SZ", gmtime(&time));
	std::string str(buffer);
	return str;
}

std::string uriDecode(std::string& str) {
    char ch, c, decoded;
	std::string encodedStr = "";
    enum {
        sw_usual = 0,
        sw_quoted,
        sw_quoted_second
    } state;

    state = sw_usual;
    decoded = 0;
	for (unsigned int i = 0; i < str.length(); i++) {

        ch = str[i];

        switch (state) {
        case sw_usual:

            if (ch == '%') {
                state = sw_quoted;
                break;
            }

            if (ch == '+') {
				encodedStr += ' ';
                break;
            }

			encodedStr += ch;
            break;

        case sw_quoted:

            if (ch >= '0' && ch <= '9') {
                decoded = (unsigned char)(ch - '0');
                state = sw_quoted_second;
                break;
            }

            c = (unsigned char)(ch | 0x20);
            if (c >= 'a' && c <= 'f') {
                decoded = (unsigned char)(c - 'a' + 10);
                state = sw_quoted_second;
                break;
            }

            /* the invalid quoted character */

            state = sw_usual;

			encodedStr += ch;

            break;

        case sw_quoted_second:

            state = sw_usual;

            if (ch >= '0' && ch <= '9') {
                ch = (unsigned char)((decoded << 4) + ch - '0');


				encodedStr += ch;

                break;
            }

            c = (unsigned char)(ch | 0x20);
            if (c >= 'a' && c <= 'f') {
                ch = (unsigned char)((decoded << 4) + c - 'a' + 10);

				encodedStr += ch;

                break;
            }

            /* the invalid quoted character */

            break;
        }
    }
    return encodedStr;

}


std::string uriEncode(std::string& str, bool path) {
    static unsigned char hex[] = "0123456789ABCDEF";
    std::string encodedStr = "";
    if (str.empty()) {
        return encodedStr;
    }
    for (unsigned int i = 0; i < str.length(); i++) {
        unsigned char c = str[i];
        if (isalnum(c) || c == '.' || c == '~' || c == '_' || c == '-' || (path && c == '/')) {
            encodedStr += str[i];
        }
        else {
            encodedStr += '%';
            encodedStr += hex[c >> 4];
            encodedStr += hex[c & 0xf];
        }
    }
    return encodedStr;
}

//@brief:UTF8תstring
std::string utf8_to_string(const std::string &str)
{
	int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);

	wchar_t * pwBuf = new wchar_t[nwLen + 1];//Be sure to add 1, otherwise there will be a tail
	memset(pwBuf, 0, nwLen * 2 + 2);

	MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char * pBuf = new char[nLen + 1];
	memset(pBuf, 0, nLen + 1);

	WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr = pBuf;

	delete[]pBuf;
	delete[]pwBuf;

	pBuf = NULL;
	pwBuf = NULL;

	return retStr;
}

//@brief:stringתUTF8
std::string string_to_utf8(const std::string & str)
{
	int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);

	wchar_t * pwBuf = new wchar_t[nwLen + 1];//Be sure to add 1, otherwise there will be a tail 
	ZeroMemory(pwBuf, nwLen * 2 + 2);

	::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);

	int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);

	char * pBuf = new char[nLen + 1];
	ZeroMemory(pBuf, nLen + 1);

	::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);

	std::string retStr(pBuf);

	delete[]pwBuf;
	delete[]pBuf;

	pwBuf = NULL;
	pBuf = NULL;

	return retStr;
}