1 rio.Theme = {
  2 	
  3 	isThemeBindingOn: function() {
  4 		return rio.environment.themeBindability;
  5 	},
  6 	
  7 	scrubStyleName: function(styleName) {
  8 		return styleName.gsub(/\./, "_");
  9 	},
 10 	
 11 	create: function(name, attributes) {
 12 		var theme;
 13 		
 14 		var compute = function(component, name) {
 15 			var themeletTheme = "." + (component.getThemelet() || "") + "." + name;
 16 			var buildComponentThemes = function(component) {
 17 				var componentTheme = component + "." + name;
 18 				if (component.superclass) {
 19 					return [componentTheme, buildComponentThemes(component.superclass)].flatten();
 20 				} else {
 21 					return [componentTheme];
 22 				}
 23 			};
 24 
 25 			var componentTheme = buildComponentThemes(component.constructor).detect(function(componentTheme) {
 26 				return this.names().include(componentTheme);
 27 			}.bind(this));
 28 			if (this.names().include(themeletTheme)) {
 29 				return this.get(themeletTheme);
 30 			} else if (componentTheme != undefined) {
 31 				return this.get(componentTheme);
 32 			} else {
 33 				return this.get(name);
 34 			}
 35 		};
 36 		if (this.isThemeBindingOn()) {
 37 			theme = rio.Attr.create();
 38 			Object.keys(attributes).each(function(styleName) {
 39 				theme.attrAccessor(rio.Theme.scrubStyleName(styleName), attributes[styleName]);
 40 			});
 41 
 42 			rio.Attr.extend(theme, {
 43 				get: function(name) {
 44 					return this[rio.Theme.scrubStyleName(name)];
 45 				},
 46 				names: function() {
 47 					return Object.keys(attributes);
 48 				},
 49 				compute: compute
 50 			});
 51 			return new theme();
 52 		} else {
 53 			theme = {};
 54 
 55 			theme._names = Object.keys(attributes);
 56 			theme.attributes = theme._names.inject({}, function(acc, name) {
 57 				acc[rio.Theme.scrubStyleName(name)] = attributes[name];
 58 				return acc;
 59 			});
 60 			
 61 			theme.get = function(name) {
 62 				var scrubbedName = rio.Theme.scrubStyleName(name);
 63 				var value = this.attributes[scrubbedName];
 64 				if (value && value.ATTR_ALIAS) {
 65 					return this.get(value.name);
 66 				} else {
 67 					return value;
 68 				}
 69 			}.bind(theme);
 70 			theme.names = function() {
 71 				return this._names;
 72 			}.bind(theme);
 73 			
 74 			theme.compute = compute.bind(theme);
 75 
 76 			return theme;
 77 		}
 78 	},
 79 	
 80 	alias: function(name) {
 81 		return rio.Attr.alias(rio.Theme.scrubStyleName(name));
 82 	},
 83 	
 84 	toString: function() { return "Theme"; }
 85 };
 86 
 87 rio.theme = function(name) {
 88 	if (rio.app && rio.app.themeLoaded()) {
 89 		return rio.app.theme(name);
 90 	} else {
 91 		var themeResolver = function() { 
 92 			return rio.app.theme(name);
 93 		};
 94 	
 95 		themeResolver.DELEGATE_GET = true;
 96 		return themeResolver;
 97 	}
 98 };