;(function($){


    // jQuery plugin
    $.fn.techtwoCaroussel = function(options)
    {
        return this.each(function(){

            /**
             * Internal mapping to this
             * @var techtwoCaroussel
            */
            var caroussel           = this;

            /**
             * Html element
             * @var jQuery
            */
            caroussel.wrapper       = $(this);

            /**
             * Caroussel configuration settings
             * @var object
            */
            caroussel.settings      = $.extend({}, $.fn.techtwoCaroussel.defaults, options);

            /**
             * Panels (frames) to animate
             * @var array
            */
            caroussel.panels        = caroussel.wrapper.find(caroussel.settings.panelSelector);

            /**
             * Counter for the current active panel
             * @var int
            */
            caroussel.activePanel   = 0;

            /**
             * Is hovered
             * @var boolean
            */
            caroussel.hover         = false;

            /**
             * Loaded plugins
             * @var array
             */
            caroussel.plugins       = [];

            
            caroussel.timer         = '';
            
            /**
             * Load animation and controls
             * @param none
             * @return void
            */
            caroussel.initialize = function()
            {
                // Check animation availability
                if (!$.fn.techtwoCaroussel.animations[caroussel.settings.animation]) {
                    alert('undefined animation ' + caroussel.settings.animation);
                    return;
                }

                // Initialize animation
                caroussel.animation = new $.fn.techtwoCaroussel.animations[caroussel.settings.animation](caroussel.settings.animationOptions, caroussel);

                // Do we need to load controls?
                if (caroussel.settings.controls) {

                    // Check controls availability
                    if (!$.fn.techtwoCaroussel.controls[caroussel.settings.controls]) {
                        alert('undefined animation ' + caroussel.settings.controls);
                        return;
                    }

                    // Initialize controls
                    caroussel.controls = new $.fn.techtwoCaroussel.controls[caroussel.settings.controls](caroussel.settings.controlOptions, caroussel);
                }

                // Do we need to load plugins?
                if (caroussel.settings.plugins) {

                    for (var plugin, i = 0, ii = caroussel.settings.plugins.length || 0; i < ii; i++) {
                        plugin = caroussel.settings.plugins[i];

                        // Check plugin availability
                        if (!$.fn.techtwoCaroussel.plugins[plugin.name]) {
                            alert('undefined plugin ' + plugin.name);
                            return;
                        }

                        // Initialize plugin
                        caroussel.plugins.push( new $.fn.techtwoCaroussel.plugins[plugin.name](plugin.options, caroussel) );
                    }
                }

                // Start autoplay ?
                if (caroussel.settings.autoPlay) {
                    caroussel.initAutoPlay();
                }

                // Toggle hover
                caroussel.wrapper.hover(function(){
                    caroussel.hover = true;
                }, function(){
                    caroussel.hover = false;
                });

                caroussel.wrapper.data('caroussel', caroussel);
            };

            /**
             * Go forward 1 panel
             * @param none
             * @return void
            */
            caroussel.next = function()
            {
                var next = caroussel.getNextPanel();
                caroussel.gotoPanel(next);
                caroussel.activePanel = next;
            };

            /**
             * Go back 1 panel
             * @param none
             * @return void
            */
            caroussel.back = function()
            {
                caroussel.gotoPanel(caroussel.getPreviousPanel());
            };

            /**
             * Alias for back()
             * @param none
             * @return void
            */
            caroussel.forward = function()
            {
                caroussel.next();
            };

            /**
             * Alias for next()
             * @param none
             * @return void
            */
            caroussel.previous = function()
            {
                caroussel.back();
            };

            /**
             * Go to a specific panel
             * @param int index
             * @return void
            */
            caroussel.gotoPanel = function (index)
            {
                // Trigger animation
                caroussel.animation.gotoPanel(index);

                caroussel.settings.onBeforeAnimate(index);

                // If nessecary, trigger controls
                if (caroussel.controls) {
                    caroussel.controls.gotoPanel(index);
                }

                if (caroussel.timer) {
                	clearTimeout(caroussel.timer);
                    caroussel.initAutoPlay();
                }

                caroussel.settings.onAfterAnimate(index);

            };

            /**
             * Retrieve animation class
             * @param none
             * @return void
            */
            caroussel.getAnimation = function()
            {
                return caroussel.animation;
            };

            /**
             * Utility method to get the previous panel index
             * @param none
             * @return int
            */
            caroussel.getPreviousPanel = function()
            {
                return (0 > (caroussel.activePanel - 1) ? (caroussel.panels.length - 1) : caroussel.activePanel - 1);
            };

            /**
             * Utility method to get the next panel index
             * @param none
             * @return int
            */
            caroussel.getNextPanel = function ()
            {
                return (caroussel.panels.length <= (caroussel.activePanel + 1) ? 0 : caroussel.activePanel + 1);
            };

            /**
             * Initialize autoplay
             * @param none
             * @return void
            */
            caroussel.initAutoPlay = function()
            {
                caroussel.settings.autoPlay = true;
                caroussel.timer = setTimeout(caroussel.autoPlay, caroussel.settings.delay);
            };

            /**
             * Autoplay function
             * @param none
             * @return void
            */
            caroussel.autoPlay = function()
            {
            	
                if (caroussel.timer) {
                    clearTimeout(caroussel.timer);
                    caroussel.timer = null;
                }

                if (!caroussel.settings.autoPlay) {
                    return;
                }

                if (!caroussel.settings.pauseOnHover || !caroussel.hover) {
                    caroussel.next();
                }

                caroussel.timer = setTimeout(caroussel.autoPlay, caroussel.settings.delay);
            };

            caroussel.initialize();

        });
    };

    // Wrapper for animations
    $.fn.techtwoCaroussel.animations = {};

    // Wrapper for controls
    $.fn.techtwoCaroussel.controls = {};

    // Wrapper for plugins
    $.fn.techtwoCaroussel.plugins = {};

    // Default settings
    $.fn.techtwoCaroussel.defaults = {

        // Elements
        panelSelector: '>li',

        // Controls
        pauseOnHover: false,
        controls: false,
        controlOptions: {},

        // Animation
        autoPlay: true,
        delay: 3000,
        duration: 400,
        animation: 'fade',
        animationOptions: {},
        onBeforeAnimate: function(){},
        onAfterAnimate: function(){},

        // Plugins
        plugins: []
    };

})(jQuery);
