//  Refactor this into an Editor.Body or Editor.Document class

Editor.IFrame = Class.create();
Editor.IFrame.prototype = {

  initialize: function(original, options) {
    this._element = new Element("iframe", { frameBorder: 0 });

    this.replace(original);
    this.enableEditing();
    this.format(options || {});

    this.document().importNode = Editor.DocumentExtensions.importNode;
  },

  window: function() {
    if (!this._window) {
      this._window = this._element.contentWindow;
    }
    return this._window;
  },
  
  document: function() {
    if (!this._document) {
      this._document = this._element.contentWindow.document;
    }
    return this._document;
  },
  
  body: function() {
    if (!this._body) {
      this._body = this._element.contentWindow.document.getElementsByTagName("body")[0];
    }
    return this._body;
  },

  replace: function(original) {
    original.parentNode.insertBefore(this._element, original);
    original.parentNode.removeChild(original);
  },

  enableEditing: function() {
    var setDesignMode = (function() { this.document().designMode = "on"; }).bind(this);
    try      { setDesignMode(); }
    catch(e) { setTimeout(setDesignMode, 250); }

    this.document().write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title></title></head><body></body></html>');
    this.document().close();

    try      { this.document().execCommand("styleWithCSS", false, false); }
    catch(e) {} // IE does not implement StyleWithCSS
  },

  format: function(options) {
    this.setStyleSheets(options.styleSheets);
    this.setDimensions(options.width, options.height);
    if (options.classNames.any()) { this._element.className = options.classNames.join(" "); }
    this._element.id = options.id + "_editor";
  },
  
  setDimensions: function(width, height) {
    this._element.setStyle({
      width:  width  + "px",
      height: height + "px"
    });
    // reset height and width to include the iframe's border & padding
    var d = this._element.getDimensions();
    var w = (d.width  < width)  ? (width  - (d.width - width))   : width;
    var h = (d.height < height) ? (height - (d.height - height)) : height;
    this._element.setStyle({
      width:  w + "px",
      height: h + "px"
    });
  },
  
  setStyleSheets: function(filepaths) {
    filepaths.each((function(filepath) {
      var l = this.document().createElement("link");
      l.href = filepath;
      l.type = "text/css";
      l.rel  = "stylesheet";
      this.document().getElementsByTagName("head")[0].appendChild(l);
    }).bind(this));
  },

  // move into own class...  
  inline: function(compare) {
    return $A(["span", "a", "em", "i", "strong", "b", "u"]).include(compare.toLowerCase());
  },
  
  defaultElement: function() {
    return this.document().createElement("p");
  },
  
  appendChild: function(element) {
    element = this.document().importNode(element);
    return this.body().appendChild(element);
  },

  wrap: function(elements) {
    if (elements.each) {
      return this.wrapCollection(elements);
    } else {
      var outer = this.defaultElement();
      outer.appendChild(elements);
      return outer;
    }
  },

  wrapCollection: function(collection) {
    if (collection.length == 0) { return collection; }
    var outer = this.defaultElement();
    collection.each(function(element) {
      outer.appendChild(element);
    });
    return outer;
  },

  build: function(elements) {
    if (typeof(elements) == "string") {
      return this.buildFromString(elements);
    }
    
    var wrapAndAppend = (function(collection) {
      if (collection.length > 0) {
        var wrapped = this.wrap(collection);
        this.appendChild(wrapped);
        collection = $A();
      }
      return collection;
    }).bind(this);

    var needWrapping = $A();
    elements.each((function(element) {
      if (element.nodeType == 3 || this.inline(element.nodeName)) {
        needWrapping.push(element);
      } else {
        needWrapping = wrapAndAppend(needWrapping);
        this.appendChild(element);
      }
    }).bind(this));
    wrapAndAppend(needWrapping);
  },

  buildFromString: function(str) {
    str                = str.strip();
    var tempNode       = this.document().createElement("div");
    tempNode.innerHTML = str;
    return this.build($A(tempNode.childNodes));
  },

  getStyle: function(element, style) {
    element = $(element);
    style = style == 'float' ? 'cssFloat' : style.camelize();
    var value = element.style[style];
    if (!value) {
      if (element.currentStyle) {
        var css = element.currentStyle;
      } else {
        var css = this.document().defaultView.getComputedStyle(element, null);
      }
      value = css ? css[style] : null;
    }
    if (style == 'opacity') return value ? parseFloat(value) : 1.0;
    return value == 'auto' ? null : value;
  },
  
  computeStylesFor: function(tagName, styles) {
    var element = this.document().createElement(tagName);
    element.style.position   = "absolute";
    element.style.visibility = "hidden";
    element.style.lineHeight = "1";
    element.style.padding    = "0";
    element.style.border     = "none";

    this.body().appendChild(element);

    var out = $H();
    styles.each((function(style) {
      if (element.currentStyle) {
        // This was painful...
        if (style == "fontSize") {
          out[style] = element.offsetHeight;
        } else {
          out[style] = element.currentStyle[style];
        }
      } else {
        out[style] = this.document().defaultView.getComputedStyle(element, null)[style];
      }
    }).bind(this));

    this.body().removeChild(element);
    return out;
  }
}
