(function ($) {
    var methods = {
        init: function (options) {
            var settings = {
                controls: null,
                startIndex: 0,
                delay: 0,
                hideControlsWhenSingle: false,
                showTimer: true,
                showCaptionsOnHover: true,
                pauseTimerOnHover: true,
                stopTimerOnNav: true,
                timerSize: 20,
                timerLineSize: 4,
                timerColor: 'rgba(255, 255, 255, 0.6)',
                timerBackgroundColor: 'rgba(255, 255, 255, 0.2)',
                captionStyle: {},
                captionBackgroundStyle: {},
                slideChanging: function (index, direction) { },
                slideChanged: function (index, direction) { }
            };

            var captionBackgroundStyle = {
                background: '#000000',
                opacity: '0.7',
                position: 'absolute',
                top: '0px',
                bottom: '0px',
                right: '0px',
                left: '0px'
            };

            var captionStyle = {
                color: '#FFFFFF',
                position: 'relative',
                padding: '15px',
                paddingRight: '40px'

            };

            if (options) {
                $.extend(settings, options);
            }

            $.extend(captionStyle, settings.captionStyle);
            $.extend(captionBackgroundStyle, settings.captionBackgroundStyle);

            return this.each(function () {
                var ss = $(this).eq(0);
                var controls = $(settings.controls);
                var timerWrapper = $('<div>');
                var timer = $('<canvas>')[0];
                var inner;
                var slides;
                var timerPosition = 0;
                var timerTimeout;
                var animating = false;
                var stopped = false;
                var paused = false;
                var hover = false;
                var currentIndex = 0;

                if (ss.length && ss.children().length > 1) {
                    currentIndex = settings.startIndex;

                    // Helper Functions
                    // --------------------------------------
                    function runTimer() {
                        if (timer.getContext && settings.showTimer) {
                            var ctx = timer.getContext("2d");
                            ctx.clearRect(0, 0, settings.timerSize, settings.timerSize);

                            if (!stopped) {
                                ctx.lineWidth = settings.timerLineSize;

                                ctx.strokeStyle = settings.timerColor;
                                ctx.beginPath();
                                ctx.arc(settings.timerSize / 2, settings.timerSize / 2, settings.timerSize / 2 - settings.timerLineSize / 2, -Math.PI / 2, -Math.PI / 2 - (Math.PI * 2 - Math.PI * timerPosition), false); // Outer circle  
                                ctx.stroke();

                                ctx.strokeStyle = settings.timerBackgroundColor;
                                ctx.beginPath();
                                ctx.arc(settings.timerSize / 2, settings.timerSize / 2, settings.timerSize / 2 - settings.timerLineSize / 2, 0, 2 * Math.PI, false); // Outer circle  
                                ctx.stroke();
                            }
                        }

                        timerPosition += 0.02;
                        if (timerPosition > 2) {
                            timerPosition = 0;
                            ss.trigger('ss-next');
                        }

                    }

                    function startTimer() {
                        clearInterval(timerTimeout);
                        if (settings.delay > 0 && !stopped && !paused) {
                            timerTimeout = setInterval(function () {
                                runTimer();
                            }, settings.delay / 100);
                        }
                    }

                    function stopTimer(clear) {
                        clearInterval(timerTimeout);

                        if (clear) {
                            timerPosition = 0;
                            runTimer();
                        }
                    }

                    function setDot(activeIndex) {
                        slides.each(function (index) {
                            if (activeIndex == index) {
                                $(this).data('dot').addClass('ss-active');
                            } else {
                                $(this).data('dot').removeClass('ss-active');
                            }
                        });
                    }

                    function changeSlide(nextIndex, direction) {
                        var current = slides.eq(currentIndex);
                        var next = slides.eq(nextIndex);

                        if (!animating) {
                            stopTimer(true);
                            if (currentIndex != nextIndex) {
                                if (direction === undefined) {
                                    if (nextIndex > currentIndex) {
                                        direction = 1
                                    } else {
                                        direction = -1
                                    }
                                }

                                if (settings.slideChanging) {
                                    settings.slideChanging(nextIndex, direction)
                                }

                                animating = true;
                                setDot(nextIndex);

                                inner.css({
                                    width: '200%'
                                });

                                inner.children().css({
                                    width: '50%'
                                })

                                var callback = function (left) {
                                    current.hide();

                                    current.trigger('ss-hidecaption');
                                    if (!settings.showCaptionsOnHover || hover) {
                                        next.trigger('ss-showcaption');
                                    }

                                    inner.css({ width: '100%' });
                                    inner.children().css({
                                        width: '100%'
                                    })
                                    if (left) inner.css({ left: 0 })

                                    animating = false;
                                    startTimer();

                                    if (settings.slideChanged) {
                                        settings.slideChanged(nextIndex, direction);
                                    }
                                }

                                if (direction > 0) {
                                    current.after(next.show());
                                    inner.css({
                                        left: 0
                                    }).animate({ left: -ss.width() }, function () {
                                        callback(true);
                                    });
                                } else {
                                    current.before(next.show());
                                    inner.css({
                                        left: -ss.width()
                                    }).animate({ left: 0 }, function () {
                                        callback();
                                    });
                                }

                                currentIndex = nextIndex;
                            } else {
                                setDot(currentIndex);
                                slides.eq(currentIndex).show();

                                if (!settings.showCaptionsOnHover) {
                                    next.trigger('ss-showcaption');
                                }

                            }
                        }
                    }

                    // Events
                    // --------------------------------------
                    ss.bind('ss-pause', function (e) {
                        paused = true;
                        stopTimer(false);
                    });

                    ss.bind('ss-play', function (e) {
                        paused = false;
                        startTimer();
                    });

                    ss.bind('ss-stop', function (e) {
                        stopped = true;
                        stopTimer(true);
                    });

                    ss.bind('ss-start', function (e) {
                        stopped = false;
                        startTimer();
                    });

                    ss.bind('ss-next', function (e, stop) {
                        nextIndex = currentIndex + 1;

                        if (nextIndex >= inner.children().length)
                            nextIndex = 0;

                        if (stop && settings.stopTimerOnNav)
                            stopped = true;

                        changeSlide(nextIndex, 1);
                    });

                    ss.bind('ss-previous', function (e, stop) {
                        prevIndex = currentIndex - 1;
                        if (prevIndex < 0)
                            prevIndex = inner.children().length - 1;

                        if (stop && settings.stopTimerOnNav)
                            stopped = true;

                        changeSlide(prevIndex, -1);
                    });

                    ss.bind('ss-goto', function (e, params) {
                        if (settings.stopTimerOnNav)
                            stopped = true;

                        changeSlide(params.index, params.direction);
                    });

                    // Initialization
                    // --------------------------------------
                    slides = ss.children().css({
                        float: 'left',
                        width: '100%',
                        height: ss.height(),
                        position: 'relative'
                    });

                    inner = $('<div>').append(slides).css({
                        width: '100%',
                        height: '100%',
                        position: 'relative'
                    });

                    timerWrapper.css({
                        position: 'absolute',
                        bottom: 5,
                        right: 5
                    })

                    ss
                        .append(inner)
                        .append(timerWrapper)
                        .css({
                            overflow: 'hidden',
                            position: 'relative'
                        })
                        .hover(
                            function () {
                                var current = slides.eq(currentIndex);
                                if (!animating && settings.showCaptionsOnHover) current.trigger('ss-showcaption');
                                hover = true;
                                if (settings.pauseTimerOnHover) stopTimer(false)
                            },
                            function () {
                                var current = slides.eq(currentIndex);
                                if (!animating && settings.showCaptionsOnHover) current.trigger('ss-hidecaption');
                                hover = false;
                                startTimer()
                            }
                        );


                    // Attach captions
                    // --------------------------------------
                    slides.filter('[data-caption]').filter('[data-caption!=""]').each(function () {
                        var height;

                        var caption = $('<div>').css({
                            position: 'absolute',
                            opacity: 0,
                            right: '0px',
                            left: '0px'
                        }).hide();

                        $(this).bind('ss-showcaption', function () {
                            caption
                                .stop()
                                .show()
                                .animate({ bottom: 0, opacity: 1 }, 'fast');
                        });

                        $(this).bind('ss-hidecaption', function () {
                            caption
                                .stop()
                                .animate({ bottom: -height, opacity: 0 }, 'fast', function () {
                                    caption.hide();
                                });
                        });

                        caption.append($('<div>').css(captionBackgroundStyle));
                        caption.append($('<div>').css(captionStyle).html($(this).data('caption')));

                        $(this).append(caption);

                        setTimeout(function () {
                            height = caption.height();
                            caption.css({
                                bottom: -height
                            });
                        }, 0)

                    });

                    // Setup Controls
                    // --------------------------------------
                    var dots = $('<div>').addClass('ss-dots');
                    var dotsul = $('<ul>').css({
                        listStyle: 'none'
                    });
                    dots.append(dotsul);

                    slides.each(function (index) {
                        var dotsli = $('<li>').css({
                            cursor: 'pointer',
                            float: 'left'
                        }).click(function (e) {
                            e.preventDefault();
                            ss.trigger('ss-goto', { index: index });
                        });

                        $(this).data('dot', dotsli);
                        dotsul.append(dotsli);
                    });

                    controls
                        .append($('<div>')
                            .addClass('ss-arrow ss-arrow-left')
                            .css({
                                cursor: 'pointer'
                            })
                            .click(function (e) {
                                e.preventDefault();
                                ss.trigger('ss-previous', true);
                            })
                        )
                        .append($('<div>')
                            .addClass('ss-arrow ss-arrow-right')
                            .css({
                                cursor: 'pointer'
                            })
                            .click(function (e) {
                                e.preventDefault();
                                ss.trigger('ss-next', true);
                            })
                        )
                        .append(dots);


                    window.setTimeout(function () {
                        slides.hide();

                        changeSlide(currentIndex);

                        // Setup Timer
                        // --------------------------------------                
                        timerWrapper.append(timer);
                        timer.width = settings.timerSize;
                        timer.height = settings.timerSize;
                        startTimer();

                    }, 0)



                } else if (settings.hideControlsWhenSingle) {
                    controls.hide();
                }
            });

        },
        next: function () {
            return this.trigger('ss-next', true);
        },
        previous: function () {
            return this.trigger('ss-previous', true);
        },
        goto: function (index, direction) {
            return this.trigger('ss-goto', { index: index, direction: direction });
        },
        pause: function () {
            return this.trigger('ss-pause');
        },
        play: function () {
            return this.trigger('ss-play');
        },
        stop: function () {
            return this.trigger('ss-stop');
        },
        start: function () {
            return this.trigger('ss-start');
        }
    };

    $.fn.slickslider = function (method) {
        if (methods[method]) {
            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
        } else if (typeof method === 'object' || !method) {
            return methods.init.apply(this, arguments);
        } else {
            $.error('Method ' + method + ' does not exist');
        }
    };
})(jQuery);
