var
    Location;


(function($) {
    "use strict";

    var
        self = window.location,

        escape = function(parameter) {
            return parameter.replace(/\$/, "\\$");
        },

        pattern = function(parameter) {
            parameter = escape(parameter);
            // better solution for now in JS, but select the catch (?, &)
            // (?:[?&])foo(?:=([^&#]+))?\b
            return new RegExp("(?:[?&])" + parameter +
                              "(?:=([^&#]+))?\\b", "g");
        },

        separator = function(captured) {
            return captured[0] ? captured[0] : "?";
        },

        clean = function(parameter) {
            return self.search.replace(pattern(parameter), function(captured) {
                return separator(captured) + parameter;
            });
        };


    try {

        Object.defineProperties($.prototype, {
            queryParameter: {
                value: function(parameter, value) {
                    if (parameter) parameter = parameter.trim();

                    var
                        uri = self.href,
                        search = self.search,
                        results,
                        regexp = pattern(parameter),

                        set = function(parameter, value) {
                            value = encodeURIComponent(value.toString().trim());

                            if (regexp.test(search)) {
                                if (value) {
                                    search = search.replace(regexp,
                                    function(captured, i, string) {
                                        return separator(captured) + parameter +
                                        "=" + value;
                                    });
                                } else {
                                    search = clean(parameter);
                                }
                                uri = self.origin + self
                                    .pathname + search + self.hash;
                            } else {
                                uri = window.location.origin + window.location
                                    .pathname + window.location.search +
                                    separator(search) + parameter + "=" +
                                    value + window.location.hash;
                            }

                            window.history.pushState("", "", uri);
                        };

                    if (value || typeof value == "string") {
                        set(parameter, value);
                        return self;
                    }

                    results = regexp.exec(search);
                    if (!results) return null;
                    return decodeURIComponent(results[1].replace(/\+/g, " "));
                }
            },

            unsetParameter: {
                value: function(parameter) {
                    var
                        uri = self.href,
                        search = self.search;

                    if (parameter) parameter = parameter.trim();

                    if (pattern(parameter).test(search)) {
                        search = clean(parameter);
                        uri = self.origin + self
                            .pathname + search + self.hash;
                    }

                    window.history.pushState("", "", uri);

                    return self;
                }
            }
        });

    } catch(e) {}

})(Location);

// the solution with positive lookbehind. Works in Python.
// (?<=(?:[?&]))foo(?:=[^&#]+)?\b
// the string for test
// ?foo=bar&foo=bar&foo&nonfoo=bar&nonfoo&foo#foo=bar