dojo.provide("UI.Base");


(function() {
	var normalizeEventType = function(type) {
		return type.toLowerCase();
	};
	
	var idIndex = 1;
	
	dojo.declare("UI.Base", null, {
		constructor: function() {
			this._eventListeners = {};
			
			// Remember kids, caps means constant
			this.EVT_BEFORE_OPEN  = 'beforeopen',
			this.EVT_OPEN         = 'open',
			this.EVT_LOAD         = 'load';
			this.EVT_BEFORE_CLOSE = 'beforeclose',
			this.EVT_CLOSE        = 'close';
			this.EVT_CHANGE       = 'change';
			this.EVT_SUCCESS      = 'success';
			this.EVT_ERROR        = 'error';
			this.EVT_SELECT       = 'select';
		},
		
		nodeAttribute: function(attribute) {
			return UI.Base.nodeAttribute(attribute, this.declaredClass);
		},
		
		getNodeAttribute: function(node, attribute) {
			return UI.Base.getNodeAttribute(node, attribute, this.declaredClass);
		},
		
		setNodeAttribute: function(node, attribute, value) {
			return UI.Base.setNodeAttribute(node, attribute, value, this.declaredClass);
		},
		
		getStyle: function(element, style) {
			return UI.Base.getStyle(element, style);
		},
		
		addEventListener: function(type, callback, synchronous) {
			type = normalizeEventType(type);
		
			if ( !this._eventListeners[type] ) {
				this._eventListeners[type] = [];
			}
			
			this._eventListeners[type].push({
				callback:    callback,
				synchronous: synchronous
			});
			
			return this;
		},
		
		removeEventListener: function(type, callback, synchronous) {
			type = normalizeEventType(type);
		
			if ( !this._eventListeners[type] ) {
				return 0;
			}
			
			var removeCount = 0;
			for ( var i=0, events=this._eventListeners[type], l=events.length; i<l; ++i ) {
				if (
					events[i].synchronous === synchronous && 
					events[i].callback    === callback
				) {
					events[i].splice(i, 1);
					--i;
					--l;
					++removeCount;
				}
			}
			
			return removeCount;
		},
		
		triggerEvent: function(type/*, arg1, arg2, arg3, ..., argN*/) {
			var args = Array.prototype.slice.call(arguments);
			
			type = normalizeEventType(args.shift());
			
			if ( !this._eventListeners[type] ) {
				return;
			}
			
			for ( var i=0, events=this._eventListeners[type], l=events.length; i<l; ++i ) {
				if ( events[i].synchronous ) {
					if ( events[i].callback.apply(this, args) === false ) {
						return false;
					}
				} else {
					setTimeout((function(callback) {
						return function() { callback.apply(this, args); };
					})(events[i].callback), 1);
				}
			}
			
			return true;
		},
		
		generateId: function() {
			return this.declaredClass.replace(/\./g, "_") + (idIndex++);
		}
	});
})();

UI.Base.nodeAttribute = function(attribute, declaredClass) {
	return "__" + declaredClass + "." + attribute;
};

UI.Base.getNodeAttribute = function(node, attribute, declaredClass) {
	return node[ UI.Base.nodeAttribute(attribute) ];
};

UI.Base.setNodeAttribute = function(node, attribute, value, declaredClass) {
	node[ UI.Base.nodeAttribute(attribute) ] = value;
	return node;
};

/**
 * Get's the computed style of a node
 * @param string|node element A CSS selector or a DOM node.
 * @param string styleProp The CSS property to get (e.g.: "z-index").
 * @return string
 * @see http://www.quirksmode.org/dom/getstyles.html
 */
UI.Base.getStyle = function(element, style) {
	var node  = typeof element == "string" ? dojo.query(element)[0] : element,
		value;

	if ( node.currentStyle ) {
		// Convert -ms-blah-blah to blahBlah per http://msdn.microsoft.com/en-us/library/ms535231%28VS.85%29.aspx
		style = style.replace(/^-ms-/i, "").replace(/-./g, function(match) {
			return match.substr(1, 1).toUpperCase()
		});
		value = node.currentStyle[style];
	} else if ( window.getComputedStyle ) {
		value = document.defaultView.getComputedStyle(node, null).getPropertyValue(style);
	}
	
	return value;
};
