#include <sstream>
#include "parser.h"
#include "utils.h"

namespace json {
    std::string bad_near(const std::string &type, const unsigned int &pos) {
        std::ostringstream err;
        err << "bad type of '" << type << "' near position [" << pos << ']';
        return err.str();
    }

    std::string bad_near(const char &c, const unsigned int &pos) {
        std::ostringstream err;
        err << "bad character '" << c << "' near position [" << pos << ']';
        return err.str();
    }

    char Parser::next_real() {
        while (std::isspace(_str[_idx])) _idx++;
        return _str[_idx];
    }

    bool Parser::is_str_end(unsigned const &pos) {
        unsigned front = pos;
        while (_str[front] == '\\') front--;
        return (pos - front) % 2 == 0;
    }

    Value Parser::_parse() {
        char next = next_real();

        switch (next) {
            case 'n':
                return parse_null();
            case 't':
            case 'f':
                return parse_bool();
            case '-':
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return parse_number();
            case '"':
                return parse_string();
            case '[':
                return parse_list();
            case '{':
                return parse_dict();
            default:
                throw std::logic_error(bad_near(_str[_idx], _idx));
        }
    }

    Value Parser::parse_null() {
        if (_str.compare(_idx, 4, "null") == 0) {
            _idx += 4;
            return {};
        }
        throw std::logic_error(bad_near("null", _idx));
    }

    Value Parser::parse_bool() {
        if (_str.compare(_idx, 4, "true") == 0) {
            _idx += 4;
            return Value(true);
        }
        if (_str.compare(_idx, 5, "false") == 0) {
            _idx += 5;
            return Value(false);
        }
        throw std::logic_error(bad_near("bool", _idx));
    }

    Value Parser::parse_number() {
        unsigned start = _idx;
        if (_str[_idx] == '-') _idx++;
        if (std::isdigit(_str[_idx])) {
            while (std::isdigit(_str[_idx])) _idx++;
            // decimal
            if (_str[_idx] == '.') {
                _idx++;
                if (std::isdigit(_str[_idx])) {
                    while (std::isdigit(_str[_idx])) _idx++;
                    return Value(std::strtod(_str.c_str() + start, nullptr));
                } else throw std::logic_error(bad_near("number", _idx));
            }
            if (_str[_idx] != '.')
                return Value(std::strtol(_str.c_str() + start, nullptr, 10));
        } else throw std::logic_error(bad_near("number", _idx));
        // 不会到这里
        return {};
    }

    Value Parser::parse_string() {
        unsigned start = ++_idx;
        auto end = _str.find('"', _idx);
        if (end != std::string::npos) {
            // 可能是 \" 而不是真正的字符串结尾
            while (true) {
                if (is_str_end(end - 1)) break;
                end = _str.find('"', end + 1);
                if (end == std::string::npos) throw std::logic_error(bad_near("string", _idx));
            }
            _idx = end + 1;
            return Value(_str.substr(start, end - start));
        }
        throw std::logic_error(bad_near("string", _idx));
    }

    Value Parser::parse_list() {
        std::vector<Value> list;
        _idx++;
        char c;
        while (true) {
            c = next_real();
            if (c == ',') _idx++;
            else if (c == ']') {
                _idx++;
                return Value(list);
            } else list.push_back(_parse());
        }
    }

    Value Parser::parse_dict() {
        std::map<std::string, Value> dict;
        _idx++;
        char c;
        string_type key;
        while (true) {
            c = next_real();
            if (c == '"') {
                key = parse_string().value<string_type>();
                if (next_real() == ':') {
                    _idx++;
                    dict[key] = _parse();
                } else throw std::logic_error(bad_near("dict", _idx));
            } else if (c == ',') _idx++;
            else if (c == '}') {
                _idx++;
                return Value(dict);
            } else throw std::logic_error(bad_near("dict", _idx));
        }
    }

    Parser::Parser() {
        _str = "";
        _idx = 0;
    }

    Value Parser::parse(const std::string &str) {
        _str = hm::trim(str);
        auto max = _str.size() - 1;
        if (max < 0) throw std::logic_error("blank string");
        if (!((_str[0] == '{' && _str[max] == '}') || (_str[0] == '[' && _str[max] == ']')))
            throw std::logic_error("bad json string");
        _idx = 0;
        return _parse();
    }
}