function CSSStyleDeclaration (element) {
  if (document.all && window.opera) {
    return new OperaCSSStyleDeclaration(element);
  } else if (document.all) {
    return new InternetExplorerCSSStyleDeclaration(element);
  } else {
    return new MozillaCSSStyleDeclaration(element);
  }
}

function OperaCSSStyleDeclaration (element) {
  this.element = element;

  this.update();
}

OperaCSSStyleDeclaration.prototype.update = function () {

  this.declaration = document.defaultView.getComputedStyle(this.element,null);
  this.cssText = this.declaration.cssText;
}

OperaCSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) {
  switch (propertyName) {
    case 'height':
      return this._getHeight();
    case 'width':
      return this._getWidth();
    default:
      return this.declaration.getPropertyValue(propertyName);
  }
}

OperaCSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) {
// alert(this.declaration.getPropertyPriority(propertyName));
  // Opera bug
  return null;
//  return this.declaration.getPropertyPriority(propertyName);
}

OperaCSSStyleDeclaration.prototype.setProperty = function (propertyName, value, priority) {
  this.element.style[CSSProperty.getECMAScriptBinding(propertyName)] = value + (priority && priority.toLowerCase() == 'important' ? ' !important' : '');
  this.update();
}

OperaCSSStyleDeclaration.prototype.removeProperty = function (propertyName) {
  this.element.style[CSSProperty.getECMAScriptBinding(propertyName)] = CSSProperty.getPropertyDefaultValue(propertyName);
  this.update();
}

OperaCSSStyleDeclaration.prototype._getHeight = function () {
  var height = parseInt(this.declaration.getPropertyValue('height'));
  if (window.opera.version() <= '9.0') {
    // version 9.0- incorrectly calculate the height. They calculate the height
    // as: border-top + padding-top + height + padding-bottom + border-bottom
    // to get the real height the border-top, padding-top, padding-bottom and
    // border-bottom needs to be substracted from the height.
    //
    // !!! does this also work when em and px measures are mixed? !!!
    //
    height -= parseInt(this.declaration.getPropertyValue('border-top-width'));
    height -= parseInt(this.declaration.getPropertyValue('padding-top'));
    height -= parseInt(this.declaration.getPropertyValue('border-bottom-width'));
    height -= parseInt(this.declaration.getPropertyValue('padding-bottom'));
  }
  return height + 'px';
}

OperaCSSStyleDeclaration.prototype._getWidth = function () {
  var width = parseInt(this.declaration.getPropertyValue('width'));
  if (window.opera.version() <= '9.0') {
    // version 9.0- incorrectly calculate the width. They calculate the width
    // as: border-left + padding-left + width + padding-right + border-right
    // to get the real height the border-left, padding-left, padding-right and
    // border-right needs to be substracted from the width.
    //
    // !!! does this also work when em and px measures are mixed? !!!
    //
    width -= parseInt(this.declaration.getPropertyValue('border-left-width'));
    width -= parseInt(this.declaration.getPropertyValue('padding-left'));
    width -= parseInt(this.declaration.getPropertyValue('border-right-width'));
    width -= parseInt(this.declaration.getPropertyValue('padding-right'));
  }
  return width + 'px';
}

MozillaCSSStyleDeclaration = function (element) {
  this.element = element;
  this.update();
}

MozillaCSSStyleDeclaration.prototype.update = function () {

  this.declaration = document.defaultView.getComputedStyle(this.element,null);
  this.cssText = this.declaration.cssText;
}

MozillaCSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) {
  switch (propertyName) {
    default:
      return this.declaration.getPropertyValue(propertyName);
  }
}

MozillaCSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) {
  return this.declaration.getPropertyPriority(propertyName);
}

MozillaCSSStyleDeclaration.prototype.setProperty = function (propertyName, value, priority) {
  this.element.style[CSSProperty.getECMAScriptBinding(propertyName)] = value + (priority && priority.toLowerCase() == 'important' ? ' !important' : '');
  this.update();
}

MozillaCSSStyleDeclaration.prototype.removeProperty = function (propertyName) {
  this.element.style[CSSProperty.getECMAScriptBinding(propertyName)] = CSSProperty.getPropertyDefaultValue(propertyName);
  this.update();
}

InternetExplorerCSSStyleDeclaration = function (element) {
  this.element = element;
  this.update();
}

InternetExplorerCSSStyleDeclaration.prototype.update = function () {

  this.declaration = this.element.currentStyle;
  this.cssText = this.element.style.cssText;
}

InternetExplorerCSSStyleDeclaration.prototype.getPropertyValue = function (propertyName) {
  switch (propertyName) {
    case 'width':
      return this._getWidth();
    case 'height':
      return this._getHeight();
    default:
      return this.declaration[CSSProperty.getECMAScriptBinding(propertyName)];
  }
}

InternetExplorerCSSStyleDeclaration.prototype.getPropertyPriority = function (propertyName) {
  // not implemented
  return null;
}

InternetExplorerCSSStyleDeclaration.prototype.setProperty = function (propertyName, value, priority) {
  this.element.style[CSSProperty.getECMAScriptBinding(propertyName)] = value /*+ (priority && priority.toLowerCase() == 'important' ? ' !important' : '')*/;
  this.update();
}

InternetExplorerCSSStyleDeclaration.prototype.removeProperty = function (propertyName) {
  this.element.style[CSSProperty.getECMAScriptBinding(propertyName)] = CSSProperty.getPropertyDefaultValue(propertyName);
  this.update();
}

InternetExplorerCSSStyleDeclaration.prototype._getWidth = function () {
  var width = this.declaration.width;
  if (width == 'auto') {
    // we do want to convert it to some pixel measure...
  }
  return width;
}

InternetExplorerCSSStyleDeclaration.prototype._getHeight = function () {
  var height = this.declaration.height;
  if (height == 'auto') {
    // we do want to convert it to some pixel measure...
  }
  return height;
}