/*! jQuery slidePanel - v0.2.1 - 2015-07-13
 * https://github.com/amazingSurge/jquery-slidePanel
 * Copyright (c) 2015 amazingSurge; Licensed GPL */
(function($, document, window, undefined) {
    "use strict";

    var SlidePanel = $.slidePanel = function() {
        SlidePanel.show.apply(this, arguments);
    };

    if (!Date.now) {
        Date.now = function() {
            return new Date().getTime();
        };
    }

    function getTime() {
        if (typeof window.performance !== 'undefined' && window.performance.now) {
            return window.performance.now();
        } else {
            return Date.now();
        }
    }

    var vendors = ['webkit', 'moz'];
    for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) {
        var vp = vendors[i];
        window.requestAnimationFrame = window[vp + 'RequestAnimationFrame'];
        window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] || window[vp + 'CancelRequestAnimationFrame']);
    }
    if (/iP(ad|hone|od).*OS (6|7|8)/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) {
        var lastTime = 0;
        window.requestAnimationFrame = function(callback) {
            var now = getTime();
            var nextTime = Math.max(lastTime + 16, now);
            return setTimeout(function() {
                    callback(lastTime = nextTime);
                },
                nextTime - now);
        };
        window.cancelAnimationFrame = clearTimeout;
    }

    var Support = (function() {
        var style = $('<support>').get(0).style,
            prefixes = ['webkit', 'Moz', 'O', 'ms'],
            events = {
                transition: {
                    end: {
                        WebkitTransition: 'webkitTransitionEnd',
                        MozTransition: 'transitionend',
                        OTransition: 'oTransitionEnd',
                        transition: 'transitionend'
                    }
                },
                animation: {
                    end: {
                        WebkitAnimation: 'webkitAnimationEnd',
                        MozAnimation: 'animationend',
                        OAnimation: 'oAnimationEnd',
                        animation: 'animationend'
                    }
                }
            },
            tests = {
                csstransforms: function() {
                    return !!test('transform');
                },
                csstransforms3d: function() {
                    return !!test('perspective');
                },
                csstransitions: function() {
                    return !!test('transition');
                },
                cssanimations: function() {
                    return !!test('animation');
                }
            };

        function test(property, prefixed) {
            var result = false,
                upper = property.charAt(0).toUpperCase() + property.slice(1);

            if (style[property] !== undefined) {
                result = property;
            }
            if (!result) {
                $.each(prefixes, function(i, prefix) {
                    if (style[prefix + upper] !== undefined) {
                        result = '-' + prefix.toLowerCase() + '-' + upper;
                        return false;
                    }
                });
            }

            if (prefixed) {
                return result;
            }
            if (result) {
                return true;
            } else {
                return false;
            }
        }

        function prefixed(property) {
            return test(property, true);
        }
        var support = {};
        if (tests.csstransitions()) {
            /* jshint -W053 */
            support.transition = new String(prefixed('transition'))
            support.transition.end = events.transition.end[support.transition];
        }

        if (tests.cssanimations()) {
            /* jshint -W053 */
            support.animation = new String(prefixed('animation'))
            support.animation.end = events.animation.end[support.animation];
        }

        if (tests.csstransforms()) {
            /* jshint -W053 */
            support.transform = new String(prefixed('transform'));
            support.transform3d = tests.csstransforms3d();
        }

        if (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch) {
            support.touch = true;
        } else {
            support.touch = false;
        }

        if (window.PointerEvent || window.MSPointerEvent) {
            support.pointer = true;
        } else {
            support.pointer = false;
        }

        support.prefixPointerEvent = function(pointerEvent) {
            return window.MSPointerEvent ?
                'MSPointer' + pointerEvent.charAt(9).toUpperCase() + pointerEvent.substr(10) :
                pointerEvent;
        }

        return support;
    })();

    function isPercentage(n) {
        return typeof n === 'string' && n.indexOf('%') != -1;
    }

    function isPx(n) {
        return typeof n === 'string' && n.indexOf('px') != -1;
    }

    function convertMatrixToArray(value) {
        if (value && (value.substr(0, 6) == "matrix")) {
            return value.replace(/^.*\((.*)\)$/g, "$1").replace(/px/g, '').split(/, +/);
        }
        return false;
    }

    function getHashCode(object) {
        if (typeof object !== 'string') {
            object = JSON.stringify(object);
        }

        var hash = 0,
            i, chr, len;
        if (object.length === 0) return hash;
        for (i = 0, len = object.length; i < len; i++) {
            chr = object.charCodeAt(i);
            hash = ((hash << 5) - hash) + chr;
            hash |= 0; // Convert to 32bit integer
        }

        return hash;
    }

    function easingBezier(mX1, mY1, mX2, mY2) {
        function a(aA1, aA2) {
            return 1.0 - 3.0 * aA2 + 3.0 * aA1;
        }

        function b(aA1, aA2) {
            return 3.0 * aA2 - 6.0 * aA1;
        }

        function c(aA1) {
            return 3.0 * aA1;
        }

        // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
        function calcBezier(aT, aA1, aA2) {
            return ((a(aA1, aA2) * aT + b(aA1, aA2)) * aT + c(aA1)) * aT;
        }

        // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
        function getSlope(aT, aA1, aA2) {
            return 3.0 * a(aA1, aA2) * aT * aT + 2.0 * b(aA1, aA2) * aT + c(aA1);
        }

        function getTForX(aX) {
            // Newton raphson iteration
            var aGuessT = aX;
            for (var i = 0; i < 4; ++i) {
                var currentSlope = getSlope(aGuessT, mX1, mX2);
                if (currentSlope === 0.0) return aGuessT;
                var currentX = calcBezier(aGuessT, mX1, mX2) - aX;
                aGuessT -= currentX / currentSlope;
            }
            return aGuessT;
        }

        if (mX1 === mY1 && mX2 === mY2) {
            return {
                css: 'linear',
                fn: function(aX) {
                    return aX;
                }
            };
        } else {
            return {
                css: 'cubic-bezier(' + mX1 + ',' + mY1 + ',' + mX2 + ',' + mY2 + ')',
                fn: function(aX) {
                    return calcBezier(getTForX(aX), mY1, mY2);
                }
            }
        }
    }

    var Easings = {
        'ease': easingBezier(0.25, 0.1, 0.25, 1.0),
        'linear': easingBezier(0.00, 0.0, 1.00, 1.0),
        'ease-in': easingBezier(0.42, 0.0, 1.00, 1.0),
        'ease-out': easingBezier(0.00, 0.0, 0.58, 1.0),
        'ease-in-out': easingBezier(0.42, 0.0, 0.58, 1.0)
    };

    SlidePanel.options = {
        skin: null,

        classes: {
            base: 'slidePanel',
            show: 'slidePanel-show',
            loading: 'slidePanel-loading',
            content: 'slidePanel-content',
            dragging: 'slidePanel-dragging',
            willClose: 'slidePanel-will-close'
        },

        closeSelector: null,

        template: function(options) {
            return '<div class="' + options.classes.base + ' ' + options.classes.base + '-' + options.direction + '">' +
                '<div class="' + options.classes.content + '"></div>' +
                '</div>';
        },

        loading: {
            appendTo: 'panel', // body, panel
            template: function(options) {
                return '<div class="' + options.classes.loading + '"></div>';
            },
            showCallback: function(options) {
                this.$el.addClass(options.classes.loading + '-show');
            },
            hideCallback: function(options) {
                this.$el.removeClass(options.classes.loading + '-show');
            }
        },

        contentFilter: function(content) {
            return content;
        },

        useCssTransforms3d: true,
        useCssTransforms: true,
        useCssTransitions: true,

        dragTolerance: 150,

        mouseDragHandler: null,
        mouseDrag: true,
        touchDrag: true,
        pointerDrag: true,

        direction: 'right', // top, bottom, left, right
        duration: '500',
        easing: 'ease', // linear, ease-in, ease-out, ease-in-out

        // callbacks
        beforeLoad: $.noop, // Before loading
        afterLoad: $.noop, // After loading
        beforeShow: $.noop, // Before opening
        afterShow: $.noop, // After opening
        onChange: $.noop, // On changing
        beforeChange: $.noop, // Before changing
        beforeHide: $.noop, // Before closing
        afterHide: $.noop, // After closing
        beforeDrag: $.noop, // Before drag
        afterDrag: $.noop // After drag
    };

    // View
    function View() {
        return this.initialize.apply(this, Array.prototype.slice.call(arguments));
    }

    $.extend(View.prototype, {
        initialize: function(options) {
            this.options = options;
            this._instance = null;
            this._showed = false;
            this._isLoading = false;

            this.build();
        },

        setLength: function() {
            switch (this.options.direction) {
                case 'top':
                case 'bottom':
                    this._length = this.$panel.outerHeight();
                    break;
                case 'left':
                case 'right':
                    this._length = this.$panel.outerWidth();
                    break;
            }
        },

        build: function() {
            if (this._builded) return;

            var options = this.options;

            var html = options.template.call(this, options);
            var self = this;

            this.$panel = $(html).appendTo('body');
            if (options.skin) {
                this.$panel.addClass(options.skin);
            }
            this.$content = this.$panel.find('.' + this.options.classes.content);

            if (options.closeSelector) {
                this.$panel.on('click', options.closeSelector, function() {
                    self.hide();
                    return false;
                });
            }
            this.loading = new Loading(this);

            this.setLength();
            this.setPosition(this.getHidePosition());

            if (options.mouseDrag || options.touchDrag || options.pointerDrag) {
                this.drag = new Drag(this);
            }

            this._builded = true;
        },

        getHidePosition: function() {
            var options = this.options;

            if (options.useCssTransforms || options.useCssTransforms3d) {
                switch (options.direction) {
                    case 'top':
                    case 'left':
                        return '-100';
                    case 'bottom':
                    case 'right':
                        return '100';
                }
            } else {
                switch (options.direction) {
                    case 'top':
                    case 'bottom':
                        return parseFloat(-(this._length / $(window).height()) * 100, 10);
                    case 'left':
                    case 'right':
                        return parseFloat(-(this._length / $(window).width()) * 100, 10);
                }
            }
        },

        empty: function() {
            this._instance = null;
            this.$content.empty();
        },

        load: function(object) {
            var self = this;
            var options = object.options;
            var previous = this._instance;

            _SlidePanel.trigger(this, 'beforeLoad', object);
            this.empty();

            function setContent(content) {
                content = options.contentFilter.call(this, content);
                self.$content.html(content);
                self.hideLoading();

                self._instance = object;

                _SlidePanel.trigger(self, 'afterLoad', object);
            }

            if (object.content) {
                setContent(object.content);
            } else if (object.url) {
                this.showLoading();

                $.ajax(object.url, object.settings || {}).done(function(data) {
                    setContent(data);
                });
            } else {
                setContent('');
            }
        },

        showLoading: function() {
            var self = this;
            this.loading.show(function() {
                self._isLoading = true;
            });
        },

        hideLoading: function() {
            var self = this;
            this.loading.hide(function() {
                self._isLoading = false;
            });
        },

        show: function(callback) {
            this.build();

            _SlidePanel.enter('show');
            _SlidePanel.trigger(this, 'beforeShow');

            $('html').addClass(this.options.classes.base + '-html');
            this.$panel.addClass(this.options.classes.show);

            var self = this;
            Animate.do(this, 0, function() {
                self._showed = true;
                _SlidePanel.trigger(self, 'afterShow');

                if ($.isFunction(callback)) {
                    callback.call(self);
                }
            });
        },

        change: function(object) {
            _SlidePanel.trigger(this, 'beforeShow');

            _SlidePanel.trigger(this, 'onChange', object, this._instance);

            this.load(object);

            _SlidePanel.trigger(this, 'afterShow');
        },

        revert: function(callback) {
            var self = this;
            Animate.do(this, 0, function() {
                if ($.isFunction(callback)) {
                    callback.call(self);
                }
            });
        },

        hide: function(callback) {
            _SlidePanel.leave('show');
            _SlidePanel.trigger(this, 'beforeHide');

            var self = this;

            Animate.do(this, this.getHidePosition(), function() {
                self.$panel.removeClass(self.options.classes.show);
                self._showed = false;
                self._instance = null;

                if (_SlidePanel._current === self) {
                    _SlidePanel._current = null;
                }

                if (!_SlidePanel.is('show')) {
                    $('html').removeClass(self.options.classes.base + '-html');
                }

                if ($.isFunction(callback)) {
                    callback.call(self);
                }

                _SlidePanel.trigger(self, 'afterHide');
            });
        },

        makePositionStyle: function(value) {
            var property, x = '0',
                y = '0';

            if (!isPercentage(value) && !isPx(value)) {
                value = value + '%';
            }

            if (this.options.useCssTransforms && Support.transform) {
                if (this.options.direction === 'left' || this.options.direction === 'right') {
                    x = value;
                } else {
                    y = value;
                }

                property = Support.transform.toString();

                if (this.options.useCssTransforms3d && Support.transform3d) {
                    value = "translate3d(" + x + "," + y + ",0)";
                } else {
                    value = "translate(" + x + "," + y + ")";
                }
            } else {
                property = this.options.direction;
            }
            var temp = {};
            temp[property] = value;
            return temp;
        },

        getPosition: function(px) {
            var value;

            if (this.options.useCssTransforms && Support.transform) {
                value = convertMatrixToArray(this.$panel.css(Support.transform));
                if (!value) {
                    return 0;
                }

                if (this.options.direction === 'left' || this.options.direction === 'right') {
                    value = value[12] || value[4];

                } else {
                    value = value[13] || value[5];
                }
            } else {
                value = this.$panel.css(this.options.direction);

                value = parseFloat(value.replace('px', ''));
            }

            if (px !== true) {
                value = (value / this._length) * 100;
            }

            return parseFloat(value, 10);
        },

        setPosition: function(value) {
            var style = this.makePositionStyle(value);
            this.$panel.css(style);
        }
    });

    // Loading
    function Loading() {
        return this.initialize.apply(this, Array.prototype.slice.call(arguments));
    };

    $.extend(Loading.prototype, {
        initialize: function(view) {
            this._view = view;
            this.build();
        },

        build: function() {
            if (this._builded) return;

            var options = this._view.options;
            var html = options.loading.template.call(this, options);
            this.$el = $(html);

            switch (options.loading.appendTo) {
                case 'panel':
                    this.$el.appendTo(this._view.$panel);
                    break;
                case 'body':
                    this.$el.appendTo('body');
                    break;
                default:
                    this.$el.appendTo(options.loading.appendTo);
            }

            this._builded = true;
        },

        show: function(callback) {
            this.build();
            var options = this._view.options;
            options.loading.showCallback.call(this, options);

            if ($.isFunction(callback)) {
                callback.call(this);
            }
        },

        hide: function(callback) {
            var options = this._view.options;
            options.loading.hideCallback.call(this, options);

            if ($.isFunction(callback)) {
                callback.call(this);
            }
        }
    });

    var Animate = {
        prepareTransition: function($el, property, duration, easing, delay) {
            var temp = [];
            if (property) {
                temp.push(property);
            }
            if (duration) {
                if ($.isNumeric(duration)) {
                    duration = duration + 'ms';
                }
                temp.push(duration);
            }
            if (easing) {
                temp.push(easing);
            } else {
                temp.push(this.easing.css);
            }
            if (delay) {
                temp.push(delay);
            }
            $el.css(Support.transition, temp.join(' '));
        },
        do: function(view, value, callback) {
            _SlidePanel.enter('animating');

            var duration = view.options.duration,
                easing = view.options.easing || 'ease';

            var self = this,
                style = view.makePositionStyle(value);
            for (var property in style) {
                break;
            }

            if (view.options.useCssTransitions && Support.transition) {
                setTimeout(function() {
                    self.prepareTransition(view.$panel, property, duration, easing);
                }, 20);

                view.$panel.one(Support.transition.end, function() {
                    if ($.isFunction(callback)) {
                        callback();
                    }

                    view.$panel.css(Support.transition, '');

                    _SlidePanel.leave('animating');
                });
                setTimeout(function() {
                    view.setPosition(value);
                }, 20);
            } else {
                var startTime = getTime();
                var start = view.getPosition();
                var end = value;

                var run = function(time) {
                    var percent = (time - startTime) / view.options.duration;

                    if (percent > 1) {
                        percent = 1;
                    }

                    percent = Easings[easing].fn(percent);

                    var current = parseFloat(start + percent * (end - start), 10);

                    view.setPosition(current);

                    if (percent === 1) {
                        window.cancelAnimationFrame(self._frameId);
                        self._frameId = null;

                        if ($.isFunction(callback)) {
                            callback();
                        }

                        _SlidePanel.leave('animating');
                    } else {
                        self._frameId = window.requestAnimationFrame(run);
                    }
                };

                self._frameId = window.requestAnimationFrame(run);
            }
        }
    }

    // Drag
    function Drag() {
        return this.initialize.apply(this, Array.prototype.slice.call(arguments));
    }

    $.extend(Drag.prototype, {
        initialize: function(view) {
            this._view = view;
            this.options = view.options;
            this._drag = {
                time: null,
                pointer: null
            };

            this.bindEvents();
        },
        bindEvents: function() {
            var self = this;
            var options = this.options,
                $panel = this._view.$panel;

            if (options.mouseDrag) {
                $panel.on(_SlidePanel.eventName('mousedown'), $.proxy(this.onDragStart, this));
                $panel.on(_SlidePanel.eventName('dragstart selectstart'), function() {
                    if (options.mouseDragHandler) {
                        if (!$(event.target).is(options.mouseDragHandler) && !($(event.target).parents(options.mouseDragHandler).length > 0)) {
                            return;
                        }
                    }
                    return false
                });
            }

            if (options.touchDrag && Support.touch) {
                $panel.on(_SlidePanel.eventName('touchstart'), $.proxy(this.onDragStart, this));
                $panel.on(_SlidePanel.eventName('touchcancel'), $.proxy(this.onDragEnd, this));
            }

            if (options.pointerDrag && Support.pointer) {
                $panel.on(_SlidePanel.eventName(Support.prefixPointerEvent('pointerdown')), $.proxy(this.onDragStart, this));
                $panel.on(_SlidePanel.eventName(Support.prefixPointerEvent('pointercancel')), $.proxy(this.onDragEnd, this));
            }
        },

        /**
         * Handles `touchstart` and `mousedown` events.
         */
        onDragStart: function(event) {
            var self = this;

            if (event.which === 3) {
                return;
            }

            var options = this.options;

            this._view.$panel.addClass(this.options.classes.dragging);

            this._position = this._view.getPosition(true);

            this._drag.time = new Date().getTime();
            this._drag.pointer = this.pointer(event);

            var callback = function() {
                _SlidePanel.enter('dragging');
                _SlidePanel.trigger(self._view, 'beforeDrag');
            }

            if (options.mouseDrag) {
                if (options.mouseDragHandler) {
                    if (!$(event.target).is(options.mouseDragHandler) && !($(event.target).parents(options.mouseDragHandler).length > 0)) {
                        return;
                    }
                }

                $(document).on(_SlidePanel.eventName('mouseup'), $.proxy(this.onDragEnd, this));

                $(document).one(_SlidePanel.eventName('mousemove'), $.proxy(function() {
                    $(document).on(_SlidePanel.eventName('mousemove'), $.proxy(this.onDragMove, this));

                    callback();
                }, this));
            }

            if (options.touchDrag && Support.touch) {
                $(document).on(_SlidePanel.eventName('touchend'), $.proxy(this.onDragEnd, this));

                $(document).one(_SlidePanel.eventName('touchmove'), $.proxy(function() {
                    $(document).on(_SlidePanel.eventName('touchmove'), $.proxy(this.onDragMove, this));

                    callback();
                }, this));
            }

            if (options.pointerDrag && Support.pointer) {
                $(document).on(_SlidePanel.eventName(Support.prefixPointerEvent('pointerup')), $.proxy(this.onDragEnd, this));

                $(document).one(_SlidePanel.eventName(Support.prefixPointerEvent('pointermove')), $.proxy(function() {
                    $(document).on(_SlidePanel.eventName(Support.prefixPointerEvent('pointermove')), $.proxy(this.onDragMove, this));

                    callback();
                }, this));
            }

            $(document).on(_SlidePanel.eventName('blur'), $.proxy(this.onDragEnd, this));

            event.preventDefault();
        },

        /**
         * Handles the `touchmove` and `mousemove` events.
         */
        onDragMove: function(event) {
            var distance = this.distance(this._drag.pointer, this.pointer(event));

            if (!_SlidePanel.is('dragging')) {
                return;
            }

            if (Math.abs(distance) > this.options.dragTolerance) {
                if (this._willClose !== true) {
                    this._willClose = true;
                    this._view.$panel.addClass(this.options.classes.willClose);
                }
            } else {
                if (this._willClose !== false) {
                    this._willClose = false;
                    this._view.$panel.removeClass(this.options.classes.willClose);
                }
            }

            if (!_SlidePanel.is('dragging')) {
                return;
            }

            event.preventDefault();
            this.move(distance);
        },

        /**
         * Handles the `touchend` and `mouseup` events.
         */
        onDragEnd: function(event) {
            var distance = this.distance(this._drag.pointer, this.pointer(event));

            $(document).off(_SlidePanel.eventName('mousemove mouseup touchmove touchend pointermove pointerup MSPointerMove MSPointerUp blur'));

            this._view.$panel.removeClass(this.options.classes.dragging);

            if (this._willClose === true) {
                this._willClose = false;
                this._view.$panel.removeClass(this.options.classes.willClose);
            }

            if (!_SlidePanel.is('dragging')) {
                return;
            }

            _SlidePanel.leave('dragging');

            _SlidePanel.trigger(this._view, 'afterDrag');

            if (Math.abs(distance) < this.options.dragTolerance) {
                this._view.revert();
            } else {
                _SlidePanel.hide();
            }
        },

        /**
         * Gets unified pointer coordinates from event.
         * @returns {Object} - Contains `x` and `y` coordinates of current pointer position.
         */
        pointer: function(event) {
            var result = {
                x: null,
                y: null
            };

            event = event.originalEvent || event || window.event;

            event = event.touches && event.touches.length ?
                event.touches[0] : event.changedTouches && event.changedTouches.length ?
                event.changedTouches[0] : event;

            if (event.pageX) {
                result.x = event.pageX;
                result.y = event.pageY;
            } else {
                result.x = event.clientX;
                result.y = event.clientY;
            }

            return result;
        },

        /**distance
         * Gets the distance of two pointer.
         */
        distance: function(first, second) {
            var d = this.options.direction;
            if (d === 'left' || d === 'right') {
                return second.x - first.x;
            } else {
                return second.y - first.y;
            }
        },

        move: function(value) {
            var position = this._position + value;

            if (this.options.direction === 'right' || this.options.direction === 'bottom') {
                if (position < 0) {
                    return;
                }
            } else {
                if (position > 0) {
                    return;
                }
            }

            if (!this.options.useCssTransforms && !this.options.useCssTransforms3d) {
                if (this.options.direction === 'right' || this.options.direction === 'bottom') {
                    position = -position;
                }
            }

            this._view.setPosition(position + 'px');
        }
    });

    // Instance
    function Instance() {
        return this.initialize.apply(this, Array.prototype.slice.call(arguments));
    };

    $.extend(Instance.prototype, {
        initialize: function(object) {
            var options = arguments[1] || {};

            if (typeof object === 'string') {
                object = {
                    url: object
                };
            } else if (object && object.nodeType == 1) {
                var $element = $(object);

                object = {
                    url: $element.attr('href'),
                    settings: $element.data('settings') || {},
                    options: $element.data() || {}
                }
            }

            if (object && object.options) {
                object.options = $.extend(true, options, object.options);
            } else {
                object.options = options;
            }

            object.options = $.extend(true, {}, SlidePanel.options, object.options);

            $.extend(this, object);

            return this;
        }
    });

    var _SlidePanel = {
        // Current state information.
        _states: {},
        _views: {},
        _current: null,

        /**
         * Checks whether the carousel is in a specific state or not.
         */
        is: function(state) {
            return this._states[state] && this._states[state] > 0;
        },

        /**
         * Enters a state.
         */
        enter: function(state) {
            if (this._states[state] === undefined) {
                this._states[state] = 0;
            }

            this._states[state]++;
        },

        /**
         * Leaves a state.
         */
        leave: function(state) {
            this._states[state]--;
        },

        trigger: function(view, event) {
            var method_arguments = Array.prototype.slice.call(arguments, 2),
                data = [view].concat(method_arguments);

            // event
            $(document).trigger('slidePanel::' + event, data);
            if ($.isFunction(view.options[event])) {
                view.options[event].apply(view, method_arguments);
            }
        },

        eventName: function(events) {
            if (typeof events !== 'string' || events === '') {
                return '.slidepanel';
            }
            events = events.split(' ');

            var length = events.length;
            for (var i = 0; i < length; i++) {
                events[i] = events[i] + '.slidepanel';
            }
            return events.join(' ');
        },

        show: function(object) {
            if (!(object instanceof Instance)) {
                switch (arguments.length) {
                    case 0:
                        object = new Instance();
                        break;
                    case 1:
                        object = new Instance(arguments[0]);
                        break;
                    case 2:
                        object = new Instance(arguments[0], arguments[1]);
                        break;
                }
            }

            var view = this.getView(object.options);
            var self = this;
            var callback = function() {
                view.show();
                view.load(object);
                self._current = view;
            }
            if (null !== this._current) {
                if (view === this._current) {
                    this._current.change(object);
                } else {
                    this._current.hide(callback);
                }
            } else {
                callback();
            }
        },

        getView: function(options) {
            var code = getHashCode(options);

            if (this._views.hasOwnProperty(code)) {
                return this._views[code];
            }

            return this._views[code] = new View(options);
        },

        hide: function(object) {
            if (object) {
                var view = this.getView(object.options);
                view.hide();
            } else {
                if (this._current !== null) {
                    var self = this;
                    this._current.hide();
                }
            }
        }
    };

    $.extend(SlidePanel, {
        is: function(state) {
            return _SlidePanel.is(state);
        },

        show: function(object, options) {
            _SlidePanel.show.apply(_SlidePanel, arguments);
            return this;
        },

        hide: function() {
            _SlidePanel.hide.apply(_SlidePanel, arguments);
            return this;
        }
    });

    $.fn.slidePanel = function(options) {
        if (typeof options === 'string') {
            var method = options;
            var method_arguments = Array.prototype.slice.call(arguments, 1);

            return this.each(function() {
                var instance = $.data(this, 'slidePanel');

                if (!(instance instanceof Instance)) {
                    instance = new Instance(this, method_arguments);
                    $.data(this, 'slidePanel', instance);
                }

                switch (method) {
                    case 'hide':
                        _SlidePanel.hide(instance);
                        break;
                    case 'show':
                        _SlidePanel.show(instance);
                        break;
                }
            });
        } else {
            return this.each(function() {
                if (!$.data(this, 'slidePanel')) {
                    $.data(this, 'slidePanel', new Instance(this, options));

                    $(this).on('click', function(e) {
                        var instance = $.data(this, 'slidePanel');
                        _SlidePanel.show(instance);

                        e.preventDefault();
                        e.stopPropagation();
                    });
                }
            });
        }
    };

})(jQuery, document, window);
