(function ($) {
    var methods = {
        init: function (options) {
            var settings = {
                controls: null,
                startIndex: 0,
                delay: 0,
                hideControlsWhenSingle: false,
                showTimer: true,
                pauseTimerOnHover: true,
                stopTimerOnNav: true,
                timerSize: 20,
                timerLineSize: 4,
                timerColor: 'rgba(255, 255, 255, 0.6)'

            };

            if (options) {
                $.extend(settings, options);
            }

            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;


            if (ss.length && ss.children().length > 1) {
                ss.data('ss-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);
                        ctx.strokeStyle = settings.timerColor;
                        ctx.lineWidth = settings.timerLineSize;
                        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();
                    }

                    timerPosition += 0.02;
                    if (timerPosition > 2) {
                        timerPosition = 0;
                        ss.trigger('ss-next');
                    }

                }

                function startTimer() {
                    clearInterval(timerTimeout);
                    if (settings.delay > 0 && !stopped) {
                        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 currentIndex = ss.data('ss-currentIndex');
                    var current = slides.eq(currentIndex);
                    var next = slides.eq(nextIndex);

                    if (!animating) {
                        stopTimer(true);
                        if (currentIndex != nextIndex) {
                            animating = true;
                            setDot(nextIndex);

                            inner.css({
                                width: '200%'
                            });

                            if ((direction && direction > 0) || (!(direction && direction < 0) && nextIndex > currentIndex)) {
                                current.after(next.show());
                                inner.css({
                                    left: 0
                                }).animate({ left: -ss.width() }, function () {
                                    current.hide();
                                    inner.css({
                                        left: 0,
                                        width: '100%'
                                    });
                                    animating = false;
                                    startTimer();
                                });
                            } else {
                                current.before(next.show());
                                inner.css({
                                    left: -ss.width()
                                }).animate({ left: 0 }, function () {
                                    current.hide();
                                    inner.css({
                                        width: '100%'
                                    })
                                    animating = false;
                                    startTimer();
                                });
                            }

                            ss.data('ss-currentIndex', nextIndex);
                        } else {
                            setDot(currentIndex);
                            slides.eq(currentIndex).show();
                        }
                    }
                }


                // Events
                // --------------------------------------
                ss.bind('ss-next', function (e, stop) {
                    currentIndex = ss.data('ss-currentIndex');
                    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) {
                    currentIndex = ss.data('ss-currentIndex');

                    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, index) {
                    if (settings.stopTimerOnNav)
                        stopped = true;

                    changeSlide(index);
                });

                // Initialization
                // --------------------------------------
                slides = ss.children().css({
                    float: 'left',
                    width: ss.width(),
                    height: ss.height(),
                    position: 'relative'
                }).hide();

                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 () {
                            if (settings.pauseTimerOnHover) stopTimer(false)
                        },
                        startTimer
                    );


                // 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);
                    });

                    $(this).data('dot', dotsli);
                    dotsul.append(dotsli);
                });

                controls
                    .append($('<div>')
                        .addClass('ss-arrow-left')
                        .css({
                            cursor: 'pointer'
                        })
                        .click(function (e) {
                            e.preventDefault();
                            ss.trigger('ss-previous', true);
                        })
                    )
                    .append($('<div>')
                        .addClass('ss-arrow-right')
                        .css({
                            cursor: 'pointer'
                        })
                        .click(function (e) {
                            e.preventDefault();
                            ss.trigger('ss-next', true);
                        })
                    )
                    .append(dots);


                changeSlide(ss.data('ss-currentIndex'));

                // Setup Timer
                // --------------------------------------                
                timerWrapper.append(timer);
                timer.width = settings.timerSize;
                timer.height = settings.timerSize;
                startTimer();

            } else if (settings.hideControlsWhenSingle) {
                controls.hide();
            }

            return this;
        },
        next: function () {
            return this.trigger('ss-next', true);
        },
        previous: function () {
            return this.trigger('ss-previous', true);
        },
        goto: function (index) {
            return this.trigger('ss-goto', index);
        }
    };

    $.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);
