
use utils

+ fn encode(str: String) String {
    let data = str.data
    let bytes = str.bytes
    let buffer = utils:ByteBuffer.new(bytes)
    let i : uint = 0
    let utf8c : u8 = 0
    while i < bytes {
        let ch = @ptrv(data, u8, i++)
        // 33 - 126
        if utf8c == 0 && ch > 32 && ch < 127 {
            buffer.append_byte(ch)
            continue
        }
        // utf8
        if utf8c == 0 {
            if ch > 127 {
                let uch = ch << 1
                while uch > 127 {
                    utf8c++
                    uch = uch << 1
                }
            }
        } else {
            utf8c--
        }
        // ch -> %{HEX}
        buffer.append_byte('%')
        let x : u32 = 0
        let ref = @ref(x)
        let bytes_used = ch.to_base_to_ptr(16, ref)
        if bytes_used == 1 {
            @ptrv(ref, u8, 1) = @ptrv(ref, u8, 0)
            @ptrv(ref, u8, 0) = 0
        }
        buffer.append_from_ptr(ref, 2)
    }
    return buffer.to_string()
}

+ fn decode(str: String) String {
    let data = str.data
    let bytes = str.bytes
    let buffer = utils:ByteBuffer.new(bytes)
    let i : uint = 0
    let utf8c : u8 = 0
    while i < bytes {
        let ch = @ptrv(data, u8, i++)
        if ch == '+' {
            buffer.append_byte(' ')
            continue
        }
        if ch == '%' {
            if i + 1 < bytes {
                let n1 = @ptrv(data, u8, i)
                let n2 = @ptrv(data, u8, i + 1)
                if(n1.is_hex() && n2.is_hex()) {
                    i += 2
                    let v1 = n1.hex_byte_to_hex_value()
                    let v2 = n2.hex_byte_to_hex_value()
                    let value : u8 = v1 * 16 + v2
                    if utf8c > 0 {
                        utf8c--
                        buffer.append_byte(value)
                        continue
                    }
                    if value <= 127 {
                        buffer.append_byte(value)
                        continue
                    }
                    // Utf8 character
                    buffer.append_byte(value)
                    let uch = value << 1
                    while uch > 127 {
                        utf8c++
                        uch = uch << 1
                    }
                    continue
                }
            }
        }
        buffer.append_byte(ch)
    }
    return buffer.to_string()
}
