
use utils
use type

+ fn encode_value(json: Value, pretty: type:bool (false)) String {
    let bb = utils:ByteBuffer.new(100)
    encode_value_buf(json, bb, 0, pretty)
    return bb.to_string()
}

fn encode_value_buf(val: Value, result: utils:ByteBuffer, depth: type:uint, pretty: type:bool) {
    if val.type == type_object {
        result.append_str("{")
        depth++
        let vals = val.object_values
        if isset(vals) {
            let count = 0
            each vals as sub, key {
                if count++ > 0 {
                    result.append_str(",")
                }
                if pretty : indent(result, depth)
                result.append_str("\"")
                result.append_str(key)
                result.append_str("\"")
                result.append_str(pretty ? ": " : ":")
                encode_value_buf(sub, result, depth, pretty)
            }
        }
        depth--
        if pretty : indent(result, depth)
        result.append_str("}")
        return
    }
    if val.type == type_array {
        result.append_str("[")
        let vals = val.array_values
        if isset(vals) {
            each vals as sub, i {
                if i > 0 {
                    result.append_str(", ")
                }
                encode_value_buf(sub, result, depth, pretty)
            }
        }
        result.append_str("]")
        return
    }
    if val.type == type_string {
        result.append_str("\"")
        result.append_str(val.string_value.escape())
        result.append_str("\"")
        return
    }
    if val.type == type_number {
        if val.float_value != 0 {
            let fstr = val.float_value.to_str(10).rtrim("0")
            if fstr.get(fstr.length - 1) == '.' : fstr += "0"
            result.append_str(fstr)
            return
        }
        result.append_str(val.int_value)
        return
    }
    if val.type == type_null {
        result.append_str("null")
        return
    }
    if val.type == type_bool {
        result.append_str(val.bool_value ? "true" : "false")
        return
    }
}

fn indent(result: utils:ByteBuffer, depth: type:uint) {
    result.append_str("\n")
    while depth-- > 0 {
        result.append_str("    ")
    }
}
