'use strict';

var has = Object.prototype.hasOwnProperty
    , undef;

/**
 * Decode a URI encoded string.
 *
 * @param {String} input The URI encoded string.
 * @returns {String} The decoded string.
 * @api private
 */
function decode(input) {
    return decodeURIComponent(input.replace(/\+/g, ' '));
}

/**
 * Simple query string parser.
 *
 * @param {String} query The query string that needs to be parsed.
 * @returns {Object}
 * @api public
 */
export function parse(query) {
    var parser = /([^=?&]+)=?([^&]*)/g
        , result = {}
        , part;

    while (part = parser.exec(query)) {
        var key = decode(part[1])
            , value = decode(part[2]);

        //
        // Prevent overriding of existing properties. This ensures that build-in
        // methods like `toString` or __proto__ are not overriden by malicious
        // querystrings.
        //
        if (key in result) continue;
        result[key] = value;
    }

    return result;
}

/**
 * Transform a query string to an object.
 *
 * @param {Object} obj Object that should be transformed.
 * @param {String} prefix Optional prefix.
 * @returns {String}
 * @api public
 */
export function stringify(obj, prefix) {
    prefix = prefix || '';

    var pairs = []
        , value
        , key;

    //
    // Optionally prefix with a '?' if needed
    //
    if ('string' !== typeof prefix) prefix = '?';

    for (key in obj) {
        if (has.call(obj, key)) {
            value = obj[key];

            //
            // Edge cases where we actually want to encode the value to an empty
            // string instead of the stringified value.
            //
            if (!value && (value === null || value === undef || isNaN(value))) {
                value = '';
            }

            pairs.push(encodeURIComponent(key) +'='+ encodeURIComponent(value));
        }
    }

    return pairs.length ? prefix + pairs.join('&') : '';
}