/*
 Class: ProtoFlow
 
 License:
 Copyright (c) 2008 DeenSoft.com - You are free to use this file wherever you wish but please do let us know at blog.deensoft.com
 so that we can showcase it. You can even post your bugs on our blog and we will fix them asap.
 This code is being release under open-terms. Use at your own risk. Give us feedback. Help us fix bugs and implement new features. :)
 <contact@deensoft.com>
 
 You can follow up with more comments and suggestions on our blog <http://blog.deensoft.com>
  
 Description:
 	ProtoFlow v0.8 is a very early preview release that simulates Apples CoverFlow effect using Prototype/Scriptaculous lib.
 
 ChangeLog:
 	July 7, 2008:
 	* Fixed z-index issue - Thanks to Xavvier (http://www.euclide.org/) for the fix.
 	March 26, 2008:
 	* Fixed major issue with IE7 and z-index for scrollbar (Thanks to all those who contributed on the blog)
 	March 19, 2008
 	* Fixed issues with IE
 	* Fixed major bug with images and links...
 	
 	Initial:
 	* Added Reflection
 	* Fixed Captions
 	
 	How to use:
 	(start code)
 	var myFlow = new ProtoFlow(
 						$('myElem'),
 						{
 							captions: 'captionsList'
 						}
 	);
 	(end)
 */

var ProtoFlow = Class.create({

    initialize: function(elem, opt){
        opt = opt || {};
        this.options = {
            startIndex: 2,
            interval: 60,
            slider: true,
            flex: 200,
            captions: false,
            autoplay: false,
            autoplayInterval: 5,
            useReflection: false,
            enableOnClickScroll: false,
			enableKeyboard: true,
			enableMouse: true,
			imgWidth: 200,
			imgHeight: 100,
			url: "",
			scrollButtonBlank: "",
			scrollButtonOver: ""
        };
		Object.extend(this.options, opt);
		
        this.useCaptions = this.options.captions;
        this.elem = $(elem);
        if (!this.elem) 
            return;
        
        this.elem.setStyle({
            overflow: "hidden",
            position: "relative",
			display: "block"
        });
        this.imageStack = this.elem.select('img');
        if (this.options.captions != false) {
            this.captions = this.imageStack.pluck("title");
            this.captionsCount = this.captions.size();
        }
		
		this.ids = this.imageStack.pluck("alt");

        this.stack = this.imageStack;
        this.stackCount = (this.stack).size();       
        
        if (this.useCaptions) {
            this.captionHolder = new Element('div');
            this.captionHolder.className = "captionHolder";
            this.captionHolder.setStyle({
                width: "100%",
                textAlign: "center",
                position: 'absolute',
                left: "0px",
                top: (Element.getHeight(this.elem) - 80) + "px"
            });
			this.captionHolderLink = new Element('a', {href: "#"});
			this.captionHolderLink.observe('click', function() {
				this.loadContent(this.ids[this.currIndex])
			}.bind(this));
			this.captionHolder.appendChild(this.captionHolderLink);
            this.elem.appendChild(this.captionHolder);
        }
  
        this.currPos = this.options.startIndex - 1;
        this.currIndex = this.currPos;

        if (this.options.slider) {
            this.sliderContainer = new Element('div');
            this.sliderContainer.setStyle({
                position: 'absolute',
                top: (Element.getHeight(this.elem) - 10) + "px",
                left: (Element.getWidth(this.elem) / 2 - (399 / 2)) + "px",
                zIndex: 99999999
            });
            
            this.sliderTrack = new Element('div');
            this.sliderTrack.className = "sliderTrack";
            
            this.sliderHandle = new Element('div');
            this.sliderHandle.className = "sliderHandle";
            
            this.sliderTrack.appendChild(this.sliderHandle);
            this.sliderContainer.appendChild(this.sliderTrack);
            
            this.elem.appendChild(this.sliderContainer);
            
            this.slider = new Control.Slider(this.sliderHandle, this.sliderTrack, {
                range: $R(0, this.getStackCount() - 1),
				sliderValue: this.getCurrentPos(), 
                onSlide: this.handleSlider.bind(this),
                onChange: this.handleSlider.bind(this)
            });
			
			this.sliderHandle.observe('mouseover', (function(event) {
				var elem = event.element();
				elem.setStyle({
					background: "url('"+this.options.scrollButtonOver+"')"
				});
			}.bind(this)));
			
			this.sliderHandle.observe('mouseout', (function(event) {
				var elem = event.element();
				elem.setStyle({
					background: "url('"+this.options.scrollButtonBlank+"')"
				});
			}.bind(this)));
			var content = $('copyright');			
			this.originalContent = '<p id="copyright">'+content.innerHTML+'</p>';
			this.loadContent(this.ids[this.currIndex]);
        }          
        
        this.timer = 0;
                
        this.stack.each(function(elem){
            elem.identify();
            if (this.options.enableOnClickScroll) 
                elem.observe('click', this.handleClick.bind(this));
        }.bind(this));
        
        if (this.options.enableOnClickScroll) 
        {
            this.disableLinks();
        }
        
        this.goTo(this.currPos);
        
        this.autoplayer = null;
        if (this.options.autoplay) {
            this.autoplayer = new PeriodicalExecuter(this.autoPlay.bind(this), this.options.autoplayInterval);
        }

		if(this.options.enableKeyboard) {
		 document.observe('keyup', (function(e) {
		   var code = e.keyCode;
		   if(37 == code) this.previous();
		   if(39 == code) this.next();
		 }).bind(this));
		}

		if(this.options.enableMouse) {
		 var eventType = Prototype.Browser.Gecko ? "DOMMouseScroll" : "mousewheel";

		 Event.observe(this.elem, eventType, (function(e) {
		   this.enableMouse(e);
		 }).bind(this), false);

		 if (this.useCaptions) {
		   Event.observe(this.captionHolder, eventType, (function(e) {
			 this.enableMouse(e);
		   }).bind(this), false);
		 }
		}
        Event.observe(window, 'resize', this.handleWindowResize.bind(this));
    },

	 disableLinks: function(){
		this.elem.select("a").each(function(a){
			a.observe('click', function(e) {
				e.preventDefault();
			});
		});
	},

    autoPlay: function(){
        if ((this.currIndex + 2) > this.stackCount) {
            this.currIndex = 0;
        }
        this.currIndex = this.currIndex + 1
        this.goTo(this.currIndex);
    },

    handleWindowResize: function(event){
    },

    handleWheel: function(event){
        v = Event.wheel(event);
        this.goTo(this.currIndex + v);
        this.slider.setValue(this.currIndex + v);
    },
	
    handleSliderChange: function(index){
        this.goTo(index);
    },
    handleSlider: function(index){
		index = Math.round(index);
		this.currIndex = index
        this.goTo(index);
    },

    handleClick: function(e){
        var elem = Event.element(e);		
        var v = elem.getAttribute("index");        
		
		this.loadContent(this.ids[v]);
        this.currIndex = v;
        this.goTo(v);
        this.updateSlider(v);
    },

    getCurrentPos: function(){
        return this.currPos;
    },

    goTo: function(index){
		index = Math.round(index);
        this.slideTo(index * this.options.flex * -1);
        //this.currPos = Math.round(index);
        if (this.useCaptions) {
            this.captionHolderLink.innerHTML = this.captions[index];
        }
    },
	
	loadContent: function(id) {
		var content = $('content').select('.inner');
		content = content[1];
		new Ajax.Request(this.options.url+id, {
			method: 'get',
			onSuccess: function(transport) {
				content.update(transport.responseText+this.originalContent);
			}.bind(this)
		});
	},

    updateSlider: function(index){
        if (this.options.slider) 
            this.slider.setValue(index);
    },

    step: function(){
        if (this.target < this.currPos - 1 || this.target > this.currPos + 1 || this.target == 0) {
            this.moveTo(this.currPos + (this.target - this.currPos) / 5);
            window.setTimeout(this.step.bind(this), this.options.interval);
            this.timer = 1;
        }
        else {
            this.timer = 0;
            
        }
    },
    slideTo: function(x){
        this.target = x;
        
        if (this.timer == 0) {
            window.setTimeout(this.step.bind(this), this.options.interval);
            this.timer = 1;
        }
        
        
    },
    moveTo: function(currentPos){
        var x = currentPos;
        this.currPos = currentPos;
        var width = Element.getWidth(this.elem);
        var height = Element.getHeight(this.elem);

        var top = this.elem.offsetTop;
        var zIndex = this.stackCount;
		var flex = this.options.flex;
        this.stack.each(function(elem, index){
		Element.absolutize(elem);
		elem.setAttribute("index", index);

		var wsize = this.options.imgWidth;
        var hsize = this.options.imgHeight;

		var sign=1;
		if(x < 0)
			sign=-1;
		var mvt=Math.abs(x/flex/this.stackCount);

		if(mvt > 0.2) {
			mvt=Math.min(1, Math.pow(mvt, 0.1));
		}
		else if(mvt > 0.01) {
			mvt=mvt*4;
		}

		

		var per = 0
		var px = this.options.imgWidth;
		var py = this.options.imgHeight;
		var z = this.stackCount;
		if(z > 16) {
			z = 15;
		}
		if(index < this.currIndex) {			
			px -= mvt/(flex/5/(z*2))*px;
			py -= mvt/(flex/5/(z*2))*py;			
			zIndex++;
		}
		else if(index > this.currIndex) {
			px -= mvt/(flex/5/(z*2))*px;
			py -= mvt/(flex/5/(z*2))*py;
			zIndex--;
		}
		else {
			px -= mvt/(flex/5/(z*2))*px;
			py -= mvt/(flex/5/(z*2))*py;
			zIndex++;
		}

		
		var nx=Math.round(width/2 + sign * ((width-wsize))*(mvt/(5/this.stackCount+1))+(-px)/2);
		var ny=Math.round((height - hsize/2 - (height-hsize)/2)+(-py+29)/2);
			
		var t1 = px;
		var t2 = py;

		elem.setStyle({
			left: nx+'px',
			top: ny+'px',
			textAlign: "center",
			width: t1+"px",
			height: t2+"px"
		});
		elem.style.zIndex = zIndex;

		x += this.options.flex;
        }.bind(this));
    },
	
    getStackCount: function(){
        return this.stackCount;
    },
	decreaseIndex: function(e) {
		if(this.currIndex > 0)
			this.currIndex--;
	},

	increaseIndex: function(e) {
		if (this.currIndex < this.getStackCount() - 1)
			this.currIndex++;
	},

	previous: function(e) {
		this.decreaseIndex();
		this.toCurrentIndex();
	},

	next: function(e) {
		this.increaseIndex();
		this.toCurrentIndex();
	},

	enableMouse: function(e) {
		Event.wheel(e)< 0 ? this.previous() : this.next();
		Event.stop(e);
	},

	toCurrentIndex: function(e) {
		this.goTo(this.currIndex);
		this.updateSlider(this.currIndex);
	}	
});

Object.extend(Event, {
	wheel: function(event){
		var delta = 0;
		if (!event) event = window.event;

		if (event.wheelDelta) {
			delta = event.wheelDelta/120;
			if (window.opera) delta = -delta;
		} 
		else if (event.detail) {
			delta = -event.detail/3;
		}
		return Math.round(delta);
	}
});
