var Protofade = Class.create({
	initialize: function (b, a) {
		this.options = {
			duration: 1,
			delay: 4,
			randomize: false,
			autoplay: true,
			controls: false,
			eSquare: false,
			eRows: 3,
			eCols: 5,
			eColor: "#FFFFFF"
		};
		Object.extend(this.options, a || {});
		this.element = $(b);
		this.slides = this.element.childElements();
		this.num_slides = this.slides.length;
		this.current_slide = (this.options.randomize) ? (Math.floor(Math.random() * this.num_slides)) : 0;
		this.end_slide = this.num_slides - 1;
		this.slides.invoke("hide");
		this.slides[this.current_slide].show();
		if (this.options.controls) {
			this.addControls()
		}
		if (this.options.eSquare) {
			this.buildEsquare()
		}
		if (this.options.autoplay) {
			this.playSlideshow()
		}
	},
	addControls: function () {
		this.wrapper = this.element.up();
		this.controls = new Element("div", {
			"class": "protofade-controls"
		});
		this.wrapper.insert(this.controls);
		this.btn_prev = new Element("a", {
			"class": "protofade-prev",
			href: "#"
		});
		this.btn_play = new Element("a", {
			"class": "protofade-play",
			href: "#"
		});
		this.btn_stop = new Element("a", {
			"class": "protofade-stop",
			href: "#"
		});
		this.btn_next = new Element("a", {
			"class": "protofade-next",
			href: "#"
		});
		this.btns = [this.btn_prev, this.btn_play, this.btn_stop, this.btn_next];
		this.btns.each(function (a) {
			this.controls.insert(a)
		}.bind(this));
		this.btn_prev.observe("click", this.moveToPrev.bindAsEventListener(this));
		this.btn_next.observe("click", this.moveToNext.bindAsEventListener(this));
		this.btn_play.observe("click", this.playSlideshow.bindAsEventListener(this));
		this.btn_stop.observe("click", this.stopSlideshow.bindAsEventListener(this))
	},
	buildEsquare: function () {
		this.eSquares = [];
		var d = this.element.getDimensions();
		var c = d.width;
		var b = d.height;
		var e = c / this.options.eCols;
		var a = b / this.options.eRows;
		$R(0, this.options.eCols - 1).each(function (f) {
			this.eSquares[f] = [];
			$R(0, this.options.eRows - 1).each(function (i) {
				var h = f * e;
				var g = i * a;
				this.eSquares[f][i] = new Element("div").setStyle({
					opacity: 0,
					backgroundColor: this.options.eColor,
					position: "absolute",
					"z-index": 5,
					left: h + "px",
					top: g + "px",
					width: e + "px",
					height: a + "px"
				});
				this.element.insert(this.eSquares[f][i])
			}.bind(this))
		}.bind(this))
	},
	playSlideshow: function (a) {
		if (a) {
			Event.stop(a)
		}
		if (!this.running) {
			this.executer = new PeriodicalExecuter(function () {
				this.updateSlide(this.current_slide + 1)
			}.bind(this), this.options.delay);
			this.running = true;
			$$(".protofade-play").invoke("hide");
			$$(".protofade-stop").invoke("show")
		}
	},
	stopSlideshow: function (a) {
		if (a) {
			Event.stop(a)
		}
		if (this.executer) {
			this.executer.stop();
			this.running = false;
			$$(".protofade-play").invoke("show");
			$$(".protofade-stop").invoke("hide")
		}
	},
	moveToPrev: function (a) {
		if (a) {
			Event.stop(a)
		}
		this.stopSlideshow();
		this.updateSlide(this.current_slide - 1)
	},
	moveToNext: function (a) {
		if (a) {
			Event.stop(a)
		}
		this.stopSlideshow();
		this.updateSlide(this.current_slide + 1)
	},
	updateSlide: function (a) {
		if (a > this.end_slide) {
			a = 0
		} else {
			if (a == -1) {
				a = this.end_slide
			}
		}
		this.fadeInOut(a, this.current_slide)
	},
	fadeInOut: function (a, b) {
		new Effect.Parallel([new Effect.Fade(this.slides[b], {
			sync: true
		}), new Effect.Appear(this.slides[a], {
			sync: true
		})], {
			duration: this.options.duration
		});
		if (this.options.eSquare) {
			$R(0, this.options.eCols - 1).each(function (c) {
				$R(0, this.options.eRows - 1).each(function (f) {
					var e = this.eSquares[c][f];
					var d = Math.random() * 150;
					setTimeout(this.delayedAppear.bind(this, e), d)
				}.bind(this))
			}.bind(this))
		}
		this.current_slide = a
	},
	delayedAppear: function (b) {
		var a = Math.random();
		new Effect.Parallel([new Effect.Appear(b, {
			from: 0,
			to: a,
			duration: this.options.duration / 4
		}), new Effect.Appear(b, {
			from: a,
			to: 0,
			duration: this.options.duration / 1.25
		})], {
			sync: false
		})
	}
});