#include "StringUtils.h"
#include <locale>
#include <algorithm>
#include <sstream>
#include <iomanip>

#ifdef _WIN32
#include "Windows.h"
#endif

bool StringUtils::IsAlphaNumeric(char c)
{
    std::locale loc;
    return std::isalnum(c, loc);
}

bool StringUtils::IsSpace(char c)
{
    std::locale loc;
    return std::isspace(c, loc);
}

std::string StringUtils::strip(const std::string& input)
{
    if (input.empty())
    {
        return {};
    }

    std::locale loc;
    std::string working_string;
    std::size_t first_nonspace = 0;
    std::size_t last_nonspace = working_string.size() - 1;
    for (std::size_t idx = 0; idx < working_string.size(); idx++)
    {
        if (!std::isspace(working_string[idx], loc))
        {
            first_nonspace = idx;
            break;
        }
    }

    if (first_nonspace == last_nonspace)
    {
        return {};
    }

    for (std::size_t idx = last_nonspace; idx > 0; idx--)
    {
        if (!std::isspace(working_string[idx], loc))
        {
            last_nonspace = idx;
            break;
        }
    }
    return working_string.substr(first_nonspace, last_nonspace-first_nonspace);
}

std::vector<std::string> StringUtils::split(const std::string& input)
{
    std::vector<std::string> substrings;
    std::string working_string;
    std::locale loc;
    bool last_was_nonspace{ false };
    for (auto c : input)
    {
        if (std::isspace(c, loc))
        {
            if (last_was_nonspace)
            {
                substrings.push_back(working_string);
                working_string = "";
                last_was_nonspace = false;
            }
        }
        else
        {
            last_was_nonspace = true;
            working_string += c;
        }
    }
    if (!working_string.empty())
    {
        substrings.push_back(working_string);
    }
    return substrings;
}


std::string StringUtils::ToLower(const std::string& s)
{
    std::string ret;
    std::transform(s.begin(), s.end(), ret.begin(),
            [](unsigned char c){ return std::tolower(c); });
    return ret;
}

std::string StringUtils::convert(const std::wstring& input)
{
    if (input.empty())
    {
        return std::string();
    }

#ifdef _WIN32
    const auto size = ::WideCharToMultiByte(CP_UTF8, 0, &input[0], 
        (int)input.size(), nullptr, 0, nullptr, nullptr);

    std::string result(size, 0);
    ::WideCharToMultiByte(CP_UTF8, 0, &input[0], (int)input.size(), 
        &result[0], size, nullptr, nullptr);
    return result;
#else
    throw std::logic_error("Not implemented");
#endif
}

std::string StringUtils::ToPaddedString(unsigned numBytes, unsigned entry)
{
    std::stringstream sstr;
    sstr << std::setfill('0') << std::setw(numBytes) << entry;
    return sstr.str();
}

std::string StringUtils::stripQuotes(const std::string& input)
{
    if (input.size() < 3)
    {
        return input;
    }
    std::size_t start_index = 0;
    std::size_t end_index = input.size()-1;
    if (input[start_index] == '"')
    {
        start_index = 1;
    }
    if (input[end_index] == '"')
    {
        end_index = end_index - 1;
    }
    return input.substr(start_index, end_index - start_index + 1);
}
