import { StringReader } from './string_reader'

export class Url {

static fromString(url, referenceUrl){
    const out = new Url()
    url = new StringReader(url)
    if(!(referenceUrl instanceof Url)){
        referenceUrl = Url.fromString(referenceUrl || window.location, new Url())
    }

    let matches;

    if(matches = url.match(/^([a-z]+):\/\/([a-z\.-]+)/i)){
        out.protocol = matches[1].toLowerCase()
        out.host = matches[2].toLowerCase()
        if(matches = url.match(/^:(\d+)/)){
            out.port = parseInt(matches[1])
        }
    } else {
        out.protocol = referenceUrl.protocol
        out.host = referenceUrl.host
        out.port = referenceUrl.port
    }

    if(matches = url.match(/^\/[^\?\#]*/)){
        out.path = normalizePath(matches[0])
    } else if(matches = url.match(/^[^\?\#]+/)){
        out.path = normalizePath(`${referenceUrl.path.replace(/[^\/]*$/, '')}${matches[0]}`)
    } else {
        out.path = referenceUrl.path
    }

    if(matches = url.match(/^\?([^\#]*)/)){
        matches[1].split(/&/).forEach((pair) => {
            const [key, value] = pair.split(/=/)
            out.params[decodeURIComponent(key)] = decodeURIComponent(value)
        })
    }

    return out
}

constructor(protocol = 'http', host = 'localhost', port = 80, path = '/', params = {}){
    this.protocol = protocol
    this.host = host
    this.port = port
    this.path = path
    this.params = params
}

toString(){
    const out = [`${this.protocol}://${this.host}`]

    const defaultPort = this.protocol == 'https' ? 443 : 80
    if(this.port != defaultPort){
        out.push(`:${this.port}`)
    }

    out.push(this.path)

    const pairs = []
    Object.keys(this.params).forEach((key) => {
        pairs.push(`${encodeURIComponent(key)}=${encodeURIComponent(this.params[key])}`)
    })
    if(pairs.length > 0){
        out.push(`?${pairs.join('&')}`)
    }

    return out.join('')
}

get defaultPort(){
    if(this.protocol == 'https'){
        return 443
    } else {
        return 80
    }
}

}

function normalizePath(path){

const out = []
path.split(/\//).forEach((segment) => {
    if(segment == '..'){
        out.pop()
    } else if(segment != '.'){
        out.push(segment);
    }
})
return out.join('/');

}