/*
Mif.Menu
*/

if(!window.Mif) var Mif={};

Mif.Menu=new Class({

	Implements: [Events, Options],
	
	options: {
		skin: 'default',
		align: 'bottomLeft'
	},

	initialize: function(options, skin){
		this.setOptions(options);
		this.target=this.options.target ? $(this.options.target) : document;
		this.showed=[];
		this.visible=[];
		this.hidden=true;
		if(!skin){
			switch(this.options.skin){
				case 'ART':
				case 'art': skin={
					container: ART.Container,
					options: {
						className: 'mif-menu-art',
						offsets:{x:-2, y:-3},
						theme: new ART.Theme({
							normal: {
								
								radius: 4,
								reflection: 0,

								overlayColor: '#fff',
								overlayOpacity: 0.9,
								borderOpacity: 0.2,
								shadow:8
								
							}
						})
					}
				}; break;
				case 'default': 
				default: skin={container: Mif.Menu.Container, options: {className: 'mif-menu-default', offsets:{x:-2, y:0}}};
			};
		};
		if(window.ART && Browser.Engine.trident && skin.container==ART.Container){
			skin.options.morph={duration:0};//because vml opacity with filter opacity=bug
		};
		this.List=Mif.Menu.List(skin);
		
		if(this.options.offsets){
			$extend(this.options.list, this.options.offsets);
		}
		this.list=new this.List(this.options.list, {menu: this});
		
		
		this.bound={
			escape: this.escape.bind(this),
			close: this.close.bind(this)
		};		
		this.addEvent('hide', function(){
			this.closing=false;
			this.hidden=true;
			document.removeEvent('keyup', this.bound.escape);
			document.removeEvent('mousedown', this.bound.close);
		}, true);
		this.addEvent('show', function(){
			this.hidden=false;
			document.addEvent('keyup', this.bound.escape);
			document.addEvent('mousedown', this.bound.close);
		}, true);
		
		this.initEvents();
	},
	
	close: function(event){
		if(this.$attaching) return;
		if(this.list.visible) this.hide();
	},
	
	initEvents: function(){
		if(this.options.contextmenu){
			this.target.addEvent('contextmenu', function(event){
				this.show(event);
				return false;
			}.bind(this));
		};
	},
	
	show: function(obj){
		this.closing=false;
		this.list.show(obj);
		return this.fireEvent('show');
	},
	
	escape: function(event){
		if(event.key!='esc') return;
		var list=this.showed.getLast();
		if(list) list.hide();
	},
	
	hide: function(){
		this.closing=true;
		this.list.hide();
	},
	
	isVisible: function(){
		return !this.hidden;
	},
	
	attachTo: function(el){
		el=$(el);
		this.show({relativeTo: el, position: this.options.align});
		this.hide();
		el.addEvents({
		
			'mousedown': function(event){
				if(event.rightClick) return;
				if(!this.isVisible()){
					this.$attaching=true;
					this.show({relativeTo: el, position: this.options.align});
					this.el=el;
				}else{
					this.hide();
				}
			}.bind(this),
			
			'mouseup': function(event){
				this.$attaching=false;
			}.bind(this)
			
		});
		return this;
	}
	
});

Mif.Menu.version='1.0';


/*
Mif.Menu.List
*/

Mif.Menu.List=function(skin){
	var skins=arguments.callee.skins;
	var lists=arguments.callee.lists;
	if(!skins) {
		skins=[]; 
		lists=[];
	};
	var index=skins.indexOf(skin);
	if(index!=-1) return lists[index];
	
	var List=new Class({

		Implements: [Events, Options],
		
		Extends: skin.container,
		
		options: $merge({
			styles: {
				'z-index': 1,
				position: 'absolute'
			}
		}, skin.options),

		initialize: function(options, structure){
			this.setOptions(options);
			this.parent($merge(this.options, {styles: {position: 'absolute'}}), 'mifmenu');
			this.list=new Element('ul', {'class': 'mif-menu-list'});
					
			this.openChildList=null;
			
			$extend(this, structure);
			$extend(this.options.offsets, this.menu.options.offsets);
			this.items=[];
			this.groups={};
			this.selected=null;
			
			this.initMenu();
			this.drawMenu();
			

			this.initEvents();
			this.container.setStyle('opacity',0);
			
		},
		
		initMenu: function(){
			this.options.items.each(function(options){
				var item=new Mif.Menu.Item(options, {list: this});
				this.list.adopt(item.container);
				if(!['separator', 'description'].contains(item.type)){
					this.items.push(item);
				}
			}, this);
		},
		
		drawMenu: function(){
			this.setContent(this.list).draw();
		},
		
		//private
		setWidth: function(){
			if(!Browser.Engine.trident) return;
			this.container.setStyle('width', 0);
			var width=this.list.offsetWidth;
			this.container.setStyle('width', width);
			this.list.setStyle('width',width);
			this.draw();
		},
		
		append: function(index, item){
			item.container.inject(this.items[index].container, 'after');
			this.items.inject(item, this.items[index], 'after');
		},
		
		initEvents: function(){
			this.container.addEvents({
				'click': this.action.bind(this),
				'mousedown': $lambda(false),
				'selectstart': $lambda(false),
				'mouseover': this.initSelect.bind(this),
				'mouseout': this.initSelect.bind(this)
			});
		},
		
		action: function(){
			var current=this.selected;
			if(!current||current.disabled||current.menu.closing) return false;
			this.menu.hide();
			current.fireEvent('action');
			return false;
		},
		
		hide: function(parents){
			if(this.hiding) return;
			this.hiding=true;
			this.unselect();
			this.menu.showed.erase(this);
			this.morpher.start({opacity: 0}).chain(function(){
				this.container.dispose();
				this.menu.visible.erase(this);
				this.hiding=false;
				if(!this.menu.visible.length) this.menu.fireEvent('hide');
			}.bind(this));
			this.hideChildren();
			if(!parents) return;
			this.hideParents();
		},
		
		hideParents: function(){
			if(this.parentItem) this.parentItem.list.hide(true);
		},
		
		hideChildren: function(){
			var open=this.openChildList;
			if(!open) return;
			open.hide();
			this.openChildList=null;
		},
		
		show: function(coords){
			if(this.menu.showed.contains(this) && !this.hiding) return;
			this.menu.showed.push(this);
			this.menu.visible.push(this);
			this.inject(document.body).draw();
			this.setWidth();
			this.hiding=false;
			this.visible=true;
			this.position(coords);
			this.morpher.start({opacity:1});
			this.showParents();
		},
		
		showParents: function(){
			if(!this.parentItem) return;
			this.parentItem.list.show();
		},
		
		initSelect: function(event){
			var target=event.target;
			if(!target||this.menu.closing) return this;
			if(target && Browser.Engine.trident){
				if(target.scopeName=='v') return this;
			}
			target=$(target);
			var item=target.getAncestorOrSelf('.mif-menu-item');
			
			if(!item){
				if(this.openChildList) return this;
				return this.unselect();
			};
			item=item.retrieve('item');
			if(!this.select(item)) return;
			if(!item.disabled && item.childList){
				item.timer=function(){
					item.childList.show();
					item.list.openChildList=item.childList;
					item.timer=null;
				}.delay(300);
			}
		},
		
		select: function(item){
			if(!item || item==this.selected || this.menu.closing) return false;
			this.unselect();
			item.select();
			this.show();
			this.selectParents(item);
			this.selected=item;
			this.menu.selected=item;
			return this;
		},
		
		selectParents: function(item){
			var parent=item.list.parentItem;
			if(!parent) return;
			parent.list.select(parent);
		},
		
		unselect: function(){
			var selected=this.selected;
			if(!selected) return;
			selected.unselect();
			if(selected.timer){
				$clear(selected.timer);
				selected.timer=null;
				return;
			}
			if(this.openChildList) this.openChildList.hide();
			this.openChildList=null;
			this.unselectChildren();
			this.selected=null;
			this.menu.selected=null;
		},
		
		unselectChildren: function(){
			var child=this.selected.childList;
			if(!child) return;
			child.unselect();
			child.hide();
		},
		
		position: function(coords){
			return this.setPosition(coords);
		}

	});
	
	skins.push(skin);
	lists.push(List);

	return  List;
}


/*
Mif.Menu.Item
*/

Mif.Menu.Item=new Class({

	Implements: [Events, Options],
	
	options: {
		type: 'default',
		checked: false,
		disabled: false,
		name: '',
		color: 'black',
		value: 0
	},

	initialize: function(options, structure){
		if(typeof options == 'string'){
			options={type: 'separator'};
		}
		this.setOptions(options);
		
		$extend(this, this.options);
		
		this.list=structure.list;
		this.menu=this.list.menu;
		
		this.draw();
		
		if(['description', 'separator'].contains(this.type)) return;
		
		if(this.disabled) {
			this.disabled=false;
			this.disable();
		}
		
		if(this.options.list) this.initChildList();
		
		if(this.type=='checkbox'){
			this.initCheckbox();
		}
		if(this.type=='radio'){
			this.initRadio();
		}
	},
	
	draw: function(){
		switch(this.type){
			case 'description': 
				this.container=new Element('li', {'class':'mif-menu-description mif-menu-name', html: this.options.name});
				break;
			case 'separator':
				this.container = new Element('li', {'class': 'mif-menu-separator mif-menu-name'});
				break;
			case 'default':
			case 'radio':
			case 'checkbox':
				this.dom={
					wrapper: new Element('div', {'class': 'mif-menu-item-wrapper'}),
					icon: new Element('span',{'class':'mif-menu-icon '+$pick(this.options.icon,''), html: Mif.Utils.zeroSpace}),
					name: new Element('span',{'class':'mif-menu-name', html: this.options.name})
				};
				this.dom.name.style.color=this.options.color;
				this.container=new Element('li',{'class': 'mif-menu-item'}).adopt(
					this.dom.wrapper.adopt(this.dom.icon, this.dom.name)
				);
				this.container.store('item', this);
		}
	},
	
	setState: function(state){
		if(this.disabled!=state){
			this.container[(state ? 'add' : 'remove') + 'Class']('mif-menu-disabled');
			this.disabled=state;
		}
		return this;
	},
	
	disable: function(){
		return this.setState(true);
	},
	
	enable: function(){
		return this.setState(false);
	},
	
	initChildList: function(){
		this.container.addClass('mif-childList');
		var options=$merge(this.options.list, {styles: {'z-index': this.list.options.styles['z-index']+1}});
		this.childList=new this.menu.List(options, {parentItem: this, menu: this.menu});
	},
	
	select: function(){
		var cls=this.disabled ? 'mif-menu-selected-disabled' : 'mif-menu-selected';
		this.container.addClass(cls);
		return this.fireEvent('select');
	},
	
	unselect: function(){
		var cls=this.disabled ? 'mif-menu-selected-disabled' : 'mif-menu-selected';
		this.container.removeClass(cls);
		return this.fireEvent('unSelect');
	},
	
	check: function(state){
		if(this.type=='checkbox'){
			if($defined(state)){
				if(this.checked==state) return this;
				this.checked=state;
			}else{
				this.checked=!this.checked;
			}
			if(this.checked){
				this.dom.icon.removeClass('mif-menu-unchecked').addClass('mif-menu-checked');
			}else{
				this.dom.icon.removeClass('mif-menu-checked').addClass('mif-menu-unchecked');
			}
			this.list.fireEvent('check', [this, this.checked]);
		}
		if(this.type=='radio'){
			var checked=$defined(state) ? state : true;
			if(this.checked==checked) return this;
			this.checked=checked;
			this.list.groups[this.group].each(function(item){
				if(item==this && this.checked){
					item.checked=true;
					item.dom.icon.addClass('mif-menu-radio-checked').removeClass('mif-menu-radio-unchecked');
					item.list.fireEvent('radioCheck', [this, true]);
					return;
				}else{
					item.checked=false;
					item.dom.icon.addClass('mif-menu-radio-unchecked').removeClass('mif-menu-radio-checked');
					item.list.fireEvent('radioCheck', [this, false]);
				}
			}, this);
		}
		return this;
	},
	
	initCheckbox: function(){
		this.dom.icon.addClass('mif-menu-'+(this.checked ? 'checked' : 'unchecked'));
		this.addEvent('action',this.check.bind(this));
	},
	
	initRadio: function(){
		this.list.groups[this.group]=(this.list.groups[this.group]||[]).include(this);
		this.dom.icon.addClass('mif-menu-radio-' + (this.checked ? 'checked' : 'unchecked'));
		this.addEvent('action',this.check.bind(this));
	}
	
});


/*
Mif.Menu.Menu
*/

if(!window.Mif) var Mif={};
if(!Mif.Utils) Mif.Utils={};

Mif.Utils.zeroSpace=Browser.Engine.trident ? '&shy;' : (Browser.Engine.webkit ? '&#8203' : '');

Element.implement({

	getAncestorOrSelf: function(match){
		var parent=this;
		while(parent){
			if(parent.match(match)) return parent;
			parent=parent.getParent();
		}
		return false;
	},
	
	setContent: function(content){
		return (typeof content == 'string') ? this.set('html', content) : this.adopt(content);
	}
	
});

Array.implement({
	
	inject: function(added, current, where){//inject added after or before current;
		var pos=this.indexOf(current)+(where=='before' ? 0 : 1);
		for(var i=this.length-1;i>=pos;i--){
			this[i+1]=this[i];
		}
		this[pos]=added;
		return this;
	}
	
});

if(Browser.Engine.presto){

	Element.Events.extend({

		contextmenu: {
			base: 'click',
			condition: function(event){ return event.alt;}
		}
		
	});
	
}


/*
Mif.Menu.Container
*/


Mif.Menu.Container=new Class({

	Implements: Options,
	
	options:{
		morph: {link: 'cancel'},
		offsets:{//max 6
			t: -5,
			r: 5,
			b: 5,
			l: -5
		},
		opacity: 1,
		styles:{
			position: 'relative'
		}
	},

	initialize: function(options){
		this.setOptions(options);
		this.offsets=this.options.offsets;
		this.container = new Element('div').setStyles(options.styles);
		if (options.id) this.container.set('id', options.id);
		if (options.className) $splat(options.className).each(function(cn){
			this.container.addClass(cn);
		}, this);
		this.morpher = new Fx.Morph(this.container, this.options.morph);
		
		
		this.shadow=new Element('div', {'class': 'mif-shadow'});
		if(Browser.Engine.trident){
			this.shadow.addClass('mif-shadow-ie');
			this.shadow.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity="+this.options.opacity*100+") progid:DXImageTransform.Microsoft.Blur(pixelradius=3)";
		}else{
			var sides=['tl','tr','br','bl','l','r','t','b','c'];
			var sideEls={};
			sides.each(function(side){
				el=new Element('div', {'class': 'mif-shadow-'+side}).setStyle('opacity', this.options.opacity);
				sideEls[side]=el;
				this.shadow.adopt(el);
			}, this);
			this.sideEls=sideEls;
		};
		this.center=new Element('div').setStyle('overflow', 'hidden');
		this.wrapper=new Element('div',{'class': 'mif-menu-wrapper', 'styles':{position: 'absolute', zIndex: 10}}).adopt(this.center);
		this.wrapper.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=100)";
		this.container.adopt(this.shadow, this.wrapper);
	},
	
	setStyle: function(style, value){
		this.container.setStyle(style, value);
		return this;
	},
	
	setStyles: function(styles){
		this.container.setStyles(styles);
		return this;
	},
	
	setContent: function(content){
		this.center.setContent(content);
		return this;
	},
	
	inject: function(element, how){
		this.container.inject(element, how);
		return this.draw();
	},
	
	draw: function(){
		this.shadow.setStyles({
			width:0,
			heigth:0
		});
		this.container.style.width='100%';
		var width=this.center.offsetWidth;
		var height=this.center.offsetHeight;
		var left=this.offsets.l;
		var top=this.offsets.t;
		var right=this.offsets.r;
		var bottom=this.offsets.b;
		this.shadow.setStyles({
			left: Math.max(-left, 0),
			top: Math.max(-top, 0)
		});
		var wrapperLeft=Math.max(left, 0);
		var wrapperTop=Math.max(top, 0);
		var wrapperRight=Math.max(right, 0);
		var wrapperBottom=Math.max(bottom, 0);
		this.offsetLeft=wrapperLeft;
		this.offsetTop=wrapperTop;
		this.wrapper.setStyles({
			left: wrapperLeft,
			top: wrapperTop
		});
		this.container.setStyles({
			width: width+wrapperLeft+wrapperRight,
			height: height+wrapperTop+wrapperBottom
		});
		var shadowWidth=width+left+right;
		var shadowHeight=height+top+bottom;
		if(Browser.Engine.trident){
			this.shadow.setStyles({
				width: Math.max(0, shadowWidth-6),
				height: Math.max(0, shadowHeight-6)
			});
		}else{
			this.sideEls.l.setStyle('height', shadowHeight-12);
			this.sideEls.r.setStyle('height', shadowHeight-12);
			this.sideEls.t.setStyle('width', shadowWidth-12);
			this.sideEls.b.setStyle('width', shadowWidth-12);
			this.sideEls.c.setStyles({
				width: shadowWidth-12,
				height: shadowHeight-12
			});
			this.shadow.setStyles({
				width: shadowWidth,
				height: shadowHeight
			});
		}
		return this;
	},
	
	setPosition: function(position){
		var x = 0;
		if(position.position.indexOf("ight")>0)
			x = this.container.getSize().x;
		var offset = {x: -x, y:5};
		this.container.position({
		    relativeTo: position.relativeTo,
		    position: position.position,
		    offset: offset,
		    relFixedPosition: true
		});
		
		return this;
	}

});


