function RegisterNamespace (name){
	eval(name + " = new Object();");
}
function RegisterEnum(name){
	eval(name + " = new " + name + "();");
}
function RegisterGlobal(name){
	eval(name + " = new " + name + "();");	
}

RegisterNamespace("pJSfw2009");
pJSfw2009.DropDownPanel = function (target, opener, fixedTarget){
	this._target = target || null;
	this._opener = opener || null;
	this._tdimensions = null;
	this._olocation = null;
	this._toffset = {top : 0, left : 0}
	this._shown = false;
	this._calculatedPosition = false;
	this._alignment = pJSfw2009.Alignment.RIGHT;
	this._animate = false;
	this._duration = pJSfw2009.AnimationSpeed.FAST;
	this._autohide = true;
	this._enabled = true;
	this._fixedTarget = fixedTarget;
	this._refixTarget = false;
	this._showTriggerEvent = pJSfw2009.Events.CLICK;
	this._hideTriggerEvent = pJSfw2009.Events.BLUR;
		
	this._init();
	
}
pJSfw2009.DropDownPanel.prototype = {
	_init : function (){
		if(this._target){
			this._tdimensions = this._target.getDimensions();
			this._odimensions = {top : 0, left : 0}
			this._target.hide();
			if(this._fixedTarget){
				this._target.setStyle({
					position : "absolute"
				});	
				this._target.innerHTML = "<div style='display:block'></div>" + this._target.innerHTML;
			}
			if(this._opener){
				this._addOpenerHandlers();
				this._olocation = this._opener.positionedOffset();
				this._odimensions = this._opener.getDimensions();
			}
		}
	},
	getEvents : function () {
		if (!this._events) {
			this._events = new Sys.EventHandlerList();
		}
		return this._events;
	},	
	_openerOnClick : function (event){
		if(this.isEnabled()){
			if(this.isShown()){
				this.hidePanel();
			}else{
				this.showPanel();
			}
		}
		Event.stop(event);
	},
	_openerOnBlur : function (event){
		if(this.isEnabled()){
			if(this.isShown()){
				this.hidePanel();
			}
		}
	},		
	_bodyOnClick : function(event){
		if(this.isEnabled()){
			if(this.isShown()){
				this.hidePanel();
			}
		}
	},
	_calculatePosition: function(){
		if(this._olocation){
			if(this._alignment == pJSfw2009.Alignment.RIGHT){
				var x_pos = this._olocation.left + this._toffset.left;
			}else{
				var x_pos = this._olocation.left + this._toffset.left - (this._tdimensions.width - this._odimensions.width);
			}
			this._target.setStyle({
				top : (this._olocation.top + this._toffset.top + this._odimensions.height ) + "px",
				left: x_pos + "px"
			});			
		}
	},
	showPanel : function (){
		this._target.fire(pJSfw2009.Events.SHOWING, "");		
		if(this._calculatedPosition){
			this._calculatePosition();
		}
		if(this._animate){
			this._target.slideDown({delay: 0, duration: this._duration, beforeStart : Function.createDelegate(this, function(){this._enabled = false;}) , afterFinish : Function.createDelegate(this, function(){this._target.fire(pJSfw2009.Events.SHOWN, ""); this._enabled = true;})});
		}else{
			this._target.show();
			this._target.fire(pJSfw2009.Events.SHOWN, "");
		}
		this._shown = true;
	},
	hidePanel : function (){
		this._target.fire(pJSfw2009.Events.HIDING, "");
		if(this._animate){
			this._target.slideUp({delay: 0, duration: this._duration, beforeStart : Function.createDelegate(this, function(){this._enabled = false;}) , afterFinish : Function.createDelegate(this, function(){this._target.fire(pJSfw2009.Events.HIDDEN, null);this._enabled = true})});
		}else{
			this._target.hide();
			this._enabled = true;
			this._target.fire(pJSfw2009.Events.HIDDEN, null);
		}
		this._shown = false;		
	},	
	_addOpenerHandlers : function (){
		this._opener.observe(this._showTriggerEvent, Function.createDelegate(this, this._openerOnClick));
		//this._opener.observe(this._hideTriggerEvent, Function.createDelegate(this, this._openerOnBlur));
		Event.observe(document.body, pJSfw2009.Events.CLICK, Function.createDelegate(this, this._bodyOnClick));
	},
	_removeOpenerHandlers : function (){
		this._opener.stopObserving(this._showTriggerEvent,this._targetOnClick);
		//this._opener.stopObserving(this._hideTriggerEvent, this._targetOnBlur);
		Event.stopObserving(document.body, pJSfw2009.Events.CLICK, Function.createDelegate(this, this._bodyOnClick));
	},		
		
	isShown	: function(){
		return this._shown;
	},
		
	isEnabled	: function(){
		return this._enabled;
	},
		
	setShowTriggerEvent : function (tevent){
		this._showTriggerEvent = tevent;
	},
	getShowTriggerEvent : function (){
		return this._showTriggerEvent;
	},
		
	setCalculatedPosition : function (value, alignment){
		this._calculatedPosition = value;
		if(alignment)
			this.setAlignment(alignment);
	},
	getCalculatedPosition : function (){
		return this._calculatedPosition;
	},
		
	setFixedTarget : function (value){
		this._fixedTarget = value;
	},
	getFixedTarget : function (){
		return this._fixedTarget;
	},
		
	setRefixedTarget : function (value){
		this._refixedTarget = value;
	},
	getRefixedTarget : function (){
		return this._refixedTarget;
	},
		
	setAlignment : function (value){
		this._alignment = value;
	},
	getAlignment : function (){
		return this._alignment;
	},
		
	setAnimate : function (value, duration){
		this._animate = value;
		if(duration)
			this._duration = duration;
	},
	getAnimate : function (){
		return this._animate;
	},
		
	setAutoHide : function (value){
		Event.stopObserving(document.body, pJSfw2009.Events.CLICK, this._bodyOnClick);
		if(value)
			Event.observe(document.body, pJSfw2009.Events.CLICK, Function.createDelegate(this, this._bodyOnClick));		
		this._autohide = value;
	},
	getAutoHide : function (){
		return this._autohide;
	},
	addOnShowing : function (handler){
		this._target.observe(pJSfw2009.Events.SHOWING, handler);		
	},
	removeOnShowing : function (handler){
		this._target.stopObserving(pJSfw2009.Events.SHOWING, handler);
	},
	addOnShown : function (handler){
		this._target.observe(pJSfw2009.Events.SHOWN, handler);		
	},
	removeOnShown : function (handler){
		this._target.stopObserving(pJSfw2009.Events.SHOWN, handler);
	},
	addOnHiding : function (handler){
		this._target.observe(pJSfw2009.Events.HIDING, handler);		
	},
	removeOnHiding : function (handler){
		this._target.stopObserving(pJSfw2009.Events.HIDING, handler);
	},
	addOnHidden : function (handler){
		this._target.observe(pJSfw2009.Events.HIDDEN, handler);		
	},
	removeOnHidden : function (handler){
		this._target.stopObserving(pJSfw2009.Events.HIDDEN, handler);
	}
	
}

pJSfw2009.Events = function (){}
pJSfw2009.Events.prototype = {
	CLICK : "click",
	OVER   : "mouseover",
	OUT     : "mouseout",
	FOCUS  : "focus",
	BLUR    : "blur",
	SHOWING: "dropdownevents:showing",
	SHOWN: "dropdownevents:shown",
	HIDING: "dropdownevents:hiding",
	HIDDEN: "dropdownevents:hidden"
}
RegisterGlobal("pJSfw2009.Events");

pJSfw2009.Alignment = function (){}
pJSfw2009.Alignment.prototype = {
	RIGHT : "right",
	LEFT   : "left",
	TOP     : "top",
	BOTTOM  : "bottom"
}
RegisterGlobal("pJSfw2009.Alignment");

pJSfw2009.AnimationSpeed = function (){}
pJSfw2009.AnimationSpeed.prototype = {
	SLOW : 2,
	NORMAL   : 1,
	FAST     : 0.2
}
RegisterGlobal("pJSfw2009.AnimationSpeed");

//Function Extension
Function.__typeName = 'Function';
Function.__class = true;
Function.createCallback = function Function$createCallback(method, context) {
    /// <summary locid="M:J#Function.createCallback" />
    /// <param name="method" type="Function"></param>
    /// <param name="context" mayBeNull="true"></param>
    /// <returns type="Function"></returns>
    var e = Function._validateParams(arguments, [
        {name: "method", type: Function},
        {name: "context", mayBeNull: true}
    ]);
    if (e) throw e;
    return function() {
        var l = arguments.length;
        if (l > 0) {
            var args = [];
            for (var i = 0; i < l; i++) {
                args[i] = arguments[i];
            }
            args[l] = context;
            return method.apply(this, args);
        }
        return method.call(this, context);
    }
}
Function.createDelegate = function Function$createDelegate(instance, method) {
    /// <summary locid="M:J#Function.createDelegate" />
    /// <param name="instance" mayBeNull="true"></param>
    /// <param name="method" type="Function"></param>
    /// <returns type="Function"></returns>
    var e = Function._validateParams(arguments, [
        {name: "instance", mayBeNull: true},
        {name: "method", type: Function}
    ]);
    if (e) throw e;
    return function() {
        return method.apply(instance, arguments);
    }
}
Function.emptyFunction = Function.emptyMethod = function Function$emptyMethod() {
    /// <summary locid="M:J#Function.emptyMethod" />
    if (arguments.length !== 0) throw Error.parameterCount();
}
Function._validateParams = function Function$_validateParams(params, expectedParams) {
    var e;
    e = Function._validateParameterCount(params, expectedParams);
    if (e) {
        e.popStackFrame();
        return e;
    }
    for (var i=0; i < params.length; i++) {
        var expectedParam = expectedParams[Math.min(i, expectedParams.length - 1)];
        var paramName = expectedParam.name;
        if (expectedParam.parameterArray) {
            paramName += "[" + (i - expectedParams.length + 1) + "]";
        }
        e = Function._validateParameter(params[i], expectedParam, paramName);
        if (e) {
            e.popStackFrame();
            return e;
        }
    }
    return null;
}
Function._validateParameterCount = function Function$_validateParameterCount(params, expectedParams) {
    var maxParams = expectedParams.length;
    var minParams = 0;
    for (var i=0; i < expectedParams.length; i++) {
        if (expectedParams[i].parameterArray) {
            maxParams = Number.MAX_VALUE;
        }
        else if (!expectedParams[i].optional) {
            minParams++;
        }
    }
    if (params.length < minParams || params.length > maxParams) {
        var e = Error.parameterCount();
        e.popStackFrame();
        return e;
    }
    return null;
}
Function._validateParameter = function Function$_validateParameter(param, expectedParam, paramName) {
    var e;
    var expectedType = expectedParam.type;
    var expectedInteger = !!expectedParam.integer;
    var expectedDomElement = !!expectedParam.domElement;
    var mayBeNull = !!expectedParam.mayBeNull;
    e = Function._validateParameterType(param, expectedType, expectedInteger, expectedDomElement, mayBeNull, paramName);
    if (e) {
        e.popStackFrame();
        return e;
    }
    var expectedElementType = expectedParam.elementType;
    var elementMayBeNull = !!expectedParam.elementMayBeNull;
    if (expectedType === Array && typeof(param) !== "undefined" && param !== null &&
        (expectedElementType || !elementMayBeNull)) {
        var expectedElementInteger = !!expectedParam.elementInteger;
        var expectedElementDomElement = !!expectedParam.elementDomElement;
        for (var i=0; i < param.length; i++) {
            var elem = param[i];
            e = Function._validateParameterType(elem, expectedElementType,
                expectedElementInteger, expectedElementDomElement, elementMayBeNull,
                paramName + "[" + i + "]");
            if (e) {
                e.popStackFrame();
                return e;
            }
        }
    }
    return null;
}
Function._validateParameterType = function Function$_validateParameterType(param, expectedType, expectedInteger, expectedDomElement, mayBeNull, paramName) {
    var e;
    if (typeof(param) === "undefined") {
        if (mayBeNull) {
            return null;
        }
        else {
            e = Error.argumentUndefined(paramName);
            e.popStackFrame();
            return e;
        }
    }
    if (param === null) {
        if (mayBeNull) {
            return null;
        }
        else {
            e = Error.argumentNull(paramName);
            e.popStackFrame();
            return e;
        }
    }
    if (expectedType && expectedType.__enum) {
        if (typeof(param) !== 'number') {
            e = Error.argumentType(paramName, Object.getType(param), expectedType);
            e.popStackFrame();
            return e;
        }
        if ((param % 1) === 0) {
            var values = expectedType.prototype;
            if (!expectedType.__flags || (param === 0)) {
                for (var i in values) {
                    if (values[i] === param) return null;
                }
            }
            else {
                var v = param;
                for (var i in values) {
                    var vali = values[i];
                    if (vali === 0) continue;
                    if ((vali & param) === vali) {
                        v -= vali;
                    }
                    if (v === 0) return null;
                }
            }
        }
        e = Error.argumentOutOfRange(paramName, param, String.format(Sys.Res.enumInvalidValue, param, expectedType.getName()));
        e.popStackFrame();
        return e;
    }
    if (expectedDomElement) {
        var val;
        if (typeof(param.nodeType) !== 'number') {
            var doc = param.ownerDocument || param.document || param;
            if (doc != param) {
                var w = doc.defaultView || doc.parentWindow;
                val = (w != param) && !(w.document && param.document && (w.document === param.document));
            }
            else {
                val = (typeof(doc.body) === 'undefined');
            }
        }
        else {
            val = (param.nodeType === 3);
        }
        if (val) {
            e = Error.argument(paramName, Sys.Res.argumentDomElement);
            e.popStackFrame();
            return e;
        }
    }
    /*if (expectedType && !expectedType.isInstanceOfType(param)) {
        e = Error.argumentType(paramName, Object.getType(param), expectedType);
        e.popStackFrame();
        return e;
    }*/
    if (expectedType === Number && expectedInteger) {
        if ((param % 1) !== 0) {
            e = Error.argumentOutOfRange(paramName, param, Sys.Res.argumentInteger);
            e.popStackFrame();
            return e;
        }
    }
    return null;
}

