/*
* A Soft Idiom popup panel.
* calling this function will pop up a panel with the node identified by the
* id as its contents.
* Parameters:
* 	event - the browser event object.
* 	id - the id of the node to be displayed.
* 	title - a title for the popup panel.
* 	width - the popup panel width.
* 	height - the popup panel height.
*/
function doPopup(event, id, title, width, height) {
  if (document.SI_login_popup != null) { return; }
  var eventObj = new EventObject(event);
  var popup = new PopupPanel();
  popup.show(id, title, eventObj.pageY-20, eventObj.pageX-240, width, height);
  return false;
}

/*
* Constructor: PopupPanel
* Parameters:
*   none
* Returns:
*   An instance of this class.
*/
//---------------------------------------------------------------------------
PopupPanel = function() {
  this.init();
  document.SI_login_popup = this;
}
PopupPanel.prototype = {
  cancelNode:		null,	// the cancel node.
  isShowing:		false,  // true if showing.
  node:			null,   // the display node.
  nodeParent:		null,   // the display node parent.
  panelNode:		null,   // the pop up node.
  titleNode:		null,   // the title node.

  CANCEL_CLASS: 'popup-cancel',
  HEADER_CLASS: 'popup-header',
  POPUP_CLASS: 'popup-panel',
  TITLE_CLASS: 'popup-title',

  /*
   * Function: init
   */
  init: function(){
    this.build();
  },
  /*
   * Function: destroy
   */
  destroy: function(){
    if (this.node != null) {
      this.panelNode.removeChild(this.node);
      this.nodeParent.appendChild(this.node);
      this.node.style.display = 'none';
    }
    document.body.removeChild(this.panelNode);
    this.cancelNode.onmouseover = null;
    this.cancelNode.popup_object = null;
    document.SI_login_popup = null;
  },
  
  //----------------------------- show/hide functions ------------------------
  
  /*
   * Function: show
   * Parameters:
   * 	id - the id of the node to be displayed.
   * 	title - a title for the popup panel.
   * 	top - the popup panel top position.
   * 	left - the popup panel left position.
   * 	width - the popup panel width.
   * 	height - the popup panel height.
   */
  show: function(id, title, top, left, width, height){
    // add the node to the panel
    this.node = document.getElementById(id);
    if (this.node == null) {
      this.createTextElement("Display node with ID '"+id+"' not found", this.panelNode)
    }
    else {
      this.nodeParent = this.node.parentNode;
      this.nodeParent.removeChild(this.node);
      this.panelNode.appendChild(this.node);
      this.node.style.display = 'block';
    }
    
    // set the title.
    this.createTextElement(title, this.titleNode);

    // position the panel and make it visible.
    var windowRight = this.getBrowserWidth();
    var windowBottom = this.getBrowserHeight();
    if (left + width > windowRight) {
      // we need to move the panel left into the window.
      left = windowRight - width - 30;
    }
    if (top + height > windowBottom) {
      // we need to move the panel up into the window.
      top = windowBottom - height - 30;
    }

    this.panelNode.style.top = top+'px';
    this.panelNode.style.left = left+'px';
    this.panelNode.style.width = width+'px';
    this.panelNode.style.height = height+'px';
    this.panelNode.style.zIndex = 9999999;
    this.panelNode.style.visibility = 'visible';
  },    
  /**
   * Function: hide
   */
  hide: function() {
    this.panelNode.style.visibility = 'hidden';
    this.destroy();
  },
  /**
   * Function: build
   */
  build: function(){
    this.panelNode = this.createElement('div', document.body, {
      className: this.POPUP_CLASS
    });
    var headerNode = this.createElement('div', this.panelNode, {
      className: this.HEADER_CLASS
    });
    this.titleNode = this.createElement('div', headerNode, {
      className: this.TITLE_CLASS
    });
    this.cancelNode = this.createElement('div', headerNode, {
      className: this.CANCEL_CLASS,
      onmouseover: this.oncancel,
      popup_object: this
    });
  },

  //----------------------------- event functions -----------------------------

  /**
   * Function: oncancel
   */
  oncancel: function() {
    var self = this.popup_object;
    self.hide();
  },
  
  //------------------- node builder functions -------------------------------
  
  /**
   * Function: createElement
   * Create a node in the DOM.
   * Properties:
   *   type - the type of node.
   *   parentNode - the parent node.
   *   properties - a collection of node properties.
   * Returns:
   *   The node.
   */
  createElement: function(type, parentNode, properties) {
    var element = document.createElement(type);
    if (properties != null) {
      for ( var property in properties) {
        if (property == "style") {
          for ( var styleProperty in properties.style) {
            element.style[styleProperty] = properties.style[styleProperty];
          }
        }
        else {
          element[property] = properties[property];
        }
      }
    }
    if (parentNode != null) {
      parentNode.appendChild(element);
    }
    return element;
  },
  /**
   * Function: replaceTextElement
   * Replace a text node in the DOM.
   * Properties:
   *   text - the text for the node.
   *   parentNode - the parent node.
   *   checkAcceleratorKeys - if true then check for accelerator key codes.
   */
  replaceTextElement: function(text, parentNode, checkAcceleratorKeys) {
    if (parentNode == null) { return; }
    for ( var j = parentNode.childNodes.length - 1; j >= 0; j--) {
      parentNode.removeChild(parentNode.childNodes[j]);
    }
    if (text != null) {
      this.createTextElement(text, parentNode, checkAcceleratorKeys);
    }
  },
  /**
   * Function: createTextElement
   * Create a text node in the DOM.
   * Properties:
   *   text - the text for the node.
   *   parentNode - the parent node.
   *   checkAcceleratorKeys - if true then check for accelerator key codes.
   */
  createTextElement: function(text, parentNode, checkAcceleratorKeys) {
    if (text == null || parentNode == null) { return; }

    // look in text for accelerator keys and new lines.
    text = text.replace(/\r/g, "");
    text = text.replace(/\n/g, "<proiv-br>");
    text = text.replace(/&amp;/g, "&");
    while (true) {
      var matches = (checkAcceleratorKeys) ? text.match(/(^.*?)(&[^\s]|<proiv-br>)(.*$)/i): text.match(/(^.*?)(<proiv-br>)(.*$)/i);
      if (matches != null && matches.length > 0) {
        parentNode.appendChild(document.createTextNode(matches[1]));
        if (matches[2].substr(0, 1) == "&") {
          // an accelerator string.
          var element = this.createElement("span", parentNode, {
            className: "proiv-accelerator"
          });
          element.appendChild(document.createTextNode(matches[2].substr(1, 1)));
          text = matches[3];
        }
        else if (matches[2] == "<proiv-br>") {
          // new line code.
          this.createElement("br", parentNode);
          text = matches[3];
        }
      }
      else {
        parentNode.appendChild(document.createTextNode(text));
        break;
      }
    }
  },

  //------------------- node layout function ---------------------------------
  
  /*
   * Function: getNodeLeftPosition
   * Parameters:
   *   node - the node object.
   * Returns:
   *   The left pixel position of the node in the page.
   */
  getNodeLeftPosition: function (node) {
    var left = 0;
    if (node.offsetParent) {
      while (node.offsetParent) {
        left += node.offsetLeft;
        node = node.offsetParent;
      }
    }
    else if (node.x) { left += node.x; }
    return left;
  },
  /*
   * Function: getNodeTopPosition
   * Parameters:
   *   node - the node object.
   * Returns:
   *   The top pixel position of the node in the page.
   */
  getNodeTopPosition: function (node) {
    var top = 0;
    if (node.offsetParent) {
      while (node.offsetParent) {
        top += node.offsetTop;
        node = node.offsetParent;
      }
    }
    else if (node.y) { top += node.y; }
    return top;
  },
  /*
   * Function: getNodeWidth
   * Parameters:
   *   node - the node object.
   * Returns:
   *   The current width of the node in the page.
   */
  getNodeWidth: function (node) {
    return node.offsetWidth;
  },
  /*
   * Function: getNodeHeight
   * Parameters:
   *   node - the node object.
   * Returns:
   *   The current height of the node in the page.
   */
  getNodeHeight: function (node) {
    return node.offsetHeight;
  },
  /*
   * Function: getBrowserWidth
   * Returns:
   *   The current width of the browser window.
   */
  getBrowserWidth: function () {
    if (typeof(window.innerWidth) == 'number') {
      return window.innerWidth;
    } 
    else if(document.documentElement && document.documentElement.clientWidth) {
      return document.documentElement.clientWidth;
    } 
    else if(document.body && document.body.clientWidth) {
      return document.body.clientWidth;
    }
  },
  /*
   * Function: getBrowserHeight
   * Returns:
   *   The current height of the browser window.
   */
  getBrowserHeight: function () {
    if (typeof(window.innerWidth) == 'number') {
      return window.innerHeight;
    } 
    else if(document.documentElement && document.documentElement.clientHeight) {
      return document.documentElement.clientHeight;
    } 
    else if(document.body && document.body.clientHeight) {
      return document.body.clientHeight;
    }
  }
};

/*
* Constructor: EventObject
* Parameters:
*   event - a browser event object.
*/
EventObject = function(event) {
  this.getEventInfo(event);
}
EventObject.prototype = {
  altKey:     false,  // true if Alt key pressed.
  capsLock:   false,  // the current capsLock state.
  ctrlKey:    false,  // true if Ctrl key pressed.
  consumed:   false,  // true if the event has been consumed.
  event:      null,   // the event object.
  isIE:       false,  // true if this is an IE event.
  keyCode:    0,      // the code of the key pressed.
  pageX:      0,      // the mouse X position.
  pageY:      0,      // the mouse Y position.
  shiftKey:   false,  // true if Shift key pressed.
  target:     null,   // the event target node.
  
  /*
   * Function: getEventInfo
   * This function handles the different event objects supplied by different browsers.
   * Parameters:
   *   event - a browser event object.
   * Returns:
   *   this object.
   */
  getEventInfo: function (event) {
    if (event == null || window.event != null) {
      // IE event.
      this.isIE     = true; 
      this.event    = window.event;
      this.target   = window.event.srcElement;
      this.keyCode  = window.event.keyCode;
      this.ctrlKey  = window.event.ctrlKey;
      this.shiftKey = window.event.shiftKey;
      this.altKey   = window.event.altKey;
      this.pageX    = window.event.clientX;
      this.pageY    = window.event.clientY;
    }
    else if (event != null) {
      // other browsers. 
      this.isIE     = false; 
      this.event    = event;
      this.target   = event.target;
      this.keyCode  = event.keyCode;
      this.ctrlKey  = event.ctrlKey;
      this.shiftKey = event.shiftKey;
      this.altKey   = event.altKey;
      this.pageX    = event.pageX;
      this.pageY    = event.pageY;
    }
    else {
      this.event = {};
    }
    return this;
  },
  /*
   * Function: consumeEvent
   * Tries to stop this event from doing anything else.
   */
  consumeEvent: function () {
    this.preventDefault();
    this.stopPropagation();
    this.consumed = true;
  },
  /*
   * Function: preventDefault
   * Tries to stop this event from performing its default action.
   */
  preventDefault: function () {
    if (this.event.preventDefault != null) { this.event.preventDefault(); }
    if (this.isIE) {
      try { this.event.returnValue = false; }
      catch (e) {}
    }
  },
  /*
   * Function: stopPropagation
   * Tries to stop this event from propagating.
   */
  stopPropagation: function () {
    if (this.event.stopPropagation != null) { this.event.stopPropagation(); }
    if (this.isIE && this.event.preventBubble != null) { this.event.preventBubble(); }
    try { this.event.cancelBubble = true; }
    catch (e) {}
  }
};

