/*
  popupmenu.js - simple JavaScript popup menu library.

  Copyright (C) 2008 Jiro Nishiguchi <jiro@cpan.org> All rights reserved.
  This is free software with ABSOLUTELY NO WARRANTY.

  You can redistribute it and/or modify it under the modified BSD license.

  Usage:
    var popup = new PopupMenu(className); //you can use different style for Popup
    popup.add(menuText, function(target){ ... });
    popup.addSeparator();
    popup.setSize(width,height); //optional default is auto; 0 - auto
    popup.bind('targetElement'); //element id
    popup.bind(); // target is document;
    popup.bind(element); //target as element
*/
/** static method to add event 
 * 
 * @param {Object} element - id or element
 * @param {Object} name - event name ('click')
 * @param {Object} observer - callback function
 * @param {Object} capture - capture method false up/true down
 */
function _addEventListener(element, name, observer, capture) {
    if (typeof element == 'string') {
        element = document.getElementById(element);
    }
    if (element.addEventListener) {
        element.addEventListener(name, observer, capture);
    } else if (element.attachEvent) {
        element.attachEvent('on' + name, observer);
    }
};

var PopupMenu = function(className,onShow) {
	this.ETimeOut=3000; 
	this.className=className;
	this.onShow=onShow; //user funtion executed when popup was showed
    this.init();
}
PopupMenu.SEPARATOR = 'PopupMenu.SEPARATOR';
PopupMenu.current = null;


PopupMenu.prototype = {
    init: function() {
        this.items  = [];
        this.width  = 0;
        this.height = 0;
    },
	addOnShow: function(f){
		this.onShow=f;
	},
    setSize: function(width, height) {
        this.width  = width;
        this.height = height;
//		if(width==0)this.width='auto';
//		if(height==0)this.height='auto';
        if (this.element) {
            var s = this;
            with (this.element.style) {
                if (s.width)  width  = s.width  + 'px';
                if (s.height) height = s.height + 'px';
            }
        }
    },
	/** bint event to element;event_type:1-contextmenu;2-click;3-both */
    bind: function(element,event_type) {
        var bind_show = function(e) {
            s.show.call(s, e, this);
			};
		var bind_hide = function(){
			s.hide.call(s); 			
		};
		if(!event_type)var event_type=0xf; //all
        var s = this;
        if (!element) {
            element = document;
        } else if (typeof element == 'string') {
            element = document.getElementById(element);
        }
		if (event_type & 0x01) {
			element.oncontextmenu = function(e){
				s.show.call(s, e, this);
				return false;
			};
		}
		if (event_type & 0x02) {
			_addEventListener(element, 'click', bind_show, false);
		}
        _addEventListener(document, 'mouseup', bind_hide, false);
    },
    add: function(text, callback) {
        this.items.push({ text: text, callback: callback, active:true });
    },
	itemDeactivate: function(text){ /** deactivate item text */
		for(var i=0;i<this.items.length;i++){
			if(this.items[i].text==text)this.items[i].active=false;
		}
	},
	/** deactivate item text */
	itemAtivateAll: function(){
		for(var i=0;i<this.items.length;i++){
			this.items[i].active=true;
		}
	},
    addSeparator: function() {
        this.items.push(PopupMenu.SEPARATOR);
    },
	clear: function(){
		this.items.length=0;
		if (this.element) this.element.style.display = 'none';
		this.element=null;
	},
    setPos: function(e) {
        if (!this.element) return;
        if (!e) e = window.event;
        var x, y,x_max,y_max;
		if(window.innerWidth){ //FF;Opera
			x_max=window.innerWidth+window.pageXOffset; 
			y_max=window.innerHeight+window.pageYOffset; //window.scrollY;
		} else {
			with(document.documentElement){ //IE
				x_max=clientWidth+scrollLeft;
				y_max=clientHeight+scrollTop;
			}
		}
		//document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop
        if (window.opera) { //Opera
            x = document.body.scrollLeft + e.clientX;
            y = document.body.scrollTop + e.clientY;
//			console.log("Opera x,y:",x,y,x_max,y_max);
        } else if (document.all) { //IE
            x = document.documentElement.scrollLeft + window.event.clientX;
            y = document.documentElement.scrollTop + window.event.clientY;
//			console.log("IE x,y:",x,y,x_max,y_max);
        } else if (document.layers || document.getElementById) {
            x = e.pageX; //Navigator FF
            y = e.pageY;
//			console.log("FF x,y:",x,y,x_max,y_max);
        }
		with (this.element) {
			style.left = x + 'px';
			style.top = y + 'px';
			style.display = '';
//			document.body.appendChild(this.element);
			if (x+clientWidth > x_max) 
				this.element.style.left = (x-clientWidth) + 'px';
			if (y+clientHeight > y_max) 
				this.element.style.top = (y-clientHeight) + 'px';
		}
    },
    show: function(e, target) {
		if (!e) 
			e = window.event;
		if (!e.target) //Opera bug? e.srcElement) 
			e.target = e.srcElement; //for IE
		if (e.target.nodeType == 3) 
			e.target = e.target.parentNode; // defeat Safari bug
		var s=this;
		this.itemAtivateAll();
		if (this.onShow)this.onShow(e.target);
        if (PopupMenu.current && PopupMenu.current != this) return;
        PopupMenu.current = this;
        if (!this.element) {
            this.element = this.createMenu(this.items);
            document.body.appendChild(this.element);
	        var start = function() {s.startTimer.call(s) };
	        var stop = function() {s.stopTimer.call(s) };
	        _addEventListener(this.element, 'mouseover', stop, false);
	        _addEventListener(this.element, 'mouseout', start, false);
        }
        this.setPos(e);
		this.target = e.target;
		this.startTimer();
    },
	stopTimer: function(){
		clearTimeout(this.timer);
	},
	startTimer: function(){
		var s=this;
        var hide = function() {s.hide.call(s) };
		clearTimeout(this.timer);
		this.timer=setTimeout(hide, this.ETimeOut);
	},
    hide: function() {
		clearTimeout(this.timer);
        PopupMenu.current = null;
        if (this.element) this.element.style.display = 'none';
		this.element=null;
    },
    createMenu: function(items) {
        var s = this;
        var menu = document.createElement('div');
		menu.className=this.className;
        with (menu.style) {
            if (s.width)  width  = s.width  + 'px';
            if (s.height) height = s.height + 'px';
        }
        for (var i = 0; i < items.length; i++) {
            var item;
            if (items[i] == PopupMenu.SEPARATOR) {
                item = this.createSeparator();
            } else {
                item = this.createItem(items[i]);
            }
            menu.appendChild(item);
        }
        return menu;
    },
    createItem: function(item) {
        var s = this;
        var elem = document.createElement('div');
		if (item.active) {
			var callback = item.callback;
			_addEventListener(elem, 'click', function(_callback){
				return function(){
					s.hide();
					_callback(s.target);
				};
			}(callback), false);
		} else {
			elem.className="inactive";
		}
        elem.appendChild(document.createTextNode(item.text));
        return elem;
    },
    createSeparator: function() {
        var sep = document.createElement('p');
        return sep;
    }
};


