(function($){

    $.dxSlider = function(obj, _options){
        var defaults = {
            'speed':400,
            'type':'horizontal', // vertical will be implemented later
            'arrowClasses':{
                'previous':'prev',
                'next':'next'
            },
            'wrapperClass':'wrap',
            debug:false
        }

        var options = $.extend(defaults, _options);
        var element = $(obj);
        var caption = element.find('.caption');
        var visibleElement = null;

        element.find('ul').wrap('<div class="' + options.wrapperClass + '"></div>');


        if (element.find('li').length > 1) {
            element.prepend('<a href="#" class="' + options.arrowClasses.previous + '"><span>prev</span></a>')
               .append('<a href="#" class="' + options.arrowClasses.next + '"><span>next</span></a>');
        }

        
			
        /**
         * Variables, needed for calculations
         */
        var wrapper, wrapperWidth, elementCount, tElementCount, total, visibleElements, elementWidth;
        /**
         * Check if element is currently in animation progress
         */
        var isAnimated = false;

        /**
         * observe next/prev buttons to animate ul
         */
        function observeButtons()
        {
            element.find('.' + options.arrowClasses.next).unbind('click').click(function(){
                animate("next");
                return false;
            });
            element.find('.' + options.arrowClasses.previous).unbind('click').click(function(){
                animate("previous");
                return false;
            });
        }

        /**
         * animates ul to left/right directions
         */
        function animate(dir)
        {
            if (elementCount <= visibleElements) {
                return;
            }
            if (isAnimated) {
                return;
            }
            isAnimated = true;
            if(dir == "next"){
                if (elementCount ==  visibleElements+total) {
                    total = 0;
                } else {
                    total = (total>tElementCount) ? tElementCount : (total == tElementCount ? total = 0 : total = total + 1);
                }
            } else {
                total = (total<0) ? 0 : (total == 0 ? total = elementCount - visibleElements : total = total - 1);
            }
            margin = -total*elementWidth;

            $("ul", obj).animate({marginLeft: margin}, options.speed, function(){
                isAnimated = false;
                var img = $(this).find('li img')[total];
                caption.find('span').fadeOut('fast', function(){
                    $(this).text($(img).attr('title')).fadeIn('fast');
                    Cufon.replace('div.caption');
                });
            });
        }

        /**
         *
         */
        function calculate()
        {
            var li = element.find('li');
            wrapper = element.find('.' + options.wrapperClass);
            
            elementCount = li.length;

            elementWidth = li.innerWidth();
            if (elementWidth == 0) {
                // fuck IE
                elementWidth = li.css('width').replace('px', '') * 1;
            }
            wrapperWidth = wrapper.width();
            if (wrapperWidth == 0) {
                // fuck IE
                wrapperWidth = wrapper.css('width').replace('px', '') * 1;
            }
            
            tElementCount = elementCount-1;
            total = 0;
            visibleElements = wrapperWidth/elementWidth;
        }

        /**
         * recalculate ul width
         */
        function calculateWidth()
        {
            return elementCount*elementWidth;//wrapperWidth;
        }

        /**
         * set ul width, based on li width and counting
         */
        function setUlWidth(width)
        {
            $("ul", element).css('width', width);
        }

        function getUlWidth()
        {
            return $('ul', element).width();
        }

        function init()
        {
            calculate();
            setUlWidth(calculateWidth());
            observeButtons();
            //bindMouseWheelObserver();
        }

        function reInit()
        {
            init();
            // reset margin for ul
            $("ul", obj).css({marginLeft:0});
        }

        function _debug(variable)
        {
            if (options.debug) {
                console.log(variable);
            }
        }

        function bindMouseWheelObserver()
        {
            element.find('ul').mousewheel(function(){
                animate(arguments[1] > 0 ? 'next' : 'previous')
                return false;
            })
        }

        init();
        
        var api = {
            reInit:reInit,
            getUlWidth:getUlWidth
        }

        return api;
    }

    $.fn.dxSlider = function(opt){
        return this.each(function(){
            if ($(this).data('dxSlider')) {
                if (typeof(opt) != 'undefined') {
                    // launch only if method exists
                    $(this).data('dxSlider')[opt]();
                }
            } else {
                // init new slider
                var slider = $.dxSlider(this,opt);
                $(this).data('dxSlider', slider);
            }
        });
    }
})(jQuery);