/*
 PNotify 2.0.1 sciactive.com/pnotify/
 (C) 2014 Hunter Perrin
 license GPL/LGPL/MPL
 */
/*
 * ====== PNotify ======
 *
 * http://sciactive.com/pnotify/
 *
 * Copyright 2009-2014 Hunter Perrin
 *
 * Triple licensed under the GPL, LGPL, and MPL.
 * 	http://gnu.org/licenses/gpl.html
 * 	http://gnu.org/licenses/lgpl.html
 * 	http://mozilla.org/MPL/MPL-1.1.html
 */

// Uses AMD or browser globals for jQuery.
(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as a module.
        define('pnotify', ['jquery'], factory);
    } else {
        // Browser globals
        factory(jQuery);
    }
}(function ($) {
    var default_stack = {
        dir1: "down",
        dir2: "left",
        push: "bottom",
        spacing1: 25,
        spacing2: 25,
        context: $("body")
    };
    var timer, // Position all timer.
        body,
        jwindow = $(window);
    // Set global variables.
    var do_when_ready = function () {
        body = $("body");
        PNotify.prototype.options.stack.context = body;
        jwindow = $(window);
        // Reposition the notices when the window resizes.
        jwindow.bind('resize', function () {
            if (timer)
                clearTimeout(timer);
            timer = setTimeout(function () {
                PNotify.positionAll(true)
            }, 10);
        });
    };
    PNotify = function (options) {
        this.parseOptions(options);
        this.init();
    };
    $.extend(PNotify.prototype, {
        // The current version of PNotify.
        version: "2.0.1",

        // === Options ===

        // Options defaults.
        options: {
            // The notice's title.
            title: false,
            // Whether to escape the content of the title. (Not allow HTML.)
            title_escape: false,
            // The notice's text.
            text: false,
            // Whether to escape the content of the text. (Not allow HTML.)
            text_escape: false,
            // What styling classes to use. (Can be either jqueryui or bootstrap.)
            styling: "bootstrap3",
            // Additional classes to be added to the notice. (For custom styling.)
            addclass: "",
            // Class to be added to the notice for corner styling.
            cornerclass: "",
            // Display the notice when it is created.
            auto_display: true,
            // Width of the notice.
            width: "300px",
            // Minimum height of the notice. It will expand to fit content.
            min_height: "16px",
            // Type of the notice. "notice", "info", "success", or "error".
            type: "notice",
            // Set icon to true to use the default icon for the selected
            // style/type, false for no icon, or a string for your own icon class.
            icon: true,
            // Opacity of the notice.
            opacity: 1,
            // The animation to use when displaying and hiding the notice. "none",
            // "show", "fade", and "slide" are built in to jQuery. Others require jQuery
            // UI. Use an object with effect_in and effect_out to use different effects.
            animation: "fade",
            // Speed at which the notice animates in and out. "slow", "def" or "normal",
            // "fast" or number of milliseconds.
            animate_speed: "slow",
            // Specify a specific duration of position animation
            position_animate_speed: 500,
            // Display a drop shadow.
            shadow: true,
            // After a delay, remove the notice.
            hide: true,
            // Delay in milliseconds before the notice is removed.
            delay: 8000,
            // Reset the hide timer if the mouse moves over the notice.
            mouse_reset: true,
            // Remove the notice's elements from the DOM after it is removed.
            remove: true,
            // Change new lines to br tags.
            insert_brs: true,
            // Whether to remove notices from the global array.
            destroy: true,
            // The stack on which the notices will be placed. Also controls the
            // direction the notices stack.
            stack: default_stack
        },

        // === Modules ===

        // This object holds all the PNotify modules. They are used to provide
        // additional functionality.
        modules: {},
        // This runs an event on all the modules.
        runModules: function (event, arg) {
            var curArg;
            for (var module in this.modules) {
                curArg = ((typeof arg === "object" && module in arg) ? arg[module] : arg);
                if (typeof this.modules[module][event] === 'function')
                    this.modules[module][event](this, typeof this.options[module] === 'object' ? this.options[module] : {}, curArg);
            }
        },

        // === Class Variables ===

        state: "initializing", // The state can be "initializing", "opening", "open", "closing", and "closed".
        timer: null, // Auto close timer.
        styles: null,
        elem: null,
        container: null,
        title_container: null,
        text_container: null,
        animating: false, // Stores what is currently being animated (in or out).
        timerHide: false, // Stores whether the notice was hidden by a timer.

        // === Events ===

        init: function () {
            var that = this;

            // First and foremost, we don't want our module objects all referencing the prototype.
            this.modules = {};
            $.extend(true, this.modules, PNotify.prototype.modules);

            // Get our styling object.
            if (typeof this.options.styling === "object") {
                this.styles = this.options.styling;
            } else {
                this.styles = PNotify.styling[this.options.styling];
            }

            // Create our widget.
            // Stop animation, reset the removal timer when the user mouses over.
            this.elem = $("<div />", {
                "class": "ui-pnotify " + this.options.addclass,
                "css": {"display": "none"},
                "mouseenter": function (e) {
                    if (that.options.mouse_reset && that.animating === "out") {
                        if (!that.timerHide)
                            return;
                        that.cancelRemove();
                    }
                    // Stop the close timer.
                    if (that.options.hide && that.options.mouse_reset) that.cancelRemove();
                },
                "mouseleave": function (e) {
                    // Start the close timer.
                    if (that.options.hide && that.options.mouse_reset) that.queueRemove();
                    PNotify.positionAll();
                }
            });
            // Create a container for the notice contents.
            this.container = $("<div />", {"class": this.styles.container + " ui-pnotify-container " + (this.options.type === "error" ? this.styles.error : (this.options.type === "info" ? this.styles.info : (this.options.type === "success" ? this.styles.success : this.styles.notice)))})
                .appendTo(this.elem);
            if (this.options.cornerclass !== "")
                this.container.removeClass("ui-corner-all").addClass(this.options.cornerclass);
            // Create a drop shadow.
            if (this.options.shadow)
                this.container.addClass("ui-pnotify-shadow");


            // Add the appropriate icon.
            if (this.options.icon !== false) {
                $("<div />", {"class": "ui-pnotify-icon"})
                    .append($("<i />", {"class": this.options.icon === true ? (this.options.type === "error" ? this.styles.error_icon : (this.options.type === "info" ? this.styles.info_icon : (this.options.type === "success" ? this.styles.success_icon : this.styles.notice_icon))) : this.options.icon}))
                    .prependTo(this.container);
            }

            // Add a title.
            this.title_container = $("<h4 />", {
                "class": "ui-pnotify-title"
            })
                .appendTo(this.container);
            if (this.options.title === false)
                this.title_container.hide();
            else if (this.options.title_escape)
                this.title_container.text(this.options.title);
            else
                this.title_container.html(this.options.title);

            // Add text.
            this.text_container = $("<div />", {
                "class": "ui-pnotify-text"
            })
                .appendTo(this.container);
            if (this.options.text === false)
                this.text_container.hide();
            else if (this.options.text_escape)
                this.text_container.text(this.options.text);
            else
                this.text_container.html(this.options.insert_brs ? String(this.options.text).replace(/\n/g, "<br />") : this.options.text);

            // Set width and min height.
            if (typeof this.options.width === "string")
                this.elem.css("width", this.options.width);
            if (typeof this.options.min_height === "string")
                this.container.css("min-height", this.options.min_height);


            // Add the notice to the notice array.
            if (this.options.stack.push === "top")
                PNotify.notices = $.merge([this], PNotify.notices);
            else
                PNotify.notices = $.merge(PNotify.notices, [this]);
            // Now position all the notices if they are to push to the top.
            if (this.options.stack.push === "top")
                this.queuePosition(false, 1);


            // Mark the stack so it won't animate the new notice.
            this.options.stack.animation = false;

            // Run the modules.
            this.runModules('init');

            // Display the notice.
            if (this.options.auto_display)
                this.open();
            return this;
        },

        // This function is for updating the notice.
        update: function (options) {
            // Save old options.
            var oldOpts = this.options;
            // Then update to the new options.
            this.parseOptions(oldOpts, options);
            // Update the corner class.
            if (this.options.cornerclass !== oldOpts.cornerclass)
                this.container.removeClass("ui-corner-all " + oldOpts.cornerclass).addClass(this.options.cornerclass);
            // Update the shadow.
            if (this.options.shadow !== oldOpts.shadow) {
                if (this.options.shadow)
                    this.container.addClass("ui-pnotify-shadow");
                else
                    this.container.removeClass("ui-pnotify-shadow");
            }
            // Update the additional classes.
            if (this.options.addclass === false)
                this.elem.removeClass(oldOpts.addclass);
            else if (this.options.addclass !== oldOpts.addclass)
                this.elem.removeClass(oldOpts.addclass).addClass(this.options.addclass);
            // Update the title.
            if (this.options.title === false)
                this.title_container.slideUp("fast");
            else if (this.options.title !== oldOpts.title) {
                if (this.options.title_escape)
                    this.title_container.text(this.options.title);
                else
                    this.title_container.html(this.options.title);
                if (oldOpts.title === false)
                    this.title_container.slideDown(200)
            }
            // Update the text.
            if (this.options.text === false) {
                this.text_container.slideUp("fast");
            } else if (this.options.text !== oldOpts.text) {
                if (this.options.text_escape)
                    this.text_container.text(this.options.text);
                else
                    this.text_container.html(this.options.insert_brs ? String(this.options.text).replace(/\n/g, "<br />") : this.options.text);
                if (oldOpts.text === false)
                    this.text_container.slideDown(200)
            }
            // Change the notice type.
            if (this.options.type !== oldOpts.type)
                this.container.removeClass(
                        this.styles.error + " " + this.styles.notice + " " + this.styles.success + " " + this.styles.info
                    ).addClass(this.options.type === "error" ?
                        this.styles.error :
                        (this.options.type === "info" ?
                            this.styles.info :
                            (this.options.type === "success" ?
                                this.styles.success :
                                this.styles.notice
                                )
                            )
                    );
            if (this.options.icon !== oldOpts.icon || (this.options.icon === true && this.options.type !== oldOpts.type)) {
                // Remove any old icon.
                this.container.find("div.ui-pnotify-icon").remove();
                if (this.options.icon !== false) {
                    // Build the new icon.
                    $("<div />", {"class": "ui-pnotify-icon"})
                        .append($("<span />", {"class": this.options.icon === true ? (this.options.type === "error" ? this.styles.error_icon : (this.options.type === "info" ? this.styles.info_icon : (this.options.type === "success" ? this.styles.success_icon : this.styles.notice_icon))) : this.options.icon}))
                        .prependTo(this.container);
                }
            }
            // Update the width.
            if (this.options.width !== oldOpts.width)
                this.elem.animate({width: this.options.width});
            // Update the minimum height.
            if (this.options.min_height !== oldOpts.min_height)
                this.container.animate({minHeight: this.options.min_height});
            // Update the opacity.
            if (this.options.opacity !== oldOpts.opacity)
                this.elem.fadeTo(this.options.animate_speed, this.options.opacity);
            // Update the timed hiding.
            if (!this.options.hide)
                this.cancelRemove();
            else if (!oldOpts.hide)
                this.queueRemove();
            this.queuePosition(true);

            // Run the modules.
            this.runModules('update', oldOpts);
            return this;
        },

        // Display the notice.
        open: function () {
            this.state = "opening";
            // Run the modules.
            this.runModules('beforeOpen');

            var that = this;
            // If the notice is not in the DOM, append it.
            if (!this.elem.parent().length)
                this.elem.appendTo(this.options.stack.context ? this.options.stack.context : body);
            // Try to put it in the right position.
            if (this.options.stack.push !== "top")
                this.position(true);
            // First show it, then set its opacity, then hide it.
            if (this.options.animation === "fade" || this.options.animation.effect_in === "fade") {
                // If it's fading in, it should start at 0.
                this.elem.show().fadeTo(0, 0).hide();
            } else {
                // Or else it should be set to the opacity.
                if (this.options.opacity !== 1)
                    this.elem.show().fadeTo(0, this.options.opacity).hide();
            }
            this.animateIn(function () {
                that.queuePosition(true);

                // Now set it to hide.
                if (that.options.hide)
                    that.queueRemove();

                that.state = "open";

                // Run the modules.
                that.runModules('afterOpen');
            });

            return this;
        },

        // Remove the notice.
        remove: function (timer_hide) {
            this.state = "closing";
            this.timerHide = !!timer_hide; // Make sure it's a boolean.
            // Run the modules.
            this.runModules('beforeClose');

            var that = this;
            if (this.timer) {
                window.clearTimeout(this.timer);
                this.timer = null;
            }
            this.animateOut(function () {
                that.state = "closed";
                // Run the modules.
                that.runModules('afterClose');
                that.queuePosition(true);
                // If we're supposed to remove the notice from the DOM, do it.
                if (that.options.remove)
                    that.elem.detach();
                // Run the modules.
                that.runModules('beforeDestroy');
                // Remove object from PNotify.notices to prevent memory leak (issue #49)
                // unless destroy is off
                if (that.options.destroy) {
                    if (PNotify.notices !== null) {
                        var idx = $.inArray(that, PNotify.notices);
                        if (idx !== -1) {
                            PNotify.notices.splice(idx, 1);
                        }
                    }
                }
                // Run the modules.
                that.runModules('afterDestroy');
            });

            return this;
        },

        // === Class Methods ===

        // Get the DOM element.
        get: function () {
            return this.elem;
        },

        // Put all the options in the right places.
        parseOptions: function (options, moreOptions) {
            this.options = $.extend(true, {}, PNotify.prototype.options);
            // This is the only thing that *should* be copied by reference.
            this.options.stack = PNotify.prototype.options.stack;
            var optArray = [options, moreOptions], curOpts;
            for (var curIndex in optArray) {
                curOpts = optArray[curIndex];
                if (typeof curOpts == "undefined")
                    break;
                if (typeof curOpts !== 'object') {
                    this.options.text = curOpts;
                } else {
                    for (var option in curOpts) {
                        if (this.modules[option]) {
                            // Avoid overwriting module defaults.
                            $.extend(true, this.options[option], curOpts[option]);
                        } else {
                            this.options[option] = curOpts[option];
                        }
                    }
                }
            }
        },

        // Animate the notice in.
        animateIn: function (callback) {
            // Declare that the notice is animating in. (Or has completed animating in.)
            this.animating = "in";
            var animation;
            if (typeof this.options.animation.effect_in !== "undefined")
                animation = this.options.animation.effect_in;
            else
                animation = this.options.animation;
            if (animation === "none") {
                this.elem.show();
                callback();
            } else if (animation === "show")
                this.elem.show(this.options.animate_speed, callback);
            else if (animation === "fade")
                this.elem.show().fadeTo(this.options.animate_speed, this.options.opacity, callback);
            else if (animation === "slide")
                this.elem.slideDown(this.options.animate_speed, callback);
            else if (typeof animation === "function")
                animation("in", callback, this.elem);
            else
                this.elem.show(animation, (typeof this.options.animation.options_in === "object" ? this.options.animation.options_in : {}), this.options.animate_speed, callback);
            if (this.elem.parent().hasClass('ui-effects-wrapper'))
                this.elem.parent().css({"position": "fixed", "overflow": "visible"});
            if (animation !== "slide")
                this.elem.css("overflow", "visible");
            this.container.css("overflow", "hidden");
        },

        // Animate the notice out.
        animateOut: function (callback) {
            // Declare that the notice is animating out. (Or has completed animating out.)
            this.animating = "out";
            var animation;
            if (typeof this.options.animation.effect_out !== "undefined")
                animation = this.options.animation.effect_out;
            else
                animation = this.options.animation;
            if (animation === "none") {
                this.elem.hide();
                callback();
            } else if (animation === "show")
                this.elem.hide(this.options.animate_speed, callback);
            else if (animation === "fade")
                this.elem.fadeOut(this.options.animate_speed, callback);
            else if (animation === "slide")
                this.elem.slideUp(this.options.animate_speed, callback);
            else if (typeof animation === "function")
                animation("out", callback, this.elem);
            else
                this.elem.hide(animation, (typeof this.options.animation.options_out === "object" ? this.options.animation.options_out : {}), this.options.animate_speed, callback);
            if (this.elem.parent().hasClass('ui-effects-wrapper'))
                this.elem.parent().css({"position": "fixed", "overflow": "visible"});
            if (animation !== "slide")
                this.elem.css("overflow", "visible");
            this.container.css("overflow", "hidden");
        },

        // Position the notice. dont_skip_hidden causes the notice to
        // position even if it's not visible.
        position: function (dontSkipHidden) {
            // Get the notice's stack.
            var s = this.options.stack,
                e = this.elem;
            if (e.parent().hasClass('ui-effects-wrapper'))
                e = this.elem.css({"left": "0", "top": "0", "right": "0", "bottom": "0"}).parent();
            if (typeof s.context === "undefined")
                s.context = body;
            if (!s) return;
            if (typeof s.nextpos1 !== "number")
                s.nextpos1 = s.firstpos1;
            if (typeof s.nextpos2 !== "number")
                s.nextpos2 = s.firstpos2;
            if (typeof s.addpos2 !== "number")
                s.addpos2 = 0;
            var hidden = e.css("display") === "none";
            // Skip this notice if it's not shown.
            if (!hidden || dontSkipHidden) {
                var curpos1, curpos2;
                // Store what will need to be animated.
                var animate = {};
                // Calculate the current pos1 value.
                var csspos1;
                switch (s.dir1) {
                    case "down":
                        csspos1 = "top";
                        break;
                    case "up":
                        csspos1 = "bottom";
                        break;
                    case "left":
                        csspos1 = "right";
                        break;
                    case "right":
                        csspos1 = "left";
                        break;
                }
                curpos1 = parseInt(e.css(csspos1).replace(/(?:\..*|[^0-9.])/g, ''));
                if (isNaN(curpos1))
                    curpos1 = 0;
                // Remember the first pos1, so the first visible notice goes there.
                if (typeof s.firstpos1 === "undefined" && !hidden) {
                    s.firstpos1 = curpos1;
                    s.nextpos1 = s.firstpos1;
                }
                // Calculate the current pos2 value.
                var csspos2;
                switch (s.dir2) {
                    case "down":
                        csspos2 = "top";
                        break;
                    case "up":
                        csspos2 = "bottom";
                        break;
                    case "left":
                        csspos2 = "right";
                        break;
                    case "right":
                        csspos2 = "left";
                        break;
                }
                curpos2 = parseInt(e.css(csspos2).replace(/(?:\..*|[^0-9.])/g, ''));
                if (isNaN(curpos2))
                    curpos2 = 0;
                // Remember the first pos2, so the first visible notice goes there.
                if (typeof s.firstpos2 === "undefined" && !hidden) {
                    s.firstpos2 = curpos2;
                    s.nextpos2 = s.firstpos2;
                }
                // Check that it's not beyond the viewport edge.
                if ((s.dir1 === "down" && s.nextpos1 + e.height() > (s.context.is(body) ? jwindow.height() : s.context.prop('scrollHeight')) ) ||
                    (s.dir1 === "up" && s.nextpos1 + e.height() > (s.context.is(body) ? jwindow.height() : s.context.prop('scrollHeight')) ) ||
                    (s.dir1 === "left" && s.nextpos1 + e.width() > (s.context.is(body) ? jwindow.width() : s.context.prop('scrollWidth')) ) ||
                    (s.dir1 === "right" && s.nextpos1 + e.width() > (s.context.is(body) ? jwindow.width() : s.context.prop('scrollWidth')) )) {
                    // If it is, it needs to go back to the first pos1, and over on pos2.
                    s.nextpos1 = s.firstpos1;
                    s.nextpos2 += s.addpos2 + (typeof s.spacing2 === "undefined" ? 25 : s.spacing2);
                    s.addpos2 = 0;
                }
                // Animate if we're moving on dir2.
                if (s.animation && s.nextpos2 < curpos2) {
                    switch (s.dir2) {
                        case "down":
                            animate.top = s.nextpos2 + "px";
                            break;
                        case "up":
                            animate.bottom = s.nextpos2 + "px";
                            break;
                        case "left":
                            animate.right = s.nextpos2 + "px";
                            break;
                        case "right":
                            animate.left = s.nextpos2 + "px";
                            break;
                    }
                } else {
                    if (typeof s.nextpos2 === "number")
                        e.css(csspos2, s.nextpos2 + "px");
                }
                // Keep track of the widest/tallest notice in the column/row, so we can push the next column/row.
                switch (s.dir2) {
                    case "down":
                    case "up":
                        if (e.outerHeight(true) > s.addpos2)
                            s.addpos2 = e.height();
                        break;
                    case "left":
                    case "right":
                        if (e.outerWidth(true) > s.addpos2)
                            s.addpos2 = e.width();
                        break;
                }
                // Move the notice on dir1.
                if (typeof s.nextpos1 === "number") {
                    // Animate if we're moving toward the first pos.
                    if (s.animation && (curpos1 > s.nextpos1 || animate.top || animate.bottom || animate.right || animate.left)) {
                        switch (s.dir1) {
                            case "down":
                                animate.top = s.nextpos1 + "px";
                                break;
                            case "up":
                                animate.bottom = s.nextpos1 + "px";
                                break;
                            case "left":
                                animate.right = s.nextpos1 + "px";
                                break;
                            case "right":
                                animate.left = s.nextpos1 + "px";
                                break;
                        }
                    } else
                        e.css(csspos1, s.nextpos1 + "px");
                }
                // Run the animation.
                if (animate.top || animate.bottom || animate.right || animate.left)
                    e.animate(animate, {duration: this.options.position_animate_speed, queue: false});
                // Calculate the next dir1 position.
                switch (s.dir1) {
                    case "down":
                    case "up":
                        s.nextpos1 += e.height() + (typeof s.spacing1 === "undefined" ? 25 : s.spacing1);
                        break;
                    case "left":
                    case "right":
                        s.nextpos1 += e.width() + (typeof s.spacing1 === "undefined" ? 25 : s.spacing1);
                        break;
                }
            }
            return this;
        },
        // Queue the position all function so it doesn't run repeatedly and
        // use up resources.
        queuePosition: function (animate, milliseconds) {
            if (timer)
                clearTimeout(timer);
            if (!milliseconds)
                milliseconds = 10;
            timer = setTimeout(function () {
                PNotify.positionAll(animate)
            }, milliseconds);
            return this;
        },


        // Cancel any pending removal timer.
        cancelRemove: function () {
            if (this.timer)
                window.clearTimeout(this.timer);
            if (this.state === "closing") {
                // If it's animating out, animate back in really quickly.
                this.elem.stop(true);
                this.state = "open";
                this.animating = "in";
                this.elem.css("height", "auto").animate({"width": this.options.width, "opacity": this.options.opacity}, "fast");
            }
            return this;
        },
        // Queue a removal timer.
        queueRemove: function () {
            var that = this;
            // Cancel any current removal timer.
            this.cancelRemove();
            this.timer = window.setTimeout(function () {
                that.remove(true);
            }, (isNaN(this.options.delay) ? 0 : this.options.delay));
            return this;
        }
    });
    // These functions affect all notices.
    $.extend(PNotify, {
        // This holds all the notices.
        notices: [],
        removeAll: function () {
            $.each(PNotify.notices, function () {
                if (this.remove)
                    this.remove();
            });
        },
        positionAll: function (animate) {
            // This timer is used for queueing this function so it doesn't run
            // repeatedly.
            if (timer)
                clearTimeout(timer);
            timer = null;
            // Reset the next position data.
            $.each(PNotify.notices, function () {
                var s = this.options.stack;
                if (!s) return;
                s.nextpos1 = s.firstpos1;
                s.nextpos2 = s.firstpos2;
                s.addpos2 = 0;
                s.animation = animate;
            });
            $.each(PNotify.notices, function () {
                this.position();
            });
        },
        styling: {
            jqueryui: {
                container: "ui-widget ui-widget-content ui-corner-all",
                notice: "ui-state-highlight",
                // (The actual jQUI notice icon looks terrible.)
                notice_icon: "ui-icon ui-icon-info",
                info: "",
                info_icon: "ui-icon ui-icon-info",
                success: "ui-state-default",
                success_icon: "ui-icon ui-icon-circle-check",
                error: "ui-state-error",
                error_icon: "ui-icon ui-icon-alert"
            },
            bootstrap2: {
                container: "alert",
                notice: "",
                notice_icon: "icon-exclamation-sign",
                info: "alert-info",
                info_icon: "icon-info-sign",
                success: "alert-success",
                success_icon: "icon-ok-sign",
                error: "alert-error",
                error_icon: "icon-warning-sign"
            },
            bootstrap3: {
                container: "alert",
                notice: "alert-warning",
                notice_icon: "glyphicon glyphicon-exclamation-sign",
                info: "alert-info",
                info_icon: "glyphicon glyphicon-info-sign",
                success: "alert-success",
                success_icon: "glyphicon glyphicon-ok-sign",
                error: "alert-danger",
                error_icon: "glyphicon glyphicon-warning-sign"
            }
        }
    });
    /*
     * uses icons from http://fontawesome.io/
     * version 4.0.3
     */
    PNotify.styling.fontawesome = $.extend({}, PNotify.styling.bootstrap3);
    $.extend(PNotify.styling.fontawesome, {
        notice_icon: "fa fa-exclamation-circle",
        info_icon: "fa fa-info",
        success_icon: "fa fa-check",
        error_icon: "fa fa-warning"
    });

    if (document.body)
        do_when_ready();
    else
        $(do_when_ready);
    return PNotify;
}));
