
/**
 * -----------------------------------------------------
 * Visual is a singleton Behavior that installs visual
 * behavior on DOM elements, usually of type HTMLDivElement.
 * A visual will automatically size itself to fill any pane
 * that it is placed into.
 * The Visual Behavior can also create a visual from scratch.
 *
 * Logging of Visual.installOn() events can be turned
 * on by setting Log.enabled to true and setting either
 * Visual.debug.installOn or Behavior.debug.installOn
 * to true.
 */
new Behavior({
  // Teacher members
  name: "Visual",
  /**
   * Visual.teach(element) teaches element to be a visual.
   */
  init: function(element) {
    var style = element.style;
    style.position = "absolute";
    style.left = "0em";
    style.right = "0em";
    style.top = "0em";
    style.bottom = "0em";
  },
  members: {
//    ADD_CLASS: function(className) {
//      if (this.className) {
//        this.className += " " + className;
//      } else {
//        this.className = className;
//      }
//    },
    CLEAR_WIDTH: function() {
      var width = this.style.width;
      this.style.width = "auto";
      return width;
    },
    CLEAR_HEIGHT: function() {
      var height = this.style.height;
      this.style.height = "auto";
      return height;
    }
  }
});
/**
 * Visual.create() returns a new HTMLDivElement visual.
 */
Visual.create = function(name) {
  var visual = document.createElement("div");
  Named.installOn(visual, name);
  Visual.installOn(visual);
  return visual;
}

HTMLElement.prototype.ADD_CLASS = function(className) {
  if (this.className) {
    this.className += " " + className;
  } else {
    this.className = className;
  }
};

/**
 * -----------------------------------------------------
 * Pane is a singleton object that educates DOM elements,
 * usually of type HTMLDivElement, to be panes.
 * A pane represents a rectangular region of the browser
 * window.
 * It has no appearence on its own, but can contain a
 * visual.
 * Pane can also create a pane from scratch.
 *
 * Logging of Pane.installOn() events can be turned
 * on by setting Log.enabled to true and setting either
 * Pane.debug.installOn or Behavior.debug.installOn
 * to true.
 * Logging of SET_VISUAL() invokations for panes can be
 * turned on by setting Pane.debug.SET_VISUAL to true.
 * Since all of the "PUT" methods invoke SET_VISUAL()
 * this will also log "PUT" method invokations.
 */
new Behavior({
  name: "Pane",
  /**
   * Intention: private
   *
   * Pane.teach(element, name) teaches element to be a
   * pane.
   * The parameter name is used to identify element in
   * its toString() method.
   */
  init: function(element, name) {
    Named.installOn(element, name);
    element.className = "pane";
    var style = element.style;
    style.position = "absolute";
    style.padding = "0em";
    style.margin = "0em";
    style.borderStyle = "none";
  },
  members: {
    /**
     * pane.SET_VISUAL(visual) replaces the old visual
     * of pane by visual.
     */
    SET_VISUAL: function(visual) {
      if (this.VISUAL == visual) {
        return;
      }
      DOM.appendChild(this, visual);
      if (this.VISUAL) {
        DOM.removeChild(this, this.VISUAL);
      }
      this.VISUAL = visual;
      if (Pane.debug.SET_VISUAL) {
        var message = this.toString();
        message += ".VISUAL changed to ";
        message += this.VISUAL.toString() + ".";
        Log.add(message);
      }
    },
    SET_CONTENT: function(element) {
      if (element.title) {
        var header = DOM.createElement("h4", element.title);
        DOM.insertFirst(element, header);
        element.title = "";
      }
      var putList = [];
      var children = element.childNodes;
      for (var i = 0; i < children.length; i++) {
        var child = children.item(i);
        if (child.className && child.className.match(/^put-/)) {
          putList.push(child);
        }
      }
      if (putList.length == 0) {
        this.SET_VISUAL(element);
        return null;
      }
      var frame = new Frame(this);
      for (var k = 0; k < putList.length; k++) {
        var tempPane = Pane.create(this.NAME + ".temp" + k);
        Visual.installOn(tempPane);
        var putItem = putList[k];
        Section.members.processIncludes.call(putItem);
        var putClass = putItem.className;
        Visual.installOn(putItem);
        putItem.ADD_CLASS("content");
        var width = putItem.CLEAR_WIDTH() || "50%";
        var height = putItem.CLEAR_HEIGHT() || "50%";
        var childFrame = tempPane.SET_CONTENT(putItem);
        if (childFrame) {
          putItem = tempPane;
        }
        if (putClass == "put-left") {
          frame.putLeft(putItem, width);
        } else if (putClass == "put-right") {
          frame.putRight(putItem, width);
        } else if (putClass == "put-top") {
          frame.putTop(putItem, height);
        } else if (putClass == "put-bottom") {
          frame.putBottom(putItem, height);
        } else if (putClass == "put-rest") {
          putItem.ADD_CLASS("content");
          frame.setVisual(putItem);
        } else {
          var message = DOM.createElement("h4", "Invalid Put Type: " + putClass);
          message.className = "error-text"
          DOM.insertFirst(putItem, message)
          frame.putTop(putItem, height);
        }
      }
      frame.setVisual(element);
      return frame;
    }
  }
});
/**
   * Intention: private
   *
   * Pane.create(name) returns a new HTMLDivElement pane
   * whose toString() is name.
   */
Pane.create = function(name) {
  var pane = document.createElement("div");
  Pane.installOn(pane, name);
  return pane;
};
/**
   * Pane.createWrapper(name) returns a new HTMLDivElement
   * pane whose toString() is name.
   * The new pane serves as a placeholder for an element to be
   * added later.
   * It fills the pane it is placed into.
   */
Pane.createWrapper = function(name) {
  var pane = this.create(name);
  var style = pane.style;
  style.left = "0em";
  style.right = "0em";
  style.top = "0em";
  style.bottom = "0em";
  return pane;
};
/**
   * Pane.getRootPane() returns the pane representing the
   * entire document window.
   */
Pane.getRootPane = function() {
  if (!this.rootPane) {
    this.rootPane = document.body;
    Pane.installOn(this.rootPane, "root");
    Visual.installOn(this.rootPane, "root");
    this.rootPane.style.overflow = "hidden";
  }
  return this.rootPane;
};

/**
   * FIXME - add comment.
   */
function Frame(pane) {
  if (!pane) {
    pane = Pane.getRootPane();
  }
  this.outerPane = pane;
  var identifier = pane.toString() + ".target";
  this.targetPane = Pane.createWrapper(identifier);
  pane.SET_VISUAL(this.targetPane);
  this.addedCount = 0;
}
Frame.prototype.getNewName = function() {
  var newName = this.targetPane.toString();
  newName += "." + this.addedCount;
  this.addedCount++;
  return newName;
}
Frame.prototype.getPane = function() {
  return this.outerPane;
};
Frame.prototype.getTargetPane = function() {
  return this.targetPane;
};
/**
   * frame.putLeft(visual, width) sets the width of visual
   * to width and inserts it to the left of the target
   * pane of frame.
   */
Frame.prototype.putLeft = function(visual, width) {
  visual.ADD_CLASS("bordered");
  var identifier = this.targetPane.toString();
  var wrapper = Pane.createWrapper(this.getNewName());
  var parent = this.targetPane.parentNode;
  parent.SET_VISUAL(wrapper);
  var leftPane = Pane.create(identifier + ".left");
  leftPane.style.width = width;
  leftPane.style.left = "0em";
  leftPane.style.top = "0em";
  leftPane.style.bottom = "0em";
  leftPane.SET_VISUAL(visual);
  wrapper.appendChild(leftPane);
  var rightPane = Pane.create(identifier + ".right");
  rightPane.style.left = width;
  rightPane.style.right = "0em";
  rightPane.style.top = "0em";
  rightPane.style.bottom = "0em";
  rightPane.SET_VISUAL(this.targetPane);
  wrapper.appendChild(rightPane);
};
/**
   * frame.putRight(visual, width) sets the width of visual
   * to width and inserts it to the right of the target
   * pane of frame.
   */
Frame.prototype.putRight = function(visual, width) {
  visual.ADD_CLASS("bordered");
  var identifier = this.targetPane.toString();
  var wrapper = Pane.createWrapper(this.getNewName());
  var parent = this.targetPane.parentNode;
  parent.SET_VISUAL(wrapper);
  var rightPane = Pane.create(identifier + ".right");
  rightPane.style.width = width;
  rightPane.style.right = "0em";
  rightPane.style.top = "0em";
  rightPane.style.bottom = "0em";
  rightPane.SET_VISUAL(visual);
  wrapper.appendChild(rightPane);
  var leftPane = Pane.create(identifier + ".left");
  leftPane.style.right = width;
  leftPane.style.left = "0em";
  leftPane.style.top = "0em";
  leftPane.style.bottom = "0em";
  leftPane.SET_VISUAL(this.targetPane);
  wrapper.appendChild(leftPane);
};
/**
   * frame.putTop(visual, height) sets the height of visual
   * to height and inserts it above the target pane of
   * frame.
   */
Frame.prototype.putTop = function(visual, height) {
  visual.ADD_CLASS("bordered");
  var identifier = this.targetPane.toString();
  var wrapper = Pane.createWrapper(this.getNewName());
  var parent = this.targetPane.parentNode;
  parent.SET_VISUAL(wrapper);
  var topPane = Pane.create(identifier + ".top");
  topPane.style.height = height;
  topPane.style.left = "0em";
  topPane.style.right = "0em";
  topPane.style.top = "0em";
  topPane.SET_VISUAL(visual);
  wrapper.appendChild(topPane);
  var bottomPane = Pane.create(identifier + ".bottom");
  bottomPane.style.top = height;
  bottomPane.style.left = "0em";
  bottomPane.style.right = "0em";
  bottomPane.style.bottom = "0em";
  bottomPane.SET_VISUAL(this.targetPane);
  wrapper.appendChild(bottomPane);
};
/**
   * frame.putBottom(visual, height) sets the height of
   * visual to height and inserts it below the target pane
   * of frame.
   */
Frame.prototype.putBottom = function(visual, height) {
  visual.ADD_CLASS("bordered");
  var identifier = this.targetPane.toString();
  var wrapper = Pane.createWrapper(this.getNewName());
  var parent = this.targetPane.parentNode;
  parent.SET_VISUAL(wrapper);
  var bottomPane = Pane.create(identifier + ".bottom");
  bottomPane.style.height = height;
  bottomPane.style.left = "0em";
  bottomPane.style.right = "0em";
  bottomPane.style.bottom = "0em";
  bottomPane.SET_VISUAL(visual);
  wrapper.appendChild(bottomPane);
  var topPane = Pane.create(identifier + ".top");
  topPane.style.bottom = height;
  topPane.style.left = "0em";
  topPane.style.right = "0em";
  topPane.style.top = "0em";
  topPane.SET_VISUAL(this.targetPane);
  this.targetPane.className = "top";
  wrapper.appendChild(topPane);
};
/**
 * frame.setVisual(visual) puts visual into the
 * target pane of frame.
 */
Frame.prototype.setVisual = function(visual) {
  this.targetPane.SET_VISUAL(visual);
};

