#include "inner_storage.h"

#include "jsonobj.h"

namespace json {
    json_t JSON::getType() const {
        return type;
    }

    bool JSON::isNull() const {
        return type == null_symbol;
    }

    bool JSON::isBool() const {
        return type == false_symbol || type == true_symbol;
    }

    bool JSON::isInteger() const {
        return type == integer;
    }

    bool JSON::isFalse() const {
        return type == false_symbol;
    }

    bool JSON::isTrue() const {
         return type == true_symbol;
    }

    bool JSON::isString() const {
        return type == string;
    }

    bool JSON::isArray() const {
        return type == array;
    }

    bool JSON::isDictionary() const {
        return type == dictionary;
    }

    bool JSON::isNatalistic() const {
        return type == array || type == dictionary;
    }

    bool JSON::isSymbol() const {
        return type == null_symbol || type == false_symbol || type == true_symbol;
    }

    bool JSON::toBool() const {
        switch(type) {
            case false_symbol:
                return false;
            case true_symbol:
                return true;
            default:
                throw misuse("json obj is not boolean");
        }
    }

    const Integer& JSON::asInteger() const {
        if (isInteger())
            return *((const Integer*)value);
        throw misuse("json obj is not integer");
    }

    const std::string& JSON::asString() const {
        if (isString())
            return *(const std::string*)value;
        throw misuse("json obj is not string");
    }

    const std::vector<JSON>& JSON::asArray() const {
        if (isArray())
            return static_cast<ArrayData*>(value)->data;
        throw misuse("json obj is not array");
    }

    const std::map<std::string, JSON>& JSON::asDictionary() const {
        if (isDictionary())
            return static_cast<DictionaryData*>(value)->data;
        throw misuse("json obj is not dictionary");
    }

    Integer & JSON::asInteger() {
        return const_cast<Integer&>(const_cast<const JSON*>(this)->asInteger());
    }

    std::string &JSON::asString() {
        return const_cast<std::string&>(const_cast<const JSON*>(this)->asString());
    }

    std::vector<JSON> &JSON::asArray() {
        return const_cast<std::vector<JSON>&>(const_cast<const JSON*>(this)->asArray());
    }

    std::map<std::string, JSON> &JSON::asDictionary() {
        return const_cast<std::map<std::string, JSON>&>(const_cast<const JSON*>(this)->asDictionary());
    }




    JSON_reference JSON::operator[](size_t index) {
        return r()[index];
    }

    JSON_reference JSON::operator[](const std::string &key) {
        return r()[key];
    }

    JSON_reference_const JSON::operator[](size_t index) const {
        return r()[index];
    }

    JSON_reference_const JSON::operator[](const std::string &key) const {
        return r()[key];
    }

    JSON& JSON::operator=(int64_t V) {
        nullify(*this);
        value = new Integer(V);
        type = integer;
        return *this;
    }

    JSON & JSON::operator=(const Integer &V) {
        nullify(*this);
        value = new Integer(V);
        type = integer;
        return *this;
    }

    JSON & JSON::operator=(const char *V) {
        nullify(*this);
        value = new std::string(V);
        type = string;
        return *this;
    }

    JSON & JSON::operator=(const std::string &V) {
        nullify(*this);
        value = new std::string(V);
        type = string;
        return *this;
    }

    bool JSON::operator==(const JSON &B) const {
        if (this == &B)
            return true;
        if (is_subtree_of(*this, B) || is_subtree_of(B, *this))
            return false;
        return eq_compare_json(*this, B);
    }

    bool JSON::operator!=(const JSON &B) const {
        return !eq_compare_json(*this, B);
    }
}