(function($, document){

$(document).ready(function(){
    var callbacks = [];

    callbacks[0] = CreateIteratorCallback(
        new CssTableModelSupport(),
        CssTableModelSupport.prototype.styleSheetCallback);

    /*
    // this cs now handled using http://code.google.com/p/ie7-js/
    callbacks[1] = CreateIteratorCallback(
        new AfterSelectorSupport(),
        AfterSelectorSupport.prototype.styleSheetCallback);
    */

    StyleSheetsIterator(callbacks);
});

function StyleSheetsIterator(callbacks) {
    var styleSheets = document.styleSheets;
    var rules, selectorText, styles;

    for (var sIndex = 0; sIndex < styleSheets.length; sIndex++) {
        rules = styleSheets[sIndex].rules;

        for (var rIndex in rules) {
            selectorText = rules[rIndex].selectorText;
            styles = rules[rIndex].style || {};

            if (selectorText) {
                $.each(callbacks, function(index, value){
                    if ($.isFunction(value)) {
                        value(selectorText, styles);
                    }
                });
            }
        }
    }
}

function CreateIteratorCallback(object, method) {
    var callback = function(selectorText, styles) {
        method.call(object, selectorText, styles);
    };

    return callback;
}

function AfterSelectorSupport() {}

AfterSelectorSupport.prototype.styleSheetCallback = function(selectorText, styles) {
    var $elements, text;

    // return if not an :after selector or is an unusuable content value
    if (!selectorText.match(/:after/i) || !styles.content) {
        return;
    }

    // need to remove the :after selector to get the actual elements
    $elements = $(selectorText.replace(/:after/ig, ""));

    // need to remove the first and last quote
    text = styles.content.substr(1, styles.content.length-2);

    $elements.each(function(){
        var $this = $(this),
            content = document.createElement("span");

        // innerText instead of innerHTML to preserve whitespace
        content.innerText = text;

        // this needs to come before the loop so that certain styles properties,
        // like dimensions can be set
        this.appendChild(content);

         for (var pIndex in styles) {
             if (styles[pIndex] && styles[pIndex] != "content") {
                 content.style[pIndex] = styles[pIndex];
             }
         }
    });
};

function CssTableModelSupport() {
    this.seenSelectors = {};
}

CssTableModelSupport.prototype.styleSheetCallback = function(selectorText, styles) {
    var display;

    // return if the selector has been seen or the display property is not set
    if (this.seenSelectors[selectorText] || !styles.display) {
        return;
    }

    display = styles.display;

    if (display == "table-cell") {
        this.transformToCell(selectorText);
        this.seenSelectors[selectorText+display];
    } else if (display == "table-row") {
        this.transformToRow(selectorText);
        this.seenSelectors[selectorText+display];
    } else if (display == "table") {
        this.transformToTable(selectorText);
        this.seenSelectors[selectorText+display];
    }
};

CssTableModelSupport.prototype.transformToCell = function(selectorText) {
  var object = this;

  this.transform(selectorText, function(){
    var parent = this.parentNode,
        cell = document.createElement("td");

    cell.innerHTML = this.innerHTML;
    object.transferAttributes(this, cell);
    parent.insertBefore(cell, this);
    parent.removeChild(this);
  });
};

CssTableModelSupport.prototype.transformToRow = function(selectorText) {
  var object = this;

  this.transform(selectorText, function(){
    var parent = this.parentNode,
        row = document.createElement("tr");

    row.innerHTML = this.innerHTML;
    object.transferAttributes(this, row);
    parent.insertBefore(row, this);
    parent.removeChild(this);
  });
};

CssTableModelSupport.prototype.transformToTable = function(selectorText) {
  var object = this;

  this.transform(selectorText, function(){
    // use jQuery because there are compatibility issues with some table
    // elements and innerHTML, e.g., IE requires it's separate table object
    // model to create tables
    $(this).wrapInner("<tbody />");
    $(this).wrapInner("<table />");
    object.transferAttributesToFirstChild(this);
  });
};

CssTableModelSupport.prototype.transform = function(selectorText, transform) {
    var $elements;

    // for now, ignore the body tag
    if (selectorText.match(/^body$/i)) {
        return;
    }

    $elements = $(selectorText);
    $elements.each(transform);
};

CssTableModelSupport.prototype.transferAttributesToParent = function(node) {
    this.transferAttributes(node, node.parentNode);
};

CssTableModelSupport.prototype.transferAttributesToFirstChild = function(node) {
    this.transferAttributes(node, node.childNodes[0]);
};

CssTableModelSupport.prototype.transferAttributes = function(from, to) {
    // transfer class names
    if (from.className) {
        to.className = from.className;
        from.className = "";
    }

    // transfer element ID
    if (from.id) {
      var id = from.id;
      $(from).removeAttr("id");
      to.id = id;
    }

    // transfer style attribute
    if (from.getAttribute("style")) {
        to.setAttribute("style", from.getAttribute("style"));
        from.removeAttribute("style");
    }
};

CssTableModelSupport.prototype.seenSelectors = null;

}(jQuery, document));
