﻿/*  PIAScript JavaScript framework, version 0.1
 *  (c) 2008 Vlada Petrović
 *
 *  PIAScript is distributed with PIACms.NET project on Kivi Com d.o.o. terms
 *--------------------------------------------------------------------------*/

/*
 * UTIL
 */
Object.extend(String, {
	format: function(s) {
		for(var i=1,l=arguments.length; i<l; i++) {
			s = s.replace("{" + (i -1) + "}", arguments[i]);
		}
		return s;
	}
});

function selectClassName(el,btns,classNameTxt){
	btns.invoke("removeClassName",classNameTxt);
	el.addClassName(classNameTxt);
}

if (!window.console) {
	window.console = {
		log: function(){}
	}
}

/*
 * PIA base
 */
var PIA = function() {
    var q = null;
    var preDomLoad = function() { setTimeout(domLoad, 100); }; // ie is slow
    var domLoad = function() { if (q) q.run(); };

    document.observe("dom:loaded", preDomLoad);

    return {
        log: function(_values) {
            //			firebug.d.console.log(_values);
            //			console.log(_values);
        },
        namespace: function(namespaceTxt) {
            for (var i = 0, o = window, ns = namespaceTxt.split('.'), l = ns.length; i < l; i++)
                o = o[ns[i]] = o[ns[i]] || {};
            return o;
        },
        alias: function(name, object) {
            if (window[name] == null) window[name] = object;
            else throw ("Alias [" + name + "] already exists.");
        },
        onLoad: function(fn, name, isFirst) {
            if (!q) q = new PIA.Class.Queue();
            q[isFirst != null && isFirst ? "addFirst" : "add"](fn, name);
        },
        loadScript: function(scriptPath) {
            var script = document.createElement("script");
            script.type = "text/javascript";
            script.src = scriptPath;
            document.getElementsByTagName("head")[0].appendChild(script);
        }
    };
} ();

/* PIAScript namespaces */
PIA.namespace("PIA.Class");
PIA.namespace("PIA.UI");
PIA.namespace("PIA.Modules");
PIA.namespace("PIA.Util");

PIA.Class.Queue = Class.create({
	initialize: function(){
		this.id = 0;
		this.q = [];
	},
	
    run: function() {
        var c  = this.q[0],fn;
        if (!c) return this;
        else if (this.id) return this;

        fn = c.fn;
		this._shift();
		
        if (typeof fn === 'function') {
            var ms = 0,me = this;
            this.id = setTimeout(function () {
                me._exec(fn,c);
                if (me.id) {
                    me.id = 0;
                    me.run();
                }
            },ms);
        }
        return this;
    },

    _exec: function(fn,c) {		
        fn.call(this);
    },
    
    _shift: function() {
        this.q.shift();
    },

    add: function(fn,name) {
        this.q.push({fn:fn,name:name});
        return this;
    },
    
    addFirst: function(fn,name) {
        this.q.unshift({fn:fn,name:name});
        return this;
    },
    
    pause: function() {
        clearTimeout(this.id);
        this.id = 0;
        return this;
    },

    stop: function() {
        this.pause();
        this.q = [];
        return this;
    }
});

window.pialoading = null;
function cancelLoading(){
    var s = $("senca2");
    if(s!=null){
        s.hide();
    }
};
function startLoading(){
    var s = $("senca2");
    if(s!=null){
        s.show();
    }
};
PIA.Ajax = function() {
    var settings = null;

    var sendAjax = function() {
        var method = null, properties = $A(arguments), settings = {};
        method = properties.shift();
        isSettings(properties[properties.length - 1]) && (settings = properties.pop());

        var results = [];
        properties.each(function(object) {
            var value = Object.toJSON(object);
            if (!Object.isUndefined(value)) results.push(value);
        });

        // send ajaxSend event
        document.fire("ajax:send", getThread(settings));
        eval(method + "(" + results.join(",") + (results.length > 0 ? ", " : "") + "sendAjax_callback.bind(settings));");
    }

    var getAjax = function() {
        var method = null, properties = $A(arguments), settings = {};
        method = properties.shift();
        isSettings(properties[properties.length - 1]) && (settings = properties.pop());

        var results = [];
        properties.each(function(object) {
            var value = Object.toJSON(object);
            if (!Object.isUndefined(value)) results.push(value);
        });

        // send ajaxSend event
        document.fire("ajax:get", getThread(settings));
        startLoading();
        var res = eval(method + "(" + results.join(",") + ");");
        var tmp = sendAjax_callback.bind(settings);
        return tmp(res);
    }

    var isSettings = function(object) {
        return object != null && typeof object === "object" &&
		('onSuccess' in object || 'onError' in object || 'thread' in object);
    };

    var getThread = function(settings) {
        var r = {};
        if ("thread" in settings)
            r["thread"] = settings["thread"];
        return r;
    };

    var sendAjax_callback = function(res) {
        document.fire("ajax:back", getThread(this));
        cancelLoading();

        if (res.error) {
            if(res.error.Type=="PIA.CustomException.SessionExpiredException"){
                alert(res.error.Message);
                var loginurl = $("login_redirect");
                if(loginurl){
                    window.location = loginurl.value;
                }
            }
            else if ('onError' in this)
                this['onError'](printError(res.error), res.error);
            else {
                PIA.Ajax.onError(printError(res.error));
            }
        }
        else {
            if ('onSuccess' in this)
                this["onSuccess"](res.value);
            else return res.value; // get request
        }
    };

    var printError = function(error) {
        var msg = [];
        msg.push("<h2>Message</h2>" + error["Message"]);
        msg.push("<h2>Type</h2>" + error["Type"]);
        msg.push("<h2>TargetSite</h2>" + error["TargetSite"]);
        msg.push("<h2>Source</h2>" + error["Source"]);
        msg.push("<h2>Stack</h2>" + error["Stack"]);
        return msg.join('<br />');
    };

    return {
        send: sendAjax,
        get: getAjax,
        onError: function() { }
    }
} ();

PIA.AjaxMonitor = Class.create({
    request: function(sender) {
        var thread = sender.memo.thread;
//        console.log("request: %o", Object.toJSON());
    },

    response: function(sender) {
//        console.log("response: %o", Object.toJSON(sender.memo));
    },

    initialize: function() {
        document.observe("ajax:send", this.request);
        document.observe("ajax:back", this.response);
    }
});

/* UI */
PIA.UI.LightBox = (function(){
	window.LB = [];
	
	function getInstance(objID){
		if("undefined" == typeof window.LB[objID])
			window.LB[objID] = new PIA.Modules.LightBox();
		return window.LB[objID];
	};
	
	return {
		open: function(obj){
			if("string" == typeof obj) obj = $(obj);
			var o = getInstance(obj.id);
			o.open(obj);
		},
		
		close: function(obj){
			if("string" == typeof obj) obj = $(obj);
			var o = getInstance(obj.id);
			o.close(obj);
		}
	}
})();


PIA.UI.TableList = Class.create({
	initialize: function(tableid){
		this.activeClassName = "active";
		this.table = $(tableid);
		if(this.table)
			this.init();
	},
	
	init: function(){
		this.table.selectedItem = -1;
		this.clickEvent = this.onClick.bind(this);
		this.table.observe("click", this.clickEvent);
		this.trs = this.table.select("tr");
	},
	
	onClick: function(ev){
		if(ev.element().tagName!="A")
			ev.stop();
		
		var element = ev.findElement("tr");
		if(element.getElementsByTagName("td").length>0){
			if(element.hasClassName(this.activeClassName)) {
				element.removeClassName(this.activeClassName);
				this.table.selectedItem = -1;
			} else {
				for(var i=0,l=this.trs.length; i<l; i++) {
					this.trs[i].removeClassName(this.activeClassName);
				}
				element.addClassName("active");
				this.table.selectedItem = element.id.split("/").length>1 ? element.id.split("/")[1] : null;
			}
			
			this.table.fire("table:onselect");
		}
	}
});


/**
 PIA.UI.TableListBase is the base class for table funcionality in PIA application
 
 Order:
	- options.canSelect
	- table:click				(E)
	- options.getKey
	- table:empty | table:first (E)
	- table:add | table:remove	(E)
*/
PIA.UI.TableListBase = Class.create({
    initialize: function(tableid) {
        this.table = $(tableid);
        this.options = Object.extend({
            multiple: false, 							// can i select multiple items
            rowContainerCss: "tbody", 				// specify container for rows ""|"thead"|"tbody"|"tfoot"
            selectedClassName: "active", 				// css class for selected row
            canSelect: function(row) { return true; }, // you can specify function to control witch rows you can select
            getKey: function(row) { return row.id; } 	// specify haw you collect key from TR
        }, arguments[1] || {});

        if (!this.table) {
            throw new Error("You must specify id for table or HTMLTable element");
            return;
        }

        this.init();
    },


    init: function() {
        this.clickEvent = this.onClick.bind(this);
        this.rowContainer = this.options.rowContainerCss.length > 0 ? this.table.select(this.options.rowContainerCss)[0] : this.table;
        this.rowContainer.observe("click", this.clickEvent);
        this.reset();

        // TESTING
        //		this.table.observe("table:click", function(event) { console.log("Click: %o",event.memo); });
        //		this.table.observe("table:empty", function(event) { console.log("Empty"); });
        //		this.table.observe("table:first", function(event) { console.log("First"); });
        //		this.table.observe("table:add", function(event) { console.log("Add: %o",event.memo); });
        //		this.table.observe("table:remove", function(event) { console.log("Remove: %o",event.memo); });
    },


    reset: function() {
        delete this.selectedItems;
        this.selectedItems = $H();
    },


    fire: function(eventname) {
        this.table.fire("table:" + eventname, arguments[1] || {});
    },


    onClick: function(ev) {
        if (["input", "select", "textarea", "legend"].indexOf(ev.element().tagName.toLowerCase()) != -1) return null;

        var element = ev.findElement("tr");

        if (element.getElementsByTagName("td").length == 0) return null;
        if (this.options.canSelect(element)) {
            this.update(element, this.selectRow(element));
        }
    },


    selectRow: function(row) {
        var isselected = row.hasClassName(this.options.selectedClassName);
        if (!this.options.multiple)
            this.rowContainer.select("tr").invoke("removeClassName", this.options.selectedClassName);

        if (isselected) {
            row.removeClassName(this.options.selectedClassName);
            return false;
        } else {
            row.addClassName(this.options.selectedClassName);
            return true;
        }
    },


    update: function(row, isnew) {
        this.fire("click", { "tr": row, "isnew": isnew });

        var isfirst = this.selectedItems.keys().length == 0;

        var rowid = this.options.getKey(row);
        if (!this.options.multiple) {
            this.reset();
        }

        this.selectedItems[isnew ? "set" : "unset"](rowid, row);
        var keys = this.selectedItems.keys();

        this.fire(isnew ? "add" : "remove", { "tr": row });

        if (isfirst && keys.length == 1) {
            this.fire("first");
        } else if (keys.length == 0) {
            this.fire("empty");
        }
    },


    items: function() {
        return this.selectedItems.keys();
    },


    unload: function() {
        // TODO clear all data from cacahe
        // may respond to pia:unload function in future
    }
});

PIA.UI.List = Class.create({
    initialize: function(objid, tagName, selClassName, eventname) {
        this.obj = $(objid);
        this.tagName = tagName;
        this.selClassName = selClassName;
        this.eventname = eventname || "list:selected";
        if (this.obj)
            this.init();
    },

    init: function() {
        this.clickEvent = this.onClick.bind(this);
        this.obj.observe("click", this.clickEvent);
        this.bindData();
    },
    
    bindData: function(){
        this.list = this.obj.select(this.tagName);
        this.listLength = this.list.length;
    },

    onClick: function(ev) {
        ev.stop();
        var element = ev.findElement(this.tagName);
        if(element!=null && element!=document){
            this.list.invoke("removeClassName", this.selClassName);
            element.addClassName(this.selClassName);
            this.obj.fire(this.eventname, { el: element });
        }
    },

    move: function(name, direction) {
        var position = 0;
        var element = null;

        for (var i = 0, e = null; (e = this.list[i]) != null; i++) {
            if (e.getAttribute("name") == name) {
                position = i;
                element = e;
                break;
            }
        }

        if (element != null) {
            var newposition = position + direction;
            if (newposition < 0 || newposition >= this.listLength)
                return false;

            var rel = this.list[newposition];
            var tempEl = $(this.obj.removeChild(element));
            var opt = direction > 0 ? { "after": tempEl} : { "before": tempEl };
            rel.insert(opt);

            var t = this.list[newposition];
            this.list[newposition] = this.list[position];
            this.list[position] = t;

            return true;
        }
        return false;
    }
});

PIA.UI.Repeater = Class.create({
    initialize: function(object, template){
        this.container = $(object);
        this.template = $(template).innerHTML;
    },
    
    render: function(data) {        
        var html = [];
        var t = new Template(this.template);
        for(var i=0,l=data.length;i<l;i++){            
            html.push(t.evaluate(data[i]));
        }
        this.container.update(html.join(''));
    }    
});

PIA.UI.RowRepeater = Class.create({
	initialize: function(object, options) {
		this.table = $(object);
		if (!this.table) return;
		
		this.cache = {};
		this.options = Object.extend({
			template: "<tr><td>#{text}</td></tr>",	// template for rendering
			ajaxRequest: function(){},				// function for requesting data from server
			onData: null							// function must return { count:[number], rows:[array of data] }
		}, options || {});
		
		this.init();
	},
	
	init: function(){
		if(!this.options.onData){
			throw Error("You must specify onData function");
			return;
		}
		this.container = this.table.select("tbody")[0];
		this.template = new Template(this.options.template);
	},

	render: function(data) {
		this.container.update("");
		var data = this.options.onData(data);
		
		var html = "";
		for(var i=0, l=data.count; i<l; i++)
			html+= this.template.evaluate(data.rows[i]);
		this.container.update(html);
	}
});

/* Modules */
PIA.Modules.LightBox = Class.create({
	initialize:function(){
		this.shadow = null;
		this._box = null;
		this.escEvent = this.escObserver.bindAsEventListener(this);
	},
	
	prepareStage: function(){
		var pageSizeObj = document.viewport.getDimensions();
		this._shadow.setStyle({height:pageSizeObj.height+"px"});
		this._shadow.addClassName("senca");
		this._box.setStyle({ visibility:"visible", left:"-9999px", top:"0px", maxHeight:(pageSizeObj.height-100)+"px", zIndex:"200" });
		
		// we need delay for position to set
		setTimeout(function(){
			Position.prepare(); // current middle of viewport
			var boxDim = this._box.getDimensions();
			var top = (Position.getPageSize().window.height/2 + Position.deltaY - boxDim.height/2)+"px";
			var left = (Position.getPageSize().window.width/2 + Position.deltaX - boxDim.width/2)+"px";
			
			var off = {
//				top: (Position.getPageSize().window.height/2 + Position.deltaY)+"px",
//				left: (Position.getPageSize().window.width/2 + Position.deltaX)+"px",
				top:top,
				left:left
//				width:"1px",
//				height:"1px",
//				overflow:"hidden"
			};
			this._box.setStyle(off).show();
			
//			this._box.morph('top:'+top+'; left:'+left+'; width:'+boxDim.width+'px; height:'+boxDim.height+'px;', {
//				duration: .8,
//				transition: Effect.Transitions.spring,
//				afterFinish: function() { }
//			});
		}.bind(this), 100);
	},
	
	clearStage: function(){
		this._shadow.removeClassName("senca");
		this._box.setStyle({ left:"-9999px" }).hide();
	},
	
	open: function(obj){
		this._box = obj;
		this._shadow = $("senca");
		this.prepareStage();
		document.fire("lightbox:open");		
		document.observe("keydown", this.escEvent);
	},
	
	close: function(){
		Try.these(function(){
			document.fire("lightbox:close");
			this.clearStage();
			
			document.stopObserving("keydown", this.escEvent);
		}.bind(this));
	},
	
	escObserver: function(ev){
		if(ev.keyCode==Event.KEY_ESC){
			document.fire("lightbox:cancel");
			this.close(this._box);
		}
	}
});



PIA.Modules.TabbedControl = Class.create({
	initialize: function(o, tabsCssRole, contentCssRole, options) {
		this.obj = $(o);
		this.tabsCssRole = tabsCssRole;
		this.contentCssRole = contentCssRole;		
		this.options = Object.extend({
			defaultTab:null,
			onClickEvent:null
        }, options);
        this.selectedTab = this.options.defaultTab;
		
		if(!this.obj) throw Error("There is no parent in DOM");
		
		this.init();
		this.startObserveEvents();		
	},
	
	init: function(){
		this.tabs = {
			list: this.obj.select(this.tabsCssRole),
			
			show: function(tabName){
				for(var i=0,l=this.list.length; i<l; i++)
					if(tabName!=null && this.getTabName(this.list[i])==tabName)
						$(this.list[i].parentNode).addClassName("active");
					else $(this.list[i].parentNode).removeClassName("active");
			},
			
			getTabName: function(element){
				if(element.href.indexOf("#")==-1) throw Error("You must specify the tab in href. (ex: #tab1)");
				return element.href.replace(/(http:\/\/[^#]+)?#(.+)/g, '$2').split("_")[0];
			},
			get: function(tabName){
				for(var i=0,l=this.list.length; i<l; i++)
					if(tabName!=null && this.getTabName(this.list[i])==tabName)
						return this.list[i];
				return null;
			}
		}
		if(this.tabs.list.length==0) throw Error("There is no tabs");
		
		this.content = {
			list: this.obj.select(this.contentCssRole),
			
			show: function(tabName){
				for(var i=0,l=this.list.length; i<l; i++)
					if(tabName!=null && this.list[i].getAttribute("name")==tabName)
						this.list[i].show();
					else this.list[i].hide();
			},
			
			get: function(tabName){
				for(var i=0,l=this.list.length; i<l; i++)
					if(tabName!=null && this.list[i].getAttribute("name")==tabName)
						return this.list[i];
				return null;
			}
		}		
		if(this.content.list.length==0) throw Error("There is no content for tabs");
		
		this.setDefaultTab();
		
		if(this.options.onClickEvent)
			this.obj.observe("tab:onClick", this.options.onClickEvent);

        this.selectTab(this.selectedTab);
	},
	
	setDefaultTab: function(){
		if(this.options.defaultTab==null) 
			this.options.defaultTab = this.content.list[0].getAttribute("name");
	},
	
	startObserveEvents: function(){
		var parent = this.tabs.list[0].up("ul");
		parent.observe("click", this.onClick.bind(this));
	},
	
	onClick: function(ev){
		ev.stop();
		var el = ev.findElement("a");
		if(el!=null && el!=document)
		{
			this.selectTab(this.tabs.getTabName(el));
		}
	},
	
	selectTab: function(tabName){
		if(!tabName) tabName = this.options.defaultTab;
		this.tabs.show(tabName);
		this.content.show(tabName);
		this.selectedTab = tabName;
		
		var tab = this.tabs.get(tabName);
		if(tab)
			this.obj.fire("tab:onClick", {name:tabName,element:tab});
	},
	
	getTab: function(tabName){
		return this.content.get(tabName);
    },

    hide: function(tabName) {
        var t = this.tabs.get(tabName); if (t) t.hide();
        var c = this.content.get(tabName); if (c) c.hide();
    },

    show: function(tabName) {
        var t = this.tabs.get(tabName); if (t) t.show();
        var c = this.content.get(tabName); if (c) c.show();
    },
	
	Error: function(errorMsg){
		return "[TabbedControl] - " + errorMsg;
	}
});


PIA.Modules.RichControl = Class.create({
    initialize: function(cssRule, toolbarid, posturl, url){
        this.elements = $$(cssRule);
        this.toolbar = $(toolbarid);
        this.action = posturl;
        this.url = url;
        this.index = 0;
        if(this.elements.length>0)
            this.initControls();
    },
    
    initControls: function(){
        for(var i=0, l=this.elements.length; i<l; i++)
        {
            this.buildControl(this.elements[i]);
        }
    },
    
    buildControl: function(control){
        var wraper = control.wrap('div', { 'class': 'control-wrapper' });
        var cont = wraper.innerHTML;
        var name = "wrapper"+this.index++;
        wraper.setStyle({"position":"relative"});
//        wraper.setAttribute("name", name);
        wraper.insert({top:new Element("a",{name:name,visible:false})});
        wraper.t = this.toolbar.cloneNode(true);
        wraper.t.setStyle({"position":"absolute", "top":"0", "right":"0"});
        wraper.t.hide();
        wraper.t.observe("click", function(ev){
            var el = ev.findElement("a");
            if (el != null && el != document && el.readAttribute("action")!="") {
			this.down("input[name='_rcaction']").value=el.readAttribute("action");
			this.down("form").submit();
		}
        }.bind(wraper));
        wraper.insert(wraper.t);
        wraper.observe("mouseover", function(){ this.t.show() }.bind(wraper));
        wraper.observe("mouseout", function(){ this.t.hide() }.bind(wraper));
        wraper.insert(["<form method='post' action='"+this.action+"' target='_blank'>",
        "<input type='hidden' name='_rcurl' value='"+this.url+"#"+name+"' />",
        "<input type='hidden' name='_rcaction' value='' />",
        "<input type='hidden' name='_rccnt' value='"+cont.escapeHTML()+"' />",
        "</form>"].join(''));
	}   
});

PIA.Class.AddonCollection = Class.create((function(){
	return {
		initialize: function(){
			this._list = $H();
		},
		add: function(addOnName, addon){
			this._list.set(addOnName, addon);
		},
		get: function(addOnName){
			return this._list.get(addOnName);
		},
		invoke: function(method) {
			var args = $A(arguments).slice(1);
			var results = [];
			this._list.each(function(pair){
				results.push(({}[pair.key]=pair.value[method]!=null ? pair.value[method](args[0]) : null));
			});
			return results;
		},
		count: function(){
			return this._list.keys().length;
		}
	}
})());

PIA.Util = {
    oldBrowser: function(control){
        var c = $(control);
//        alert(/MSIE/.test(navigator.userAgent));
//        alert(navigator.userAgent.match(/MSIE (\d+(?:\.\d+)+(?:b\d*)?)/));
        
        if(c && true)
            c.show();
    },
    
    removeOptions: function(oSelect) {
        oSelect.oldOptions = [];
        oSelect.cleanWhitespace();

        while (oSelect.length > 0) {
            var item = oSelect.options[0].cloneNode(true);
            oSelect.remove(0);
            oSelect.oldOptions.push($(item));
        }
        return oSelect;
    },

    stopWatch: Class.create({
        initialize: function() {
            this.st = this.et = 0;
        },

        getTime: function() {
            var ms = this.et - this.st;
            var h = parseInt(ms / 3600000); ms -= h * 3600000;
            var m = parseInt(ms / 60000); ms -= m * 60000;
            var s = parseInt(ms / 1000); ms -= s * 1000;
            return h.toString() + ":" + m.toString() + ":" + s.toString() + "." + ms.toString();
        },

        start: function() {
            this.st = new Date().getTime();
        },

        stop: function() {
            this.et = new Date().getTime();
            return this.getTime();
        }
    }),

    datePickerToAjax: function(dateStr) {
        var date = DateFormat.parseFormat(dateStr, Control.DatePicker.Locale[Control.DatePicker.CurrentCulture].dateTimeFormat);
        return {
            "Year": date.getFullYear(),
            "Month": date.getMonth() + 1,
            "Day": date.getDate(),
            "Hour": date.getHours(),
            "Minute": date.getMinutes(),
            "Second": date.getSeconds(),
            "Millisecond": 0
        };
    }
};

PIA.UI.ContextMenu = Class.create((function() {
    var _control = null;
    var onclickEvent = function() { };
    var _int = null;

    var _initialize = function(obj, clickEv) {
        _control = $(obj);
        onclickEvent = clickEv;

        var _tempF = function() {
            var clone = _control.cloneNode(true);
            clone.hide();
            _control.remove();
            $(document.body).down("div").insert(clone);
            _control = clone;
            if (_control) init();
        } .delay();
    };

    var init = function() {
        _control.observe("click", function(ev) {
            ev.stop();
            var el = ev.findElement("a");
            onclickEvent(el);
        });
    };

    var onClick = function(elOff) {
        _control.show();
        _control.setStyle(elOff).setStyle({ zIndex: 100 });
        clearTimeout(_int);
        _int = setTimeout(close, 5000);
    };

    var close = function() {
        _control.hide();
    };


    return {
        initialize: _initialize,
        click: onClick
    }
} ()));


/// PIA.UI.Binder
PIA.UI.Binder = Class.create({
    initialize: function(control, cssrule)
    {
        this.control = $(control);
        this.cssrule = cssrule;
        if(this.control)
            this.initControls();
    },
    
    initControls: function(){
        this.control.select(this.cssrule).each(function(element){
            var name = element.getAttribute("name");
            if(name) this[name] = element;
        }.bind(this));
    }
});



PIA.UI.InputChangeTriger = Class.create({
    initialize: function(input, options){
        this.control = $(input);
        this.options = Object.extend({
            delay: 300
        }, options || {});
        this.trigerOn = false;
        
        if(this.control && this.control.tagName=="INPUT")
            this.initEvent();
    },
    
    initEvent: function(){
        this["onTriger"] = function(){};
    
        this.control.observe("keydown", function(){
            if(!this.trigerOn){
                this.trigerOn = true;
                setTimeout(function(){
                    this["onTriger"](this.control.value);
                    this.trigerOn = false;
                }.bind(this), this.options.delay);
            }
        }.bind(this));
    }
});


/// Use this class for event functionality of the single container with html elements
/// you can attach any event to any html element
/// class will return object with predefined events
/// event names will be created from name of the html element you seek
/// if you have tag "a" with name Move -> object will have function "onMove" you just need to define it
PIA.UI.ActionBar = Class.create({
    initialize: function(control, options)
    {
        this.control = $(control);
        this.options = Object.extend({
            cssrule: "a",
            events: ["Click"],
            disablePostfix: "_d",
            valid: function(){ return true; }
        }, options || {});
        if(this.control)
            this.initEvents();
    },
    
    disable: function(elements) {
        var ps = this.options.disablePostfix;
        this.control.select(this.options.cssrule).each(function(el){
            var name = el.getAttribute("name");
            if(elements==null) {
                el.removeClassName(name);
                el.addClassName(name+ps);
            }else if(elements.include(name)){
                el.removeClassName(name);
                el.addClassName(name+ps);
            }
        });
    },
    
    enable: function(elements) {
        var ps = this.options.disablePostfix;
        this.control.select(this.options.cssrule).each(function(el){
            var name = el.getAttribute("name");
            if(elements==null) {
                el.removeClassName(name+ps);
                el.addClassName(name);
            }else if(elements.include(name)){
                el.removeClassName(name+ps);
                el.addClassName(name);
            }
        });
    },
    
    initEvents: function(){
        for(var i=0,l=this.options.events.length; i<l; i++) {
            var eve = this.options.events[i];
            this.control.observe(eve.toLowerCase(), this.onEvent.bind({ eve:eve, obj: this }));
        }
    },
    
    onEvent: function(ev){
        ev.stop();
        var el = ev.findElement(this.obj.options.cssrule);
        if(el!=null && el!=document){
            var name = el.getAttribute("name");
            if(name && !el.hasClassName(name+this.obj.options.disablePostfix)) {
                if(typeof this.obj["on"+name+this.eve]=="function")
                    this.obj["on"+name+this.eve](el);
                else alert("You must define function: "+"on"+name+this.eve);
            }
        }
    }
});


/// Build JSON structure for jsTree control
/// input if html container with "a" tags.
/// from "a" tag we need
///     - name      (used for id and for name of the icon)
///     - title     (used for label of the item in context menu)
///     - action    (used for function when context item is clickes)
///     - isvisible (used for function to determine visibiliti of the context item)
PIA.UI.TreeContextMenu = Class.create({
    initialize: function(control) {
        this.control = $(control);        
        this.data = [];
        if(this.control)
            this.buildData();
    },
    
    getFunction: function(name, fName) {
        var f = eval(name);
        return typeof f==="function" ?
            f : 
            (fName=="visible" ? 
                function (NODE, TREE_OBJ) { if(NODE.length != 1) return false; return true; } : // visible
                function (NODE, TREE_OBJ) {  }  // action
            );
    },
    
    buildData: function(){
        var tags = this.control.select("a");
        for(var i=0,l=tags.length; i<l; i++)
        {
            var f1 = tags[i].getAttribute("action");
            var f2 = tags[i].getAttribute("isvisible");
            
            var name = tags[i].getAttribute("name");
            this.data.push({
                id		: name, 
	            label	: tags[i].title ? tags[i].title : name, 
	            icon	: name + ".png", 
	            "visible"	: this.getFunction(f2, "visible"),
	            "action"	: this.getFunction(f1, "action")
            });
        }
    }
});

//PM.FormWatcher = Class.create();
//PM.FormWatcher.prototype = {	
//	inputTags : [
//		"input[type=text]:not(input[class~=dontWatch]):enabled",
//		"input[type=password]:not(input[class~=dontWatch]):enabled",
//		"input[type=radio]:not(input[class~=dontWatch]):enabled",
//		"input[type=checkbox]:not(input[class~=dontWatch]):enabled",
//		"textarea:not(textarea[class~=dontWatch]):enabled",
//		"select:not(select[class~=dontWatch]):enabled"
//	],	
//	prompt : "Prišlo je do spremembe podatkov. Ali želite shraniti podatke ?",
//	
//	initialize: function(form, start){
//		this.form = $(form);
//		this.inputs=[];
//		this._onChangeObservers=[];
//		this._onUnloadObservers=[];
//		this._onSaveObservers=[];
//		this._customFields=[];
//		
//		this.getInputs(arguments[2]);
//		if(start) this.startObserving(arguments[2]);
//		
//		//register internal events
//		//this.addOnChange(this.onChange.bind(this));
//		
//		this.eventWindowObserver = this.windowObserver.bind(this);
//		Event.observe(window, "unload", this.eventWindowObserver);
//	},
//	
//	// kreira string z vrednostimi
//	updateValue: function(){
//		var i=0;
//		var val="";
//		var value="";
//		this.inputs.each(
//			function(el){
//			    value = ('function'==typeof el) ? el() : el.getValue();
//				val+= (i++==0?"":";") + value;
//			}.bind(this)
//		);
////		console.log("Vrednosti:\n %s",val);
//		return val;
//	},
//	
//	getInputs: function(){
//	    this.inputs.clear();
//		// poišče vse inpute znotraj objekta
//		var group = arguments[0];
//		this.form.getElementsBySelector(this.inputTags).each(
//			function(el){
//				var addEl = el.getStyle('display')!='none';
//				if(group && 'string'==typeof(group))
//					addEl&= el.hasClassName(group);
//				if(addEl) this.inputs.push(el);
//			}.bind(this)
//		);
//		
//		for(var i=0; i<this._customFields.length; i++)
//		    this.inputs.push(this._customFields[i]);
//	},
//	
//	setSubmitButton : function(){
//		this.submitBtns = this.form.getElementsBySelector("button[class~=submit"+(arguments[0]?" "+arguments[0] : "") +"]","input[class~=submit"+(arguments[0]?" "+arguments[0] : "") +"]");		
//		var eventObserve = this.startObserving.bind(this);
//		this.submitBtns.each(function(el){
//			el.disabled=true;
//			el.addClassName("disabled");
//			el.observe("click", eventObserve);
//		});
//	},
//	
//	setWarningButton : function(){
//		this.warningBtns = this.form.getElementsBySelector("button[class~=warning"+(arguments[0]?" "+arguments[0] : "") +"]","input[class~=warning"+(arguments[0]?" "+arguments[0] : "") +"]");
//		var eventSave = this.onSave.bind(this);
//		this.warningBtns.each(function(el){
//			el.observe("click", eventSave);
//		});
//	},
//	
//	startObserving: function(){		
//		this.stopObserving();
//		this.setSubmitButton(arguments[0]);
//		this.setWarningButton(arguments[0]);
//		this.isChanged=false;
//		
//		this.observer = new PM.FormWatcher.Observer(this, 0.5, function(form, value){
//			form.stopObserving();
//			// call change observers
//			form._onChangeObservers.call();
//		}.bind(this));
//	},
//	
//	stopObserving: function(){
//		if(this.observer){
//			this.observer.stop();
//			this.onChange();
//		}
//	},
//	
//	clearWatcher: function(){
//		if(this.observer){
//			this.observer.stop();
//		}
//		// clear submit button events
//		// clear warning button events
//	},
//	
//	invokeChange: function(){
//		this.stopObserving();
//		this._onChangeObservers.call();
//	},
//	
//	onChange: function(){
//		this.isChanged=true;
//		this.submitBtns.each(function(el){
//			el.disabled=false;
//			el.removeClassName("disabled");
//		});
//	},
//	
//	onSave: function(){		
//		if(this.isChanged && this._onSaveObservers.length>0){
//			if(confirm(this.prompt)){
//				this._onSaveObservers.call();
//				this.startObserving();
//			}
//		}
//	},
//	
//	windowObserver: function(){		
//		this._onUnloadObservers.call();
//		this.onSave();
//	},
//	
//	log: function(){
//		alert(this.updateValue());
//		var log="Inputs count: "+this.inputs.length+"\n";
//		for(var i=0; i<this.inputs.length; i++)
//		    if('function'==typeof(this.inputs[i]))
//		        log+="Function:\n" + this.inputs[i] +"\n";
//		    else
//			    log+="Id: "+this.inputs[i].id+"\t\tNode: "+this.inputs[i].nodeName+"\t\tType: "+this.inputs[i].getAttribute("type")+"\n";
//		alert(log);
//		
//		log="Submits count: "+this.submitBtns.length+"\n";
//		for(var i=0; i<this.submitBtns.length; i++)
//			log+="Id: "+this.submitBtns[i].id+"\t\tNode: "+this.submitBtns[i].nodeName+"\t\tValue: "+this.submitBtns[i].innerHTML+"\n";
//		alert(log);
//		
//		log="Warnings count: "+this.warningBtns.length+"\n";
//		for(var i=0; i<this.warningBtns.length; i++)
//			log+="Id: "+this.warningBtns[i].id+"\t\tNode: "+this.warningBtns[i].nodeName+"\t\tValue: "+this.warningBtns[i].innerHTML+"\n";
//		alert(log);
//	},
//	
//	// EVENTS
//	addOnChange : function(f){
//		if(f && 'function' == typeof f && this._onChangeObservers.indexOf(f)==-1)
//			this._onChangeObservers.push(f);
//	},
//	
//	removeOnChange : function(f){
//		if(f && 'function' == typeof f)
//			this._onChangeObservers.remove(f);
//	},
//	
//	addOnUnload : function(f){
//		if(f && 'function' == typeof f && this._onUnloadObservers.indexOf(f)==-1)
//			this._onUnloadObservers.push(f);
//	},
//	
//	removeOnUnload : function(f){
//		if(f && 'function' == typeof f)
//			this._onUnloadObservers.remove(f);
//	},
//	
//	addOnSave : function(f){	    
//		if(f && 'function' == typeof f && this._onSaveObservers.indexOf(f)==-1)
//			this._onSaveObservers.push(f);
//	},
//	
//	removeOnSave : function(f){
//		if(f && 'function' == typeof f)
//			this._onSaveObservers.remove(f);
//	},
//	
//	addCustomField : function(f){
//	    if(f && 'function' == typeof f){
//	        this._customFields.push(f);
//	        this.getInputs();
//	    }
//	}
//};

//Object.extend(PM.FormWatcher.prototype, {
//	getValue: function(){		
//		return this.updateValue();
//	}
//});

//PM.FormWatcher.Observer = Class.create();
//PM.FormWatcher.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
//	getValue: function() {
//		return this.element.getValue(this.element);
//	}
//});

///* PROTOTYPE UPDATE */
//Object.extend(Abstract.TimedObserver.prototype, {
//	registerCallback: function() {
//		this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
//	},

//	stop: function() {
//		if (!this.timer) return;
//		clearInterval(this.timer);
//		this.timer = null;
//	}
//});

Position.getPageSize = function() {
  var xScroll, yScroll;

  if (window.scrollMaxX) {  
    xScroll = window.innerWidth  + window.scrollMaxX;
    yScroll = window.innerHeight + window.scrollMaxY;
  } else {
    xScroll = document.body.scrollWidth;
    yScroll = document.body.scrollHeight;
  } 
  
  var windowWidth, windowHeight;
  if (self.innerHeight) { // all except Explorer
    windowWidth = self.innerWidth;
    windowHeight = self.innerHeight;
  } else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
    windowWidth = document.documentElement.clientWidth;
    windowHeight = document.documentElement.clientHeight;
  } else if (document.body) { // other Explorers
    windowWidth = document.body.clientWidth;
    windowHeight = document.body.clientHeight;
  }
  // for small pages with total height less then height of the viewport
  pageHeight = Math.max(windowHeight, yScroll);

  // for small pages with total width less then width of the viewport
  pageWidth = Math.max(windowWidth, xScroll);

  return { page: { width: pageWidth, height: pageHeight }, window: { width: windowWidth, height: windowHeight } };
}