/*
 * Simplified horizontal accordion designed to work without using quirks
 * in all modern browsers and IE.
 * @author Igor Zinovyev 
 */

/**
 * Accordion constructor, sets all required option defaults,
 * finds handles, positions slide elements and sets mouse
 * event handlers.
 * @param {Object} options
 */
function Accordion(options) {
    this.options = $.extend({
        accordion: '#accordion',
        handles: '.handle',
        slideContainer: 'li',
        zIndex: 100,
        contentWidth: 872
    }, options || null);
    
    this.accordion = $(this.options.accordion);
    this.handles = this.accordion.find(this.options.handles);
    
    // Let's determine offsets for each slide
    var totalOffset = 0;
    this.handleOffsets = [];
    
    this.handles.each($.proxy(function(index, element){
        
        var handle = $(element);
        handle.closest(this.options.slideContainer).css({
            'left': totalOffset,
            'z-index': this.options.zIndex + index * 10
        });
        totalOffset += handle.outerWidth();
        this.handleOffsets[index] = totalOffset;
        
    }, this));
    
    this.handles.bind('click', $.proxy(this.handleClick, this));
}

/**
 * Method for handling mouse clicks on accordion handles
 * @param {Object} event
 */
Accordion.prototype.handleClick = function(event){
    var open = $(jQuery.grep(this.handles, function(element){ 
        return $(element).data('open'); 
    }));
    var current = $(event.target).closest(this.options.handles);
    
    if (!current.length || current.attr('id') == open.attr('id')) {
        return;
    }
    event.preventDefault();
    this.openSlide(current);
};

/**
 * Universal method for opening a certain slide, takes a DOM element,
 * a jQuery object or a slide index as an argument.
 * @param {Object|Number} element
 * @return {Accordion} self
 */
Accordion.prototype.openSlide = function(element) {
    var currentSlide;
    if (typeof(element) == 'number') {
        element = $(this.handles.get(element));
    }
    
    slideToOpen = this.handles.index(element);

    // We need to determine which slides we need to move right or left                
    var slidesMovedLeft = $();
    var slidesMovedRight = $();
    for (var i = 0; i < this.handles.length; i++) {
        var container;
        
        if (i > slideToOpen && 
            (typeof(this.currentIndex) != 'number' || 
             i <= this.currentIndex)) {
            // If a slide that is to be opened is to the 
            // left of current then we need to move all
            // that are in between the one to be opened 
            // and current to the right
            container = $(this.handles.get(i)).closest(this.options.slideContainer);
            slidesMovedRight.push(container.get(0));
        } else if (i <= slideToOpen && 
                   (typeof(this.currentIndex) == 'number' && 
                    i > this.currentIndex)) {
            // If a slide that is to be opened is to the 
            // right of current then we need to move all
            // that are in between the one to be opened 
            // and current to the left
            container = $(this.handles.get(i)).closest(this.options.slideContainer);
            slidesMovedLeft.push(container.get(0));  
        }
    }
                    
    if (this.current) {
        this.current.data('open', false).fadeIn();
    }
    element.data('open', true).fadeOut();
    
    if (slidesMovedLeft.length) {
        slidesMovedLeft.animate({
            'left': '-=' + this.options.contentWidth + 'px'
        }, {queue: false});
    }
    if (slidesMovedRight.length) {
        slidesMovedRight.animate({
            'left': '+=' + this.options.contentWidth + 'px'
        }, {queue: false});
    }          
    
    this.current = element;
    this.currentIndex = slideToOpen;
    
    return this;
};

/**
 * Method for cycling the accordion slides opening with a certain
 * interval
 * @param {Number} interval
 */
Accordion.prototype.setInterval = function(interval){
    this.leftToRight = typeof(this.leftToRight) == 'undefined' ?
        true : !!this.leftToRight;
    this.interval = interval; 
    this.intervalId = setInterval($.proxy(this.walk_, this), this.interval);
    
    this.accordion.bind('mouseover', $.proxy(function(event){
        event.stopPropagation();
        clearInterval(this.intervalId);
    }, this));
    this.accordion.bind('mouseout', $.proxy(function(event){
        event.stopPropagation();
        this.intervalId = setInterval($.proxy(this.walk_, this), this.interval);
    }, this));
};

/**
 * Method for pausing the accordion slides cycle
 * @param {Number} interval
 */
Accordion.prototype.clearInterval = function(){
    if (this.intervalId) {
        clearInterval(this.intervalId);
    } 
};

/**
 * Private method for determining which slide to open next and
 * passing the index to openSlide method
 * @private
 */
Accordion.prototype.walk_ = function(){
    var toOpen;
    
    if ((this.leftToRight && this.currentIndex == this.handles.length - 1) ||
        (!this.leftToRight && this.currentIndex === 0)) {
        this.leftToRight = !this.leftToRight;
    } 
    
    if (this.leftToRight) {
        toOpen = this.currentIndex + 1;
    } else {
        toOpen = this.currentIndex - 1;
    }
    
    this.openSlide(toOpen);   
};
