﻿// Extending MooTools Element
Element.implement({
	show: function() {
		this.setStyle('display', 'block');
	},
	hide: function() {
		this.setStyle('display', 'none');
	},
	toggle: function() {
		this.isVisible() ? this.hide() : this.show();
	},
	isVisible: function() {
		return this.getStyle('display') !== 'none';
	},
	dissolve: function (speed) {
		var el = this, speed = speed || 500;
		el.setStyle('opacity', 1);
		el.set('tween', {
			duration: speed,
			onComplete: function () {
				el.hide();
			}
		});
		el.tween('opacity', 0);
	},
	reveal: function (speed) {
		var el = this, speed = speed || 500;
		el.setStyle('opacity', 0);
		el.set('tween', {
			duration: speed,
			onStart: function () {
				el.show();
			}
		});
		el.tween('opacity', 1);
	},
	pulsate: function (from, to, freq, limit) {
		var from = from || 0, to = to || 1, freq = freq || 500, el = this, counter = 0;
		var tween = new Fx.Tween(el, {
			duration: freq,
			onComplete: function () {
				if (limit && el.getStyle('opacity') == to) {
					counter += 1;
				}
			}
		});
		
		var puls = function () {
			if (!limit || limit > counter) {
				el.getStyle('opacity') == from ? 
					tween.start('opacity', from, to) : tween.start('opacity', to, from);
			}
		}
		
		return puls.periodical(freq);
	}
});

// Basic tab class
var MooTabs = new Class({
	
	Implements: [Options],
	
	options: {
		activeTabClass: 'active',
		tabSelector: 'ul li',
		panelSelector: 'div',
		selectedTab: 0,
		rememberTab: false,
		cookieID: ''
	},
	
	container: 'tabs', // the container id string/element
	tabs: [], // the tab elements
	panels: [], // the panel elements
	cookieName: 'tabFxRemember', // the cookie name (prefix)
	
	initialize: function(container, options) {
		
		this.setOptions(options);
		this.container = (container ? $(container) : $(this.container));
		
		this.cookieName = this.options.cookieID || this.cookieName;
		this.options.selectedTab = this.options.selectedTab || Cookie.read(this.cookieName) || 0;
		
		if (this.options.rememberTab && !Cookie.read(this.cookieName)) {
			Cookie.write(this.cookieName, this.options.selectedTab);
		}
		
		this.tabs = this.container.getElements(this.options.tabSelector);
		this.panels = this.container.getElements(this.options.panelSelector);
		
		if (this.tabs.length != this.panels.length) {
			return false;
		}
		
		this.panels.each(function(element, index) {
			if (index != this.options.selectedTab)
				element.hide();
		}.bind(this));
		
		this.tabs.each(function(element, index) {
			element.addEvent('click', function(e) {
				e.stop();
				this.activate(index);
			}.bind(this));
			
			if (index == this.options.selectedTab)
				element.addClass(this.options.activeTabClass);
		}.bind(this));
	}, 
	
	activate: function(tab) {
		this.panels.each(function(element, index) {
			element.hide();
			
			if (tab == index) {
				element.show();
			}
		});
		
		this.tabs.each(function(element, index) {
			(tab == index) ? element.addClass(this.options.activeTabClass) : element.removeClass(this.options.activeTabClass);
		}.bind(this));
		
		if (this.options.rememberTab) {
			Cookie.write(this.cookieName, tab);
		}
	}
});

(function () {

	var read = function (option, element) {
		return (option) ? ($type(option) == 'function' ? option(element) : element.get(option)) : '';
	};

	this.Tips = new Class({

		Implements: [Events, Options],

		options: {
			/*
			onAttach: $empty(element),
			onDetach: $empty(element),
			*/
			onShow: function () {
				this.tip.show();
			},
			onHide: function () {
				this.tip.hide();
			},
			title: 'title',
			text: function (element) {
				return element.get('data-text');
			},
			showDelay: 100,
			hideDelay: 100,
			className: 'tip-wrap',
			offset: { x: 16, y: 16 },
			windowPadding: { x: 0, y: 0 },
			fixed: false
		},

		initialize: function () {
			var params = Array.link(arguments, { options: Object.type, elements: $defined });
			this.setOptions(params.options);
			if (params.elements) this.attach(params.elements);
			this.container = new Element('div', { 'class': 'tip' });
			this.titleElement = new Element('div', { 'class': 'tip-title' });
			this.textElement = new Element('div', { 'class': 'tip-text' });
			this.container.adopt(this.titleElement, this.textElement)
		},

		toElement: function () {
			if (this.tip) return this.tip;

			return this.tip = new Element('div', {
				'class': this.options.className,
				styles: {
					position: 'absolute',
					top: 0,
					left: 0
				}
			}).adopt(this.container);
		},

		attach: function (elements) {
			$$(elements).each(function (element) {
				var title = read(this.options.title, element),
				text = read(this.options.text, element);

				element.erase('title').store('tip:native', title).retrieve('tip:title', title);
				element.retrieve('tip:text', text);
				this.fireEvent('attach', [element]);

				var events = ['enter', 'leave'];
				if (!this.options.fixed) events.push('move');

				events.each(function (value) {
					var event = element.retrieve('tip:' + value);
					if (!event) event = this['element' + value.capitalize()].bindWithEvent(this, element);

					element.store('tip:' + value, event).addEvent('mouse' + value, event);
				}, this);
			}, this);

			return this;
		},

		detach: function (elements) {
			$$(elements).each(function (element) {
				['enter', 'leave', 'move'].each(function (value) {
					element.removeEvent('mouse' + value, element.retrieve('tip:' + value)).eliminate('tip:' + value);
				});

				this.fireEvent('detach', [element]);

				if (this.options.title == 'title') { // This is necessary to check if we can revert the title
					var original = element.retrieve('tip:native');
					if (original) element.set('title', original);
				}
			}, this);

			return this;
		},

		elementEnter: function (event, element) {
			var title = element.retrieve('tip:title'), text = element.retrieve('tip:text');
			this.titleElement.hide();
			this.textElement.hide();

			if (title) {
				this.titleElement.set('text', title).show();
			}

			if (text) {
				this.textElement.set('text', text).show();
			}

			$clear(this.timer);
			this.timer = (function () {
				this.show(element);
				this.position((this.options.fixed) ? { page: element.getPosition()} : event);
			}).delay(this.options.showDelay, this);
		},

		elementLeave: function (event, element) {
			$clear(this.timer);
			this.timer = this.hide.delay(this.options.hideDelay, this, element);
			this.fireForParent(event, element);
		},

		fireForParent: function (event, element) {
			element = element.getParent();
			if (!element || element == document.body) return;
			if (element.retrieve('tip:enter')) element.fireEvent('mouseenter', event);
			else this.fireForParent(event, element);
		},

		elementMove: function (event, element) {
			this.position(event);
		},

		position: function (event) {
			if (!this.tip) document.id(this);

			var size = window.getSize(), scroll = window.getScroll(),
			tip = { x: this.tip.offsetWidth, y: this.tip.offsetHeight },
			props = { x: 'left', y: 'top' },
			obj = {};

			for (var z in props) {
				obj[props[z]] = event.page[z] + this.options.offset[z];
				if ((obj[props[z]] + tip[z] - scroll[z]) > size[z] - this.options.windowPadding[z]) obj[props[z]] = event.page[z] - this.options.offset[z] - tip[z];
			}

			this.tip.setStyles(obj);
		},

		show: function (element) {
			if (!this.tip) document.id(this);
			if (!this.tip.getParent()) this.tip.inject(document.body);
			this.fireEvent('show', [this.tip, element]);
		},

		hide: function (element) {
			if (!this.tip) document.id(this);
			this.fireEvent('hide', [this.tip, element]);
		}

	});

})();

Fx.Scroll = new Class({

	Extends: Fx,

	options: {
		offset: { x: 0, y: 0 },
		wheelStops: true
	},

	initialize: function (element, options) {
		this.element = this.subject = $(element);
		this.parent(options);
		var cancel = this.cancel.bind(this, false);

		if ($type(this.element) != 'element') this.element = $(this.element.getDocument().body);

		var stopper = this.element;

		if (this.options.wheelStops) {
			this.addEvent('start', function () {
				stopper.addEvent('mousewheel', cancel);
			}, true);
			this.addEvent('complete', function () {
				stopper.removeEvent('mousewheel', cancel);
			}, true);
		}
	},

	set: function () {
		var now = Array.flatten(arguments);
		if (Browser.Engine.gecko) now = [Math.round(now[0]), Math.round(now[1])];
		this.element.scrollTo(now[0] + this.options.offset.x, now[1] + this.options.offset.y);
	},

	compute: function (from, to, delta) {
		return [0, 1].map(function (i) {
			return Fx.compute(from[i], to[i], delta);
		});
	},

	start: function (x, y) {
		if (!this.check(x, y)) return this;
		var scrollSize = this.element.getScrollSize(),
			scroll = this.element.getScroll(),
			values = { x: x, y: y };
		for (var z in values) {
			var max = scrollSize[z];
			if ($chk(values[z])) values[z] = ($type(values[z]) == 'number') ? values[z] : max;
			else values[z] = scroll[z];
			values[z] += this.options.offset[z];
		}
		return this.parent([scroll.x, scroll.y], [values.x, values.y]);
	},

	toTop: function () {
		return this.start(false, 0);
	},

	toLeft: function () {
		return this.start(0, false);
	},

	toRight: function () {
		return this.start('right', false);
	},

	toBottom: function () {
		return this.start(false, 'bottom');
	},

	toElement: function (el) {
		var position = $(el).getPosition(this.element);
		return this.start(position.x, position.y);
	},

	scrollIntoView: function (el, axes, offset) {
		axes = axes ? $splat(axes) : ['x', 'y'];
		var to = {};
		el = $(el);
		var pos = el.getPosition(this.element);
		var size = el.getSize();
		var scroll = this.element.getScroll();
		var containerSize = this.element.getSize();
		var edge = {
			x: pos.x + size.x,
			y: pos.y + size.y
		};
		['x', 'y'].each(function (axis) {
			if (axes.contains(axis)) {
				if (edge[axis] > scroll[axis] + containerSize[axis]) to[axis] = edge[axis] - containerSize[axis];
				if (pos[axis] < scroll[axis]) to[axis] = pos[axis];
			}
			if (to[axis] == null) to[axis] = scroll[axis];
			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
		}, this);
		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
		return this;
	},

	scrollToCenter: function (el, axes, offset) {
		axes = axes ? $splat(axes) : ['x', 'y'];
		el = $(el);
		var to = {},
			pos = el.getPosition(this.element),
			size = el.getSize(),
			scroll = this.element.getScroll(),
			containerSize = this.element.getSize(),
			edge = {
				x: pos.x + size.x,
				y: pos.y + size.y
			};

		['x', 'y'].each(function (axis) {
			if (axes.contains(axis)) {
				to[axis] = pos[axis] - (containerSize[axis] - size[axis]) / 2;
			}
			if (to[axis] == null) to[axis] = scroll[axis];
			if (offset && offset[axis]) to[axis] = to[axis] + offset[axis];
		}, this);
		if (to.x != scroll.x || to.y != scroll.y) this.start(to.x, to.y);
		return this;
	}
});

var PulseFade = new Class({

	//implements
	Implements: [Options, Events],

	//options
	options: {
		min: 0,
		max: 1,
		duration: 200,
		times: 5
	},

	//initialization
	initialize: function (el, options) {
		//set options
		this.setOptions(options);
		this.element = $(el);
		this.times = 0;
	},

	//starts the pulse fade
	start: function (times) {
		if (!times) times = this.options.times * 2;
		this.running = 1;
		this.fireEvent('start').run(times);
	},

	//stops the pulse fade
	stop: function () {
		this.running = 0;
		this.fireEvent('stop');
	},

	//runs the shizzle
	run: function (times) {
		//make it happen
		var self = this;
		var to = self.element.get('opacity') == self.options.min ? self.options.max : self.options.min;
		self.fx = new Fx.Tween(self.element, {
			duration: self.options.duration / 2,
			onComplete: function () {
				self.fireEvent('tick');
				if (self.running && times) {
					self.run(times - 1);
				} else {
					if (to == self.options.min) {
						self.run(0);
					}

					self.fireEvent('complete');
				}
			}
		}).start('opacity', to);
	}
});
