/*
 * Aurora - v0.1
 * Copyright (c) 2009, Ryan Morr (ryanmorr.com)
 * Licensed under the MIT license.
 */

(function(){this.Aurora={types:{},classes:{},register:function(name,klass){Aurora.classes[name]=klass;Aurora.define(name,function(o){return Aurora.isClassInstance(o,klass)},klass)},define:function(name,fn,obj){var type=Aurora.namespace(name,obj);type._name=name;type._isValid=fn;Aurora.types[name]=type},namespace:function(ns,obj){obj=obj||{};var parts=ns.split(".");var root=window[parts[0]]=window[parts[0]]||obj;if(parts.length>1){for(var i=1;i<parts.length;i++){root[parts[i]]=root[parts[i]]||((i==(parts.length-1))?obj:{});root=root[parts[i]]}}return root},mixin:function(obj,properties,override){for(var prop in properties){if(override||Aurora.isUndefined(obj[prop])){obj[prop]=properties[prop]}}return obj},extend:function(subclass,superclass,overrides){var fn=function(){};fn.prototype=superclass.prototype;subclass.prototype=new fn();subclass.prototype.constructor=subclass;subclass.superclass=superclass.prototype;Aurora.mixin(subclass.prototype,overrides,true)},declare:function(className,superclass,properties){var klass=function(){this._init.apply(this,arguments)};if(Aurora.isObject(superclass)){properties=superclass;properties._props={};properties.invariant=properties.invariant||{}}else{properties._props={};properties.invariant=properties.invariant||{};Aurora.mixin(properties._props,superclass.prototype._props);Aurora.mixin(properties.invariant,superclass.prototype.invariant);Aurora.extend(klass,superclass,properties)}for(var prop in properties){if(prop!='constructor'&&Aurora.isFunction(properties[prop])&&!Aurora.isType(properties[prop])){properties[prop]=Aurora.intercept(properties[prop],prop)}else if(prop!='invariant'){if(Aurora.isType(properties[prop])){properties._props[prop]=properties[prop]}}}Aurora.mixin(klass.prototype,properties,true);klass.prototype._className=className;klass.prototype._init=Aurora.intercept(properties.constructor||function(){},'constructor');Aurora.register(className,klass)},intercept:function(method,name){return function(){if(!this._intercepted){var instance=this;instance._intercepted=true;var result=method.apply(this,arguments);for(var prop in instance){if(!Aurora.isFunction(instance[prop])){var value=instance[prop];var type=instance._props[prop];if(type){var typeEx=Aurora.typeCheck(value,type,prop,instance,name);if(!typeEx){var invariantEx=Aurora.invariantCheck(prop,instance,name);if(invariantEx){throw invariantEx;}}else{throw typeEx;}}}}instance._intercepted=false;return result}else{return method.apply(this,arguments)}}},typeCheck:function(value,type,prop,instance,method){if(Aurora.isArray(type)){if(Aurora.isType(type[0])){if(!Aurora.isValidArray(value,type[0])){return Aurora.Exception.array(instance._className,method,prop,type[0]._name)}return false}else{if(!Aurora.isArray(value)){return Aurora.Exception.type(instance._className,method,prop,'Array')}return false}}else{if(!type._isValid(value)){return Aurora.Exception.type(instance._className,method,prop,type._name)}return false}},invariantCheck:function(prop,instance,method){var invariant=instance.invariant[prop];if(invariant&&!invariant.call(instance)){return Aurora.Exception.invariant(instance._className,method,prop)}return false},isElement:function(o){return(o.htmlElement||(o.nodeName&&o.nodeType===1))?true:false},isEvent:function(o){return(window.Event&&o instanceof Event)||(Aurora.isObject(o)&&Aurora.isUndefined(o.constructor)&&(window.event&&o.clientX&&o.clientX===window.event.clientX))},isHash:function(o){return Aurora.isObject(o)&&o.constructor===Object&&!Aurora.isEvent(o)&&!Aurora.isFunction(o)},isArray:function(o){return Object.prototype.toString.call(o)==="[object Array]"},isArrayLike:function(o){return(Aurora.isNumber(o.length)&&!Aurora.isFunction(o)&&!Aurora.isString(o))||Aurora.isArray(o)||Aurora.isNodeList(o)},isBoolean:function(o){return typeof o==='boolean'},isFunction:function(o){return Object.prototype.toString.call(o)==="[object Function]"},isNull:function(o){return o===null},isUndefined:function(o){return typeof o==='undefined'},isVoid:function(o){return Aurora.isNull(o)||Aurora.isUndefined(o)},isNumber:function(o){return typeof o==='number'&&isFinite(o)},isDecimal:function(o){return(/^-?(\d+|(\d*[.,]\d+))$/).test(String(o))&&Aurora.isNumber(o)},isInteger:function(o){return(/^-?\d+$/).test(String(o))&&Aurora.isNumber(o)},isObject:function(o){return typeof o==='object'},isString:function(o){return typeof o==='string'},isDate:function(o){return o instanceof Date},isRegExp:function(o){return Object.prototype.toString.call(o)==='[object RegExp]'},isXML:function(o){return Aurora.isXMLDocument(o)||Aurora.isXMLNode(o)},isXMLDocument:function(o){return!!(o.documentElement&&!o.body)},isXMLNode:function(o){return o.tagName&&o.ownerDocument&&!o.ownerDocument.body?true:false},isDocument:function(o){return Object.prototype.toString.call(o)==='[object HTMLDocument]'||o.nodeType===9||Aurora.isXMLDocument(o)},isNative:function(o){return(/\{\s*\[native code\]\s*\}/).test(o.toString())},isNode:function(o){return(o.nodeName&&o.nodeType&&(/1|2|3|4|5|6|7|8|9|10|11|12/).test(o.nodeType))||Aurora.isXML(o)},isNodeList:function(o){var type=Object.prototype.toString.call(o);if(type==="[object NodeList]"||type==="[object HTMLCollection]"){return true}else if(Aurora.isArrayLike(o)){for(var i=0;i<o.length;i++){if(!Aurora.isNode(o[i])){return false}}return true}else{return false}},isWindow:function(o){var type=Object.prototype.toString.call(o);if(type==="[object Window]"||type==="[object DOMWindow]"||type==="[object global]"){return true}else if(Aurora.isObject(o)&&!!o.Array){return true}else{return false}},isClass:function(o){return Aurora.isString(o)?!!Aurora.classes[o]:(Aurora.isFunction(o)&&!!Aurora.classes[o._name])},isClassInstance:function(o,klass){return Aurora.isClass(klass)&&o instanceof klass},isType:function(o){if(Aurora.isArray(o)){return o[0]&&Aurora.isType(o[0])}else{return!!Aurora.types[o._name]}},isValidArray:function(o,rule){if(Aurora.isArray(o)){if(rule){for(var i=0;i<o.length;i++){if(!rule._isValid(o[i])){return false}}}return true}else{return false}}};Aurora.Exception={array:function(className,method,prop,type){return new Error('Type Violation on '+className+' in '+method+': array items of instance variable "'+prop+'" must match the expected type ('+type+')')},type:function(className,method,prop,type){return new Error('Type Violation on '+className+' in '+method+': instance variable "'+prop+'" must match the expected type ('+type+')')},invariant:function(className,method,prop){return new Error('Invariant Violation on '+className+' in '+method+': instance variable "'+prop+'" must meet the terms of the invariant')}};var types=['String','Date','Number','RegExp','Function','Boolean','Array','Object','Null','Element','Event','NodeList'];for(var i=0;i<types.length;i++){var type=types[i];Aurora.define(type,Aurora['is'+type])}}())