/*  Noopty Slideshow & Noopty Image Scaler version 1.0
 *  (c) 2010 Outpost Design
 *
 *  SVN FILE: $Id: noopty.js 570 2010-05-20 14:41:20Z michaelklauss $
 *--------------------------------------------------------------------------*/

var Noopty = Class.create({
	container:      null,
	slides:         [],
	currentSlide:   0,
	nextSlide:      0,
	initialize: function(args) {
		// update default options
		var h = $H(args);
		h.each(function(item) {
			if( typeof(this.options[item.key]) != 'undefined' ) {
				this.options[item.key] = item.value ;
			}
		}.bind(this));
		// set slide container element
		if(this.options.containerId!=null) {
			this.container = $(this.options.containerId);
		}
		// select slide elements
		if(this.options.slide!=null) {
			this.slides = this.container.select(this.options.slide);
		} else {
			this.slides = this.container.childElements();
		}
		this.slides.each(function(s) {s.hide();}); // hide them by default
		if(this.options.shuffle){this.slides.shuffle();} // mix them up

		// set a primary image as the default image (maybe something with a logo)
		// we swap the src to show a different version of the image
		// only when it's the very first image on display
		// after it's been seen, we roll it back to it's default value
		if(this.options.primary==true) {
			for(i=0;i<this.slides.length;i++) {
				if(this.slides[i].readAttribute('primary')=='true') {
					this.currentSlide = i;
					this.setprimary(this.slides[i]);
					break;
				}
			}
		}
		if(this.options.before!=null) {
			this.options.before(this.slides[this.currentSlide]);
		}
		this.slides[this.currentSlide].show();

		// attach UI events
		this.attachui();
	},
	attachui: function() {
		if(this.options.hover) {
			this.slides.each(function(item) {
				if(this.options.mouseenter != null) {
					item.observe('mouseenter',function(evt){
						this.stop();
						this.options.mouseenter(evt);
					}.bindAsEventListener(this));
				}
				if(this.options.mouseleave != null) {
					item.observe('mouseleave',function(evt){
						this.options.mouseleave(evt);
						this.start();
					}.bindAsEventListener(this));
				}
			}.bind(this));
		}
		['next','back','stop','start'].each(function(item) {
			var action = function(evt) {
				evt.stop();
				this[item]();
			}.bindAsEventListener(this)
			$$(this.options[item]).each(function(item) {
				item.observe('click',action);
			});
		}.bind(this));
	},
	start: function() {
		this.stop();
		if(this.options.timeout > 0) {
			this.peHandle = new PeriodicalExecuter(function(){this.next();}.bind(this),(this.options.delay));
			this.options.delay = this.options.timeout; // delay used on initial start only
		}
	},
	stop: function() {
		if(this.peHandle!=null) {
			this.peHandle.stop();
		}
	},
	back: function() {
		this.move('back');
	},
	next: function() {
		this.move('next');
	},
	move: function(pos) {
		if( pos=='next') {
			this.nextSlide = this.currentSlide +1;
		} else if ( pos=='back' ) {
			this.nextSlide = this.currentSlide -1;
		} else {
			this.nextSlide = pos;
		}
		if(this.nextSlide < 0) {
			this.nextSlide = this.slides.length-1;
		}
		if(this.nextSlide >= this.slides.length) {
			this.nextSlide = 0;
		}
		this.transition();
	},
	transition: function() {
		if(this.inprogress != true) {
			// Prevent new transition while one is in progress
			this.inprogress = true;
			// Run before callback
			if(this.options.before!=null) {
				this.options.before(this.slides[this.nextSlide]);
			}
			// Fade out current slide - Fade in next slide
			this.slides[this.currentSlide].fade({
				duration: this.options.duration
			});
			this.slides[this.nextSlide].appear({
				duration: this.options.duration,
				afterFinish:function() {
					this.release();
				}.bind(this)
			});
		}
	},
	release: function() {
		this.inprogress = false;
		// run after callback
		if(this.options.after!=null) {
			this.options.after(this.slides[this.currentSlide]);
		}
		if(this.options.primary==true) {
			this.removeprimary();
		}
		// Update current - next slide references
		this.currentSlide = this.nextSlide;
		this.nextSlide    = null;
		// Reset PeriodicalExecuter
		this.start();
	},
	setprimary: function(slide) {
		if(this.options.primary_sufx == null){ return; }
		// find the <img> and update the src to pull the primary image
		var img = (slide.tageName=='IMG')? slide : slide.select('img')[0] ;
		var pos = img.src.lastIndexOf(".");
		img.src = img.src.substring(0,pos)+this.options.primary_sufx+img.src.substring(pos);
	},
	removeprimary: function() {
		if(this.options.primary_sufx == null){ return; }
		this.slides.each(function(slide) {
			var img = (slide.tageName=='IMG')? slide : slide.select('img')[0] ;
			if(img.src.match( this.options.primary_sufx + '.') ) {
				img.src = img.src.replace((this.options.primary_sufx + '.'), '.');
			}
		}.bind(this));
	},
	options: {
		containerId:   null,  // id of slide container element
		slide:         null,  // expression for selecting slides (if something other than all children is required)
		delay:         6.0,   // additional delay (in seconds) for first transition
		timeout:       6.0,   // seconds between slide transitions (0 to disable auto advance)
		duration:      1.0,   // speed of the transition in seconds
		next:          '[class="nooptyNext"]',  // expression for selecting elements to use as click trigger for next slide
		back:          '[class="nooptyBack"]',  // expression for selecting elements to use as click trigger for back slide
		stop:          '[class="nooptyStop"]',  // expression for selecting elements to use as click trigger for stop transitions
		start:         '[class="nooptyStart"]', // expression for selecting elements to use as click trigger for start transitions
		before:        null,  // transition callback (scope set to element to be shown)
		after:         null,  // transition callback (scope set to element that was shown)
		mouseenter:    null,  // mouseenter callback
		mouseleave:    null,  // mouseleave callback
		hover:         0,     // true to enable "pause on hover"
		shuffle:       0,     // randomize our array of slides
		primary:       0,      // load slides with attribute "primary"="true" by default
		primary_sufx:  '-primary' // append a suffix to the default primary image to show an alternate version (with logo for example)
	},
	version: function() {
		return '1.0';
	}
});

var NooptyScaler = Class.create({
	vp: null,
	imgs: [],
	initialize: function(args) {
		// update default options
		var h = $H(args);
		h.each(function(item) {
			if( typeof(this.options[item.key]) != 'undefined' ) {
				this.options[item.key] = item.value ;
			}
		}.bind(this));
		// set slide container element
		if(this.options.containerId!=null && this.options.image!=null) {
			var images = $(this.options.containerId).select(this.options.image);
		} else {
			var images = $$(this.options.image);
		}
		images.each(function(image,idx) {
			this.imgs.push({
				ele: image,
				width: image.getWidth(),
				height: image.getHeight(),
				ratio: image.getWidth()/image.getHeight()
			});
			if(!this.options.rightclick) {
				image.oncontextmenu = function(){return false;};
			}
		}.bind(this));
		if(this.options.coverId!=null && !this.options.rightclick) {
			$(this.options.coverId).oncontextmenu = function(){return false;};
		}
		this.update();
	},
	update_vp: function() {
		this.vp = $(this.options.containerId).getDimensions();
		this.vp.ratio = this.vp.width/this.vp.height;
	},
	update: function() {
		this.update_vp();
		this.imgs.each(function(obj) {
			this.resize(obj);
		}.bind(this));
	},
	resize: function(obj) {
		var w,h,t=0,l=0;
		if( this.vp.ratio == obj.ratio) {
			w = this.vp.width;
			h = this.vp.height;
		} else if( this.vp.ratio > obj.ratio) { // window more horizontal than image
			w = this.vp.width;
			h = Math.abs((w*obj.height)/obj.width);
			t = Math.abs((h - this.vp.height)/2);
		} else { //  this.vp.ratio < obj.ratio // window more vertical than image
			h = this.vp.height;
			w = Math.abs((h*obj.width)/obj.height);
			l = Math.abs((w-this.vp.width)/2);
		}
		obj.ele.setStyle({'width':w+'px',
		              'height':h+'px',
		              'left':-l+'px',
		              'top':-t+'px'});
	},
	options: {
		containerId:   null,  // id of slide container element
		coverId:       null,  // id of slide cover element
		image:         null,  // expression for selecting slides (if something other than all children is required)
		rightclick:    true  // disable right click on image
	},
	version: function() {
		return '1.0';
	}
});

 Array.prototype.shuffle = function(deep) {
	var i = this.length, j, t;
	while( i ) {
		j = Math.floor( ( i-- ) * Math.random() );
		t = deep && typeof this[i].shuffle!=='undefined' ? this[i].shuffle() : this[i];
		this[i] = this[j];
		this[j] = t;
	}
	return this;
};

