    /**
     * Utility class for manipulating CSS rules
     * @singleton
     */
    Ext.define('Ext.util.CSS', function() {
        var CSS,
            rules = null,
            doc = document,
            camelRe = /(-[a-z])/gi,
            camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };

        return {

            singleton: true,

            rules: rules,

            initialized: false,

            constructor: function() {
                // Cache a reference to the singleton
                CSS = this;
            },

            /**
             * Creates a stylesheet from a text blob of rules.
             * These rules will be wrapped in a STYLE tag and appended to the HEAD of the document.
             * @param {String} cssText The text containing the css rules
             * @param {String} id An id to add to the stylesheet for later removal
             * @return {CSSStyleSheet}
             */
            createStyleSheet : function(cssText, id) {
                var ss,
                    head = doc.getElementsByTagName("head")[0],
                    styleEl = doc.createElement("style");

                styleEl.setAttribute("type", "text/css");
                if (id) {
                   styleEl.setAttribute("id", id);
                }

                if (Ext.isIE) {
                   head.appendChild(styleEl);
                   ss = styleEl.styleSheet;
                   ss.cssText = cssText;
                } else {
                    try{
                        styleEl.appendChild(doc.createTextNode(cssText));
                    } catch(e) {
                       styleEl.cssText = cssText;
                    }
                    head.appendChild(styleEl);
                    ss = styleEl.styleSheet ? styleEl.styleSheet : (styleEl.sheet || doc.styleSheets[doc.styleSheets.length-1]);
                }
                CSS.cacheStyleSheet(ss);
                return ss;
            },

            /**
             * Removes a style or link tag by id
             * @param {String} id The id of the tag
             */
            removeStyleSheet : function(id) {
                var existing = doc.getElementById(id);
                if (existing) {
                    existing.parentNode.removeChild(existing);
                }
            },

            /**
             * Dynamically swaps an existing stylesheet reference for a new one
             * @param {String} id The id of an existing link tag to remove
             * @param {String} url The href of the new stylesheet to include
             */
            swapStyleSheet : function(id, url) {
                var ss;
                CSS.removeStyleSheet(id);
                ss = doc.createElement("link");
                ss.setAttribute("rel", "stylesheet");
                ss.setAttribute("type", "text/css");
                ss.setAttribute("id", id);
                ss.setAttribute("href", url);
                doc.getElementsByTagName("head")[0].appendChild(ss);
            },

            /**
             * Refresh the rule cache if you have dynamically added stylesheets
             * @return {Object} An object (hash) of rules indexed by selector
             */
            refreshCache : function() {
                return CSS.getRules(true);
            },

            // @private
            cacheStyleSheet : function(ss) {
                if (!rules) {
                    rules = CSS.rules = {};
                }
                try {// try catch for cross domain access issue
                    var ssRules = ss.cssRules || ss.rules,
                        i = ssRules.length - 1,
                        imports = ss.imports,
                        len = imports ? imports.length : 0,
                        rule, j;

                    // Old IE has a different way of handling imports
                    for (j = 0; j < len; ++j) {
                        CSS.cacheStyleSheet(imports[j]);
                    }

                    for (; i >= 0; --i) {
                        rule = ssRules[i];
                        // If it's an @import rule, import its stylesheet
                        if (rule.styleSheet) {
                            CSS.cacheStyleSheet(rule.styleSheet);
                        }
                        CSS.cacheRule(rule, ss);
                    }
                } catch(e) {}
            },

            cacheRule: function(cssRule, styleSheet) {
                // If it's an @import rule, import its stylesheet
                if (cssRule.styleSheet) {
                    return CSS.cacheStyleSheet(cssRule.styleSheet);
                }

                var selectorText = cssRule.selectorText,
                    selectorCount, j;

                if (selectorText) {

                    // Split in case there are multiple, comma-delimited selectors
                    selectorText = selectorText.split(',');
                    selectorCount = selectorText.length;
                    for (j = 0; j < selectorCount; j++) {
                        // IE<8 does not keep a reference to parentStyleSheet in the rule, so we
                        // must cache an object like this until IE<8 is deprecated.
                        rules[Ext.String.trim(selectorText[j]).toLowerCase()] = {
                            parentStyleSheet: styleSheet,
                            cssRule: cssRule
                        };
                    };
                }
            },

            /**
             * Gets all css rules for the document
             * @param {Boolean} refreshCache true to refresh the internal cache
             * @return {Object} An object (hash) of rules indexed by selector
             */
            getRules : function(refreshCache) {
                var result = {},
                    selector;

                if (rules === null || refreshCache) {
                    CSS.refreshCache();
                }
                for (selector in rules) {
                    result[selector] = rules[selector].cssRule;
                }
                return result;
            },

            refreshCache: function() {
                var ds = doc.styleSheets,
                    i = 0,
                    len = ds.length;

                rules = CSS.rules = {}
                for (; i < len; i++) {
                    try {
                        if (!ds[i].disabled) {
                            CSS.cacheStyleSheet(ds[i]);
                        }
                    } catch(e) {}
                }
            },

            /**
             * Gets an an individual CSS rule by selector(s)
             * @param {String/String[]} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
             * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
             * @return {CSSStyleRule} The CSS rule or null if one is not found
             */
            getRule: function(selector, refreshCache, rawCache) {
                var i, result;

                if (!rules || refreshCache) {
                    CSS.refreshCache();
                }
                if (!Ext.isArray(selector)) {
                    result = rules[selector.toLowerCase()]
                    if (result && !rawCache) {
                        result = result.cssRule;
                    }
                    return result || null;
                }
                for (i = 0; i < selector.length; i++) {
                    if (rules[selector[i]]) {
                        return rawCache ? rules[selector[i].toLowerCase()] : rules[selector[i].toLowerCase()].cssRule;
                    }
                }
                return null;
            },

            /**
             * Creates a rule.
             * @param {CSSStyleSheet} styleSheet The StyleSheet to create the rule in as returned from {@link #createStyleSheet}.
             * @param {String} selector The selector to target the rule.
             * @param {String} property The cssText specification eg `"color:red;font-weight:bold;text-decoration:underline"`
             * @return {CSSStyleRule} The created rule
             */
            createRule: function(styleSheet, selector, cssText) {
                var result,
                    ruleSet = styleSheet.cssRules || styleSheet.rules,
                    index = ruleSet.length;

                if (styleSheet.insertRule) {
                    styleSheet.insertRule(selector + '{' + cssText + '}', index);
                } else {
                    styleSheet.addRule(selector, cssText||' ');
                }
                CSS.cacheRule(result = ruleSet[index], styleSheet);
                return result;
            },

            /**
             * Updates a rule property
             * @param {String/String[]} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
             * @param {String} property The css property or a cssText specification eg `"color:red;font-weight:bold;text-decoration:underline"`
             * @param {String} value The new value for the property
             * @return {Boolean} true If a rule was found and updated
             */
            updateRule : function(selector, property, value) {
                var rule, i, styles;
                if (!Ext.isArray(selector)) {
                    rule = CSS.getRule(selector);
                    if (rule) {
                        // 2 arg form means cssText sent, so parse it and update each style
                        if (arguments.length == 2) {
                            styles = Ext.Element.parseStyles(property);
                            for (property in styles) {
                                rule.style[property.replace(camelRe, camelFn)] = styles[property];
                            }
                        } else {
                            rule.style[property.replace(camelRe, camelFn)] = value;
                        }
                        return true;
                    }
                } else {
                    for (i = 0; i < selector.length; i++) {
                        if (CSS.updateRule(selector[i], property, value)) {
                            return true;
                        }
                    }
                }
                return false;
            },

            deleteRule: function(selector) {
                var rule = CSS.getRule(selector, false, true),
                    styleSheet, index;

                if (rule) {
                    styleSheet = rule.parentStyleSheet;
                    index = Ext.Array.indexOf(styleSheet.cssRules || styleSheet.rules, rule.cssRule);
                    if (styleSheet.deleteRule) {
                        styleSheet.deleteRule(index);
                    } else {
                        styleSheet.removeRule(index);
                    }
                    delete rules[selector];
                }
            }
        };
    });