/**
 * Script: class.floom.js
 *	Compatible with:
 *		mootools-1.2.4-core.js
 *		mootools-1.2.4.2-more.js
 *
 *	Inspired by Floom by Oskar Krawczyk: http://www.mootools.net/forge/p/floom
 *		Customized for personal preferences and project requirements
 *
 *	Description: blinds style slideshow
 */
var Floom = new Class({
  Implements: [Events, Options],

	Binds: ['setCoordinates'],

	options: {
    prefix: 'floom_',
    amount: 24,
    animationDuration: 70,
    interval: 8000,
    axis: 'vertical',
    progressbar: true,
    captions: true,
		id: ''/*,
    captionsFxOut: $empty,
    captionsFxIn: $empty,
    slidesBase: $empty,
    sliceFxIn: $empty,
    onSlideChange: $empty,
    onPreload: $empty*/
	},

	initialize: function(mainImage, slides, options) {
		this.setOptions(options);
    this.allSlidesPreloaded = false;
		this.isRunning = false;
    this.isPlaying = false;
		this.animation = null;
		this.paused = false;

		this.mainImage = document.id(mainImage); //img element (wallpaper)
		this.wrapper = new Element('div', {
		  'class': this.options.prefix+'wrapper',
			id: this.options.id || ''
		}).inject(document.body).grab(this.mainImage);

		this.slides = [];
		this.slices = {
			els: []
		};

		this.slidesPreloaded = 0;
		this.preloadStack = this.driver(slides);
	
		this.current = {
			slide: -1,
			counter: 0
		};
		this.createStructure();

    this.bound = {
			click: this.nextSlide.bind(this, false)
    }
		this.attach();
	},

  attach: function(attach) {
    var method = $pick(attach, true) ? 'addEvents' : 'removeEvents';
    this.wrapper[method]({
      click: this.bound.click
    });
    return this;
  },

  detach: function() {
    this.attach(false);
  },

	driver: function(slides) {
    //Build the options object from a set of elements
		if($type(slides[0]).contains('element')) {			
			var slidesElements = [];
			//Assign caption and the filename/url
			slides.each(function(slide) {
				slidesElements.push({
					image: slide.get('src'),
					caption: slide.get('title')
				});
			}.bind(this));

			//Remove redundant elements
			slides.destroy();
			//Assign the new object
			var slides = slidesElements;
		}
		return slides;
	},

	createStructure: function(){
		this.container = new Element('div', {
			'class': this.options.prefix+'container',
			styles: {
			  position: 'absolute',
			  zIndex: 2
			}
		});
		this.container.inject(this.wrapper, 'top');

		if(this.options.progressbar) this.createProgressbar();
		if(this.options.captions) this.createCaptions();

    this.setCoordinates();
		//Preload images and start up the slider
		this.preload();
	},

  setCoordinates: function() {
    var coordinates = this.mainImage.getCoordinates();

    this.coordinates = {
			wrapperWidth: coordinates.width,
			wrapperHeight: coordinates.height,
			slicesWidth: (this.options.axis == 'vertical' ?  coordinates.width / this.options.amount : coordinates.width).toInt(),
			slicesHeight:(this.options.axis == 'vertical' ? coordinates.height : coordinates.height / this.options.amount).toInt()
		};

		this.wrapper.setStyles({
	    width: (coordinates.left < 0 ? coordinates.right : coordinates.width),
	    height: (coordinates.top < 0 ? coordinates.height+coordinates.top : coordinates.height)
		});

		this.container.setStyles({
	    width: coordinates.width,
	    height: coordinates.height,
	    top: coordinates.top,
	    left: coordinates.left
		});
  },

	createProgressbar: function() {
		this.progressbar = new Element('div', {
			'class': this.options.prefix+'progressbar',
			morph: {
				duration: this.options.interval - (this.options.animationDuration * this.options.amount),
				transition: 'linear'
			}
		});
		this.progressbar.inject(this.wrapper, 'top');
	},
	
	createCaptions: function(){
		this.captions = new Element('div', {
			'class': this.options.prefix+'caption',
			html: 'caption',
			styles: {
				opacity: 0
			}
		});

		this.captions.inject(this.wrapper, 'top');
	},

	addImage: function(image) {
		this.preloadStack.push(image);
	},

	preload: function() {
    //Build the images array
		//console.log('preload: ', this.preloadStack);
		var preloadImgs = [];
    this.preloadStack.each(function(slide, stackIndex) {
			new Asset.image(this.options.slidesBase+slide.image, {
				onload: this.slideLoaded.bind(this, stackIndex)
			});
    }.bind(this));

    //Preload all and activate when done
		/*new Asset.images(preloadImgs, {
      onComplete: this.onPreload.bind(this)
    });*/
  },

  onPreload: function() {
    this.allSlidesPreloaded = true;
    this.play();
    this.fireEvent('onPreload', this.slides[this.current.slide+1]);
	},

	slideLoaded: function(stackIndex) {
		//console.log('slideLoaded met stackIndex: ', stackIndex, this.preloadStack[stackIndex]);
		this.slidesPreloaded++;
		this.slides.push(this.preloadStack[stackIndex]);

		if(!this.isRunning && this.slides.length > 1) {
			this.isRunning = true;
			this.play();
		}

		if(this.slidesPreloaded == this.preloadStack.length) {
			//console.log('slides: ', this.slides);
			this.allSlidesPreloaded = true;
			this.slidesPreloaded = 0;
			this.preloadStack = [];
			this.fireEvent('slidesPreloaded', this.slides);
		}
	},

	play: function() {
		//console.log('play: ', this.slides);
		if(this.paused) this.paused = false;
		this.animation = this.animateBlinds.periodical(this.options.interval, this);
	},

	pause: function(state) {
		this.paused = true;
		$clear(this.animation);
		if(this.options.progressbar) this.progressbar.fade('out');
		if(this.options.captions) this.captions.fade('out');
	},

  nextSlide: function(fast) {
		if(!$defined(fast)) fast = false;
		if(!this.allSlidesPreloaded || this.isPlaying) return;
		if(fast) {
			this.current.slide++;
			if(this.current.slide == this.slides.length) this.current.slide = 0;
			this.mainImage.set('src', this.options.slidesBase+this.slides[this.current.slide].image);
			this.slideChangeCompleted();
		} else {
	    this.pause();
	    this.animateBlinds();
	    this.play();
		}
  },

	animateBlinds: function() {
	if(console) console.log(this);
    this.isPlaying = true;
		this.current.slide++;
		if(this.current.slide == this.slides.length) this.current.slide = 0;

		//Create blinds
		for (var idx = 0; idx < this.options.amount; idx++) {
			this.createBlinds.delay(this.options.animationDuration * idx, this, idx);
		}

		//Hide the progressbar when it reaches the end
		if(this.options.progressbar) this.progressbar.fade('out');

		if(this.options.captions) {
			//Apply the animation
			this.captions.morph($merge({
				opacity: 0
			}, this.options.captionsFxOut));
		}

		return this.animateBlinds;
	},

	horizontal: function() {
    return {
      'background-position': '0 -'+(this.coordinates.slicesHeight * this.current.counter)+'px'
		};	
	},

	vertical: function() {
		return {
			'background-position': '-'+(this.coordinates.slicesWidth * this.current.counter)+'px 0'
		};
	},

	createBlinds: function(idx) {
		//Update the global counter
		this.current.counter = idx;

    //Create the slices
    var image = new Element('img', {
      src: this.options.slidesBase+this.slides[this.current.slide].image,
      styles: {
        width: this.coordinates.wrapperWidth.toInt(),
        height: this.coordinates.wrapperHeight.toInt(),
        'margin-left': -(this.coordinates.slicesWidth * this.current.counter).toInt()
      }
    });
		this.slices.els[idx] = new Element('div', {
			'class': this.options.prefix+'slice '+this.options.prefix+this.options.axis,
			tween: {
				duration: this.options.animationDuration * 4
			},
			styles: {
				opacity: 0,
				width: this.coordinates.slicesWidth,
				height: this.coordinates.slicesHeight,
				overflow: 'hidden'
			}
		}).grab(image).inject(this.container);

		//Animate the slide
		this.slices.els[idx].morph($merge({
			opacity: 1
		}, this.options.sliceFxIn));

		//Move to the next slide
		if(idx == this.options.amount-1) this.step.delay(this.options.animationDuration, this);
	},

	step: function() {
    //Apply the image to the main image element
		this.mainImage.set('src', this.options.slidesBase+this.slides[this.current.slide].image);

		//Destroy slices when animations finishes
		this.slices.els.each(function(slice) {
			slice.destroy();
		});

		//Prepare and animate the progressbar
		if(this.options.progressbar) {
      //Calculate the width of the progressbar including margins
      var calculatedWidth = this.container.getSize().x - (this.progressbar.getStyles('margin-left')['margin-left'].toInt() * 2);
      //Animate the size
      this.progressbar.morph({
				width: [0, calculatedWidth]
      });

      //Show the progressbar
      this.progressbar.fade('in');
		}

    //Update and animate the caption
    if(this.options.captions) {
      //Update the copy
      this.captions.set('html', this.slides[this.current.slide].caption);
      //Animate the caption
      this.captions.morph($merge({
        opacity: 1
      }, this.options.captionsFxIn));
    }

    this.isPlaying = false;
		this.slideChangeCompleted();
	},

	slideChangeCompleted: function() {
		this.fireEvent('onSlideChange', this.slides[this.current.slide]);
	}
});

Element.implement({
	floom: function(slides, options){
		return new Floom(this, slides, options);
	}
});
