/**
 * @ignore
 * Normalize operation about stylesheet
 * @author yiminghe@gmail.com
 */
KISSY.add("stylesheet", function (S, DOM) {

    /**
     * Normalize operation about stylesheet
     * @class KISSY.StyleSheet
     * @param el {HTMLElement} style/link element
     */
    function StyleSheet(el) {

        /**
         * style/link element or selector
         * @cfg {HTMLElement|String} el
         */

        /**
         * style/link element
         * @type {HTMLElement}
         * @property el
         */
        

        if (el.el) {
            el = el.el;
        }

        this['el'] = DOM.get(el);
        // http://msdn.microsoft.com/en-us/library/ie/ms535871(v=vs.85).aspx
        // firefox 跨域时抛出异常
        var sheet = el.sheet || el.styleSheet;

        this.sheet = sheet;

        var cssRules = {};

        this.cssRules = cssRules;

        var rulesName = sheet && ('cssRules' in sheet) ? 'cssRules' : 'rules';

        this.rulesName = rulesName;

        var domCssRules = sheet[rulesName];

        var i, rule, selectorText, styleDeclaration;

        for (i = domCssRules.length - 1; i >= 0; i--) {
            rule = domCssRules[i];
            selectorText = rule.selectorText;
            // 去重
            if (styleDeclaration = cssRules[selectorText]) {
                styleDeclaration.style.cssText += ";" + styleDeclaration.style.cssText;
                deleteRule(sheet, i);
            } else {
                cssRules[selectorText] = rule;
            }
        }
    }

    StyleSheet.prototype = {

        constructor: StyleSheet,

        /**
         * Make current stylesheet enabled.
         * @chainable
         */
        enable: function () {
            this.sheet.disabled = false;
            return this;
        },

        /**
         * Make current stylesheet disabled.
         * @chainable
         */
        disable: function () {
            this.sheet.disabled = true;
            return this;
        },

        /**
         * Whether current stylesheet is enabled.
         * @return {Boolean}
         */
        'isEnabled': function () {
            return !this.sheet.disabled;
        },

        /**
         * Set sheet's rule by selectorText and css.
         * @param {String} selectorText selector text separated by ,
         * @param {Object} css style declaration object. set value to "" to unset
         *
         * for example:
         * <code>
         *      // set
         *      set("p",{color:'red'})
         *      // unset
         *      set("p",{color:''})
         * </code>
         * @chainable
         */
        set: function (selectorText, css) {
            var sheet = this.sheet;
            var rulesName = this.rulesName;
            var cssRules = this.cssRules;
            var rule = cssRules[selectorText];
            var multiSelector = selectorText.split(/\s*,\s*/);
            var i;

            if (multiSelector.length > 1) {
                for (i = 0; i < multiSelector.length - 1; i++) {
                    this.set(multiSelector[i], css);
                }
                return this;
            }

            if (rule) {
                css = toCssText(css, rule.style.cssText);
                if (css) {
                    rule.style.cssText = css;
                } else {
                    // unset remove this rule
                    delete cssRules[selectorText];
                    for (i = sheet[rulesName].length - 1; i >= 0; i--) {
                        if (sheet[rulesName][i] == rule) {
                            deleteRule(sheet, i);
                            break;
                        }
                    }
                }
            } else {
                var len = sheet[rulesName].length;
                css = toCssText(css);
                if (css) {
                    insertRule(sheet, selectorText, css, len);
                    cssRules[selectorText] = sheet[rulesName][len];
                }
            }

            return this;
        },

        /**
         * Get cssText corresponding to specified selectorText
         * @param {String} selectorText specified selector as string
         * @return {String} CssText corresponding to specified selectorText
         */
        get: function (selectorText) {
            var rule, css, selector, cssRules = this.cssRules;

            if (selectorText) {
                rule = cssRules[selectorText];

                return rule ? rule.style.cssText : null;
            } else {
                css = [];
                for (selector in cssRules) {

                    rule = cssRules[selector];
                    css.push(rule.selectorText + " {" + rule.style.cssText + "}");

                }
                return css.join("\n");
            }
        }

    };


    // # ------------------ private start

    var workerElement = document.createElement("p");

    function toCssText(css, base) {
        workerElement.style.cssText = base || "";
        DOM.css(workerElement, css);
        return workerElement.style.cssText;
    }

    function deleteRule(sheet, i) {
        if (sheet.deleteRule) {
            sheet.deleteRule(i);
        } else if (sheet.removeRule) {
            sheet.removeRule(i);
        }
    }

    function insertRule(sheet, sel, css, i) {
        if (sheet.insertRule) {
            sheet.insertRule(sel + ' {' + css + '}', i);
        } else if (sheet.addRule) {
            sheet.addRule(sel, css, i);
        }
    }

    // # ------------------ private end

    return StyleSheet;

}, {
    requires: ['dom']
});
/**
 * @ignore
 * Refer
 *  - http://www.w3.org/TR/DOM-Level-2-Style/css.html
 *  - rule.style 和 el.style 效果一样,同属于 CSSStyleDeclare
 **/