var Flute = new Class({
	Implements: [Options, Events],
	options: {
		'parent-element': false,
		'root-selector': 'ol.root',
		'menu-selector': 'ol',
		'item-selector': 'li',
		'delay': 100,
		'default-align': 'right',
		'default-valign': 'top',
		'default-position': 'relative',
		'default-anchor': 'item',
		'fade': false,
		'fade-options': {
			'duration': 'short',
			'transition': Fx.Transitions.Sine.easeInOut,
			'link': 'cancel'
		},
		'behavior': 'hover'
	},
	initialize: function(options) {
		this.setOptions(options);
		var that = this;
		this.timeouts = [];
		
		this.parent = $(this.options['parent-element']);
		if (!this.parent) return false;
		
		this.parent.getElements(this.options['menu-selector']).each(function(o, i) {
			var parent = $(o.get('data-flute-parent'));
			var id = o.get('id');
			if (!id) that.assign(o);
			if (parent) parent.set('data-flute-child', o.get('id'));
		});
		
		this.root = this.parent.getElements(this.options['root-selector']);
		if (!this.root.length) return false;
		this.root = this.root[0];
		this.walk(this.root, 1);
		
		var delegates = [];
		delegates[this.options['item-selector']] = function() {
			that.timeouts.each(function(o, i) {
				clearTimeout(o);
			});
			
			var parent = this.getParent();
			var level = parent.get('data-flute-level');
			
			that.parent.getChildren(that.options['menu-selector']).each(function(o, i) {
				if (o.get('data-flute-level') > level) {
					that.hide(o, true);
				}
			});
			
			var child = $(this.get('data-flute-child'));
			if (child) {
				var position = child.get('data-flute-position'), coordinates, anchor = child.get('data-flute-anchor');
				if (!position) position = that.options['default-position'];
				if (!anchor) anchor = that.options['default-anchor'];
				if (anchor == 'item') {
					if (position == 'absolute') {
						coordinates = this.getCoordinates();
					}
					else if (position == 'relative') {
						coordinates = this.getCoordinates(that.parent);
					}
				}
				else if (anchor == 'root') {
					coordinates = that.root.getCoordinates(that.parent);
				}
				that.show(child, coordinates);
			}
		};
		this.parent.delegateEvent('mouseover', delegates);
		if (this.options['behavior'] == 'hover') {
			this.parent.addEvent('mouseout', function() {
				that.timeouts.push(setTimeout(function() {
					that.check();
				}, that.options['delay'].limit(100, 5000)));
			});
		}
				
		this.parent.getChildren(that.options['menu-selector']).erase(this.root).each(function(o, i) {
			that.hide(o, true);
		});
	},
	walk: function(menu, level) {
		var that = this;
		$(menu).set('data-flute-level', level).getChildren(this.options['item-selector']).each(function(o, i) {
			if (o.get('data-flute-child')) that.walk($(o.get('data-flute-child')), level + 1);
		});
	},
	assign: function(el) {
		var seed = Math.floor(Math.random() * 1000000);
		var id = 'flute_' + seed;
		if ($(id)) {
			assign(el);
		}
		else {
			el.set('id', id);
		}
	},
	hide: function(menu, instant) {		
		var that = this;
		if (this.options['fade'] && !instant) {		
			menu.setStyles({
				'opacity': 1
			});
			menu.set('morph', that.options['fade-options']);
			menu.morph({
				'opacity': 0
			});
		}
		else {
			menu.setStyles({
				'display': 'none'
			});
		}
	},
	show: function(menu, coordinates) {
		var top, left, menu = $(menu), that = this, align = menu.get('data-flute-align'), valign = menu.get('data-flute-valign'), position = menu.get('data-flute-position');
		if (!align) align = this.options['default-align'];
		if (!valign) valign = this.options['default-valign'];
		if (!position) position = this.options['default-position'];
		if (!top) top = coordinates.bottom;
		if (!left) left = coordinates.right;
		
		if (position == 'relative') {
			left = coordinates[align];
			top = coordinates[valign]
		}
		
		$(menu).setStyles({
			'left': left,
			'top': top,
			'position': 'absolute'
		});
		
		if (this.options['fade']) {		
			menu.setStyles({
				'display': 'block',
				'opacity': 0
			});
			menu.set('morph', that.options['fade-options']);
			menu.morph({
				'opacity': 1
			});
		}
		else {
			menu.setStyles({
				'display': 'block'
			});
		}
	},
	check: function() {
		var that = this;
		this.parent.getChildren(that.options['menu-selector']).erase(this.root).each(function(o, i) {
			that.hide(o);
		});
	}
});