var MessageManager = {
  
  msgDuration: 2000,
  msgBoxId: "main_message_box",
  msgContentId: "main_message_content",
  msgMarkup: "<div class='message'>#{msg}</div>",
  inProgress: false,
  
  getElements: function() {
    var elements = {};
    elements.box = $(this.msgBoxId);
    elements.content = $(this.msgContentId);
    return elements;
  },

  /**
   * Shows a message in the "main_message_box" element.
   * This method is the preferred way of showing messages to the end user.
   * Will hide the message after an interval of time has lapsed.
   *
   * TODO: Update to ensure the message box is always visible even if the user has scrolled.
   *
   * @param {String} msg The message to display. */
  showMessage: function(msg, preserve) {
    if (window != top && top.MessageManager) {
      top.MessageManager.showMessage(msg, preserve);
      return;
    }
    
    inProgress = true;
    var elements = this.getElements();
    var box = elements.box;
    var content = elements.content;

    if (box && content) {
      var html = this.msgMarkup.interpolate({msg: msg});
      clearTimeout(this.msgTimeout);

      if (this.msgVisible) {
        if (content.innerHTML.indexOf(msg) == -1) {
          content.innerHTML += html;
        }
      }
      else {
        content.innerHTML = html;
        var resetMorph = new Fx.Styles(box, {duration: 0});
        resetMorph.setStyle(box, "opacity", 0);
        box.style.display = "";
        this.positionMessage();
        
        box.visibleTop = Number(box.style.top.replace("px", ""));
        box.hiddenTop = Number("-" + (box.offsetHeight + box.visibleTop));
        resetMorph.setStyle(box, "top", box.hiddenTop);
        
        var morph = new Fx.Styles(box, {duration: 1000, transition: Fx.Transitions.elasticInOut });
        morph.custom({opacity: [0, .9], top: [box.hiddenTop, box.visibleTop]});
      }

      this.msgVisible = true;
      if (!preserve) {
        this.msgTimeout = setTimeout('MessageManager.hideMessage();', this.msgDuration);
      }
    }
  },

  /**
   * Hides the message contained in the "main_message_box" element. */
  hideMessage: function() {
    clearTimeout(this.msgTimeout);
    
    var elements = this.getElements();
    var box = elements.box;
    
    if (box && this.msgVisible) {
      var morph = new Fx.Styles(box, {duration: 300, transition: Fx.Transitions.elasticInOut });
      morph.custom({opacity: [.9, 0]});
      this.msgVisible = false;
      setTimeout("MessageManager.finalizeMessage();", 400);
    }
  },
  
  closeMessage: function() {
    clearTimeout(this.msgTimeout);
    
    var elements = this.getElements();
    var box = elements.box;
    
    if (box && this.msgVisible) {
      var morph = new Fx.Styles(box, {duration: 0});
      morph.setStyle(box, "opacity", 0);
      this.msgVisible = false;
      setTimeout("MessageManager.finalizeMessage();", 10);
    }
  },
  
  /** 
   * Finalizes the message by removing the message content and sets inProgress to false. */
  finalizeMessage: function() {
    var elements = this.getElements();
    elements.content.innerHTML = "";
    elements.box.style.display = "none";
    this.inProgress = false;
  },

  /**
   * Initializes a message that has been set on the server using the flash.
   * Will show the message in the standard way.
   * 
   * @param {Boolean} preserve Indicates that the message should be preserved (not hidden
   *  after a specified interval of time. */
  initMessage: function(preserve) {
    if (this.inProgress) {
      setTimeout("MessageManager.initMessage(" + preserve + ");", 250);
      return;
    }
    
    var elements = this.getElements();
    var box = elements.box;
    var content = elements.content;
    
    if (box && content && content.innerHTML.length > 0) {
      var resetMorph = new Fx.Styles(box, {duration: 0});
      resetMorph.setStyle(box, "opacity", 0);
      box.style.display = "";
      this.positionMessage();
      box.visibleTop = Number(box.style.top.replace("px", ""));
      box.hiddenTop = Number("-" + (box.offsetHeight + box.visibleTop));
      resetMorph.setStyle(box, "top", box.hiddenTop);

      var morph = new Fx.Styles(box, {duration: 1000, transition: Fx.Transitions.elasticInOut });
      morph.custom({opacity: [0, .9], top: [box.hiddenTop, box.visibleTop]});
      
      this.msgVisible = true;
      
      if (!preserve) {
        this.msgTimeout = setTimeout('MessageManager.hideMessage();', this.msgDuration);
      }  
    }
  },

  /**
   * Positions the message box.
   * This is invoked on an interval because onscroll is not a dependable event
   * across browser implementations.
   */
  positionMessage: function() {
    var elements = this.getElements();
    var box = elements.box;
    var offsets = document.viewport.getScrollOffsets();
    box.style.position = "absolute";
    box.style.zIndex = 9999;
    box.style.top = (offsets.top + 75) + "px";
    var visibleWidth = document.viewport.getWidth();
    box.style.left = ((visibleWidth / 2) - (box.offsetWidth / 2) + 10) + "px";
  }
}

//setInterval("MessageManager.positionMessage();", 150);