window.addEvent('domready', function() {
	var menuSet = [];
	
	var slides = new Slides($$('.slides')[0], {
		prevSlideButton: $$('.previous_slide.slide_break')[0],
		nextSlideButton: $$('.next_slide.slide_break')[0],
		prevSectionButton:$$('.previous_slide.section_break')[0],
		nextSectionButton:$$('.next_slide.section_break')[0],
		slideProgress: $$('span.slide_position')[0]
	});
	
	$$('ul.tabs li').each(function(el) {
		if (el.getElement('.tab_index')) {
			menuSet.push(new TabMenuIndex(
				el.getElement('div.tab_index_link a'),
				el.getElement('ul.tab_index_list'),
				menuSet,
				slides
			));
		}
	});
});


var TabMenuIndex = new Class({
	
	initialize: function(button, menu, menuSet, slides) {
		// Setup elements
		this.button = $(button);
		this.menu = $(menu).clone(); // So we can z-index this sucker to the absolute front.
		if (menu.getParent('li').hasClass('active')) this.menu.addClass('active');
		this.menuSet = menuSet;
		this.slides = slides;
		this.connector = new Element('div', {
			styles: {
				position: 'absolute',
				zIndex: 100000-1,
				height: 7,
				width: 19,
				backgroundColor: '#dde2e6',
				borderLeft: '1px solid #d3d8db',
				borderRight: '1px solid #d3d8db'
			}
		});
		this.indexIsVisible = false;
		
		// Add events
		this.listener = $(this.button.getDocument().body);
		this.bound = {
			menuClick: this.menuClick.bind(this)
		};
		this.button.addEvent('click', function(event) {
			if (this.indexIsVisible) {
				this.hideIndex();
			} else {
				this.showIndex();
			}
			return false;
		}.bind(this));
	},
	
	addEventHandlers: function() {
		this.listener.addEvent('click', this.bound.menuClick);
	},
	
	removeEventHandlers: function() {
		this.listener.removeEvent('click', this.bound.menuClick);
	},
	
	menuClick: function(event) {
		if ($(event.target) != this.menu) {
			// If user clicked on an index menu link
			var indexList = $(event.target).getParent('.tab_index_list');
			if (indexList == this.menu) {
				if (indexList.hasClass('active')) {
					// Update slide position
					this.slides.slide($($(event.target).get('href').split('#')[1]));
					this.slides.updateProgress();
				} else {
					return true;
				}
			}
			
			this.hideIndex();
		}
		
		return false;
	},
	
	showIndex: function() {
		this.hideAllIndexes();
		this.addEventHandlers();
				
		var buttonCoords = this.button.getCoordinates();
		
		this.connector.setStyles({
			zIndex: 9999+1,
			top: buttonCoords.bottom - 10,
			left: buttonCoords.left + 6
		}).inject(document.body);
		
		this.menu.setStyles({
			display: 'block',
			zIndex: 9999,
			top: buttonCoords.bottom,
			left: buttonCoords.left + buttonCoords.width/2 - 100
		});
		this.button.addClass('active');
		this.menu.inject(document.body);
		
		this.indexIsVisible = true;
	},
	
	hideIndex: function() {
		this.button.removeClass('active');
		this.removeEventHandlers();
		this.connector.dispose();
		this.menu.dispose();
		
		this.indexIsVisible = false;
	},
	
	hideAllIndexes: function() {
		if (this.menuSet) {
			this.menuSet.each(function(el) {
				el.hideIndex();
			});
		}
	}
});

var Slides = new Class({
	Implements: Options,
	
	options: {
		prevSlideButton: null,
		nextSlideButton: null,
		prevSectionButton: null,
		nextSectionButton: null,
		slideProgress: null,
		scrollFx: null
	},

	initialize: function(container, options) {
		this.setOptions(options);
		this.element = $(container);
		this.allSlides = this.element.getElements('.slide_body');
		this.currentSlide = this.element.getElement('.slide_body');
		
		// Add wrapper with enough width to put all slides in side-by-side
		var totalWidth = 0;
		this.element.getElements('.slide_body').each(function(el) {
			totalWidth += el.getSize().x.toInt();
		}.bind(this));
		this.slideWrapper = new Element('div', {
			'class': 'slideWrapper',
			styles: {
				width: totalWidth,
				margin: 0,
				padding: 0
			}
		}).inject(this.element);
		this.element.getElements('.slide_body').each(function(el) {
			el.inject(this.slideWrapper);
		}.bind(this));
		
		// Create slide transition effect, if needed
		if (this.options.scrollFx) {
			this.scrollFx = this.options.scrollFx;
		} else {
			this.scrollFx = new Fx.Scroll2(this.element, {
				wheelStops: false,
				onComplete: function() {
					window.location.replace('#' + this.currentSlide.get('id'));
					window.scroll(0,0);
				}.bind(this)
			});
		}
		
		/* Attach events */
		
		if (this.options.prevSlideButton) {
			this.options.prevSlideButton.addEvent('click', function() {
				this.slide('backward');
				return false;
			}.bind(this));
		}
		if (this.options.nextSlideButton) {
			this.options.nextSlideButton.addEvent('click', function() {
				this.slide('forward');
				return false;
			}.bind(this));
		}
		
		/* Scroll to initial slide indicated in URL hash, if it exists */
		
		if (window.location.hash.length > 1) {
			window.scroll(0,0);
			var slide = this.element.getElement(window.location.hash);
			if (slide){
				this.slide(slide);
			}
		}
		
		this.updateProgress();
	},
	
	slide: function(slideTo) {
		this.scrollFx.cancel();
		var nextSlide = null;
		
		switch (slideTo) {
			case 'backward':
			case 'previous':
				nextSlide = this.currentSlide.getPrevious('.slide_body');
				break;
			case 'forward':
			case 'next':
				nextSlide = this.currentSlide.getNext('.slide_body');
				break;
			case 'first':
				nextSlide = this.allSlides[0];
				break;
			default:
				nextSlide = slideTo;
		}
		
		if (nextSlide) {
			this.scrollFx.toElement(nextSlide);
			this.currentSlide = nextSlide;
			this.updateProgress();
		} else {
			// Recover & reset buttons
			alert('error: nextslide = ' + nextSlide);
		}
		
		return false;
	},
	
	updateProgress: function() {
		if (this.options.slideProgress) {
			var progressText = this.getCurrentSlideNum() + " of " + this.allSlides.length;
			this.options.slideProgress.set('text', progressText)
		}
		
		var prevSlideButtonDisplay = 'block';
		var nextSlideButtonDisplay = 'block';
		var prevSectionButtonDisplay = 'none';
		var nextSectionButtonDisplay = 'none';
		
		if (this.getCurrentSlideNum() == 1) {
			prevSlideButtonDisplay = 'none';
			if (this.options.prevSectionButton) {
				prevSectionButtonDisplay = 'block';
			}
		}
		if (this.getCurrentSlideNum() == this.allSlides.length) {
			nextSlideButtonDisplay = 'none';
			if (this.options.nextSectionButton) {
				nextSectionButtonDisplay = 'block';
			}
		}
		
		this.options.prevSlideButton.setStyle('display', prevSlideButtonDisplay);
		this.options.nextSlideButton.setStyle('display', nextSlideButtonDisplay);
		if (this.options.prevSectionButton) {
			this.options.prevSectionButton.setStyle('display', prevSectionButtonDisplay);
		}
		if (this.options.nextSectionButton) {
			this.options.nextSectionButton.setStyle('display', nextSectionButtonDisplay);
		}
	},
	
	getCurrentSlideNum: function() {
		for (var i=0; i < this.allSlides.length; i++) {
			if (this.currentSlide == $(this.allSlides[i])) return i+1;
		}
		
		return 0;
	}
});

 
 
/* A workaround for IE issues in mootools 1.2.1
 * - Recreates FX.Scroll() but utilises 1.2.0's getPosition/getOffset routines.
 */
Fx.Scroll2 = new Class({
 
    'Extends': Fx.Scroll,
 
    'styleString': Element.getComputedStyle,
    'styleNumber': function(element, style) {
        return this.styleString(element, style).toInt() || 0;
    },
    'borderBox': function(element) {
        return this.styleString(element, '-moz-box-sizing') == 'border-box';
    },
    'topBorder': function(element) {
        return this.styleNumber(element, 'border-top-width');
    },
    'leftBorder': function(element) {
        return this.styleNumber(element, 'border-left-width');
    },
    'isBody': function(element) {
        return (/^(?:body|html)$/i).test(element.tagName);
    }, 
    'toElement': function(el) {
        var offset   = {x: 0, y: 0};
        var element  = $(el);
       
        if (this.isBody(element)) {
            return offset;
        }
        var scroll = element.getScrolls();
               
        while (element && !this.isBody(element)){
            offset.x += element.offsetLeft;
            offset.y += element.offsetTop;
           
            if (Browser.Engine.gecko){
                if (!this.borderBox(element)){
                    offset.x += this.leftBorder(element);
                    offset.y += this.topBorder(element);
                }
                var parent = element.parentNode;
                if (parent && this.styleString(parent, 'overflow') != 'visible'){
                    offset.x += this.leftBorder(parent);
                    offset.y += this.topBorder(parent);
                }
            } else if (Browser.Engine.trident || Browser.Engine.webkit){
                offset.x += this.leftBorder(element);
                offset.y += this.topBorder(element);
            }
 
            element = element.offsetParent;
            if (Browser.Engine.trident) {
                while (element && !element.currentStyle.hasLayout) {
                    element = element.offsetParent;
                }
            }
        }
        if (Browser.Engine.gecko && !this.borderBox(element)){
            offset.x -= this.leftBorder(element);
            offset.y -= this.topBorder(element);
        }
       
        var relative = this.element;
        var relativePosition = (relative && (relative = $(relative))) ? relative.getPosition() : {x: 0, y: 0};
        var position = {x: offset.x - scroll.x, y: offset.y - scroll.y};
       
        return this.start(position.x - relativePosition.x, position.y - relativePosition.y);
    }
});
