/*****************************************************************************
 * $Header$
 * $Author$
 * $Revision$
 * $Date$
 *
 * UI controller.
 *
 * Copyright: Neolane 2001-2007
 *****************************************************************************/

// 
// browser detection
// 

// browser engine name
var isGecko = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsGecko = (ua.indexOf('gecko') != -1 && ua.indexOf('safari') == -1);
  return function(){return bIsGecko;}
}();

var isAppleWebKit = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsAppleWebKit = (ua.indexOf('applewebkit') != -1);
  return function(){return bIsAppleWebKit;}
}();

// browser name
var isKonqueror = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsKonqueror = (ua.indexOf('konqueror') != -1);
  return function(){return bIsKonqueror;}
}();

var isSafari = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsSafari = (ua.indexOf('safari') != - 1);
  return function(){return bIsSafari;}
}();

var isOmniweb = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsOmniweb = (ua.indexOf('omniweb') != - 1);
  return function(){return bIsOmniweb;}
}();

var isOpera = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsOpera = (ua.indexOf('opera') != -1);
  return function(){return bIsOpera;}
}();

var isAol = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsAol = (ua.indexOf('aol') != -1);
  return function(){return bIsAol;}
}();

var isIE = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsIE = (ua.indexOf('msie') != -1 && !isOpera() && (ua.indexOf('webtv') == -1) );
  return function(){return bIsIE;}
}();

var isMozilla = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsMozilla = (isGecko() && ua.indexOf('gecko/') + 14 == ua.length);
  return function(){return bIsMozilla;}
}();

var isNS = function()
{
  var ua = navigator.userAgent.toLowerCase(); 
  var bIsNS = ( isGecko() ? (ua.indexOf('netscape') != -1) : ( (ua.indexOf('mozilla') != -1) && !isOpera() && !isSafari() && (ua.indexOf('spoofer') == -1) && (ua.indexOf('compatible') == -1) && (ua.indexOf('webtv') == -1) && (ua.indexOf('hotjava') == -1) ) );
  return function(){return bIsNS;}
}();

/** Helper function used to fix transparency bug under IE */
function IEFixImage()
{
  if ( this.src.indexOf(".png") != -1 )
  { // fix the PNG transparency bug under IE
    var src = this.src;
	  this.src = "/xtk/img/blank.gif";
	  this.runtimeStyle.filter = "progid:DXImageTransform.Microsoft." +
				  "AlphaImageLoader(src='" + src + "',sizingMethod='scale')";
	}
  else if ( this.src.indexOf(".bmp") != -1 )
    // make magenta color transparent
    this.style.filter = "progid:DXImageTransform.Microsoft.Chroma(color=#FF00FF)";
}

function Navigator() {}

Navigator.prototype.fixImage = function(img)
{
  if (isIE())
    img.onload = IEFixImage;
}

/** Constructor
  *
  */
function UIController()
{
  this.ctx = null                       /* the XML context */
  this.soapRouterUrl = window.location.protocol + "//" + window.location.host  + "/nl/jsp/soaprouter.jsp"
   
/** Map of observers (using xpath as key).
  * 
  * Observer properties are:
  *
  * object: object to notify.
  * method: method of the object 'object' to call.
  * name:   name of the observer (must be unique). Used to avoid to notify the 
  *         observer which has modified the context. 
  * 
  * Remarks:
  * - if the object 'object' has a method onSubmit(), that method is 
  *   automatically called on form submission. */
  this.observers = new Hash()
  
  this.childrenObservers = new Array()  /* observers registered on OBSERVE_CHILDREN mode */
}

UIController.prototype = new Navigator()

UIController.prototype.OBSERVE_XPATH      = 1
UIController.prototype.OBSERVE_CHILDREN   = 2

/** Register an XPATH observer.
  *
  * @xpath  XPATH to observe.
  * @object object to notify.
  * @mode   registration mode (OBSERVE_XPATH or OBSERVE_CHILDREN). */ 
UIController.prototype.registerObserver = function(xpath, obj, method, name, mode)
{
  var observer = { "object": obj, "method": method, "name": name, "mode": mode }
  if ( mode == this.OBSERVE_XPATH )
  {
    var registration = this.observers.get(xpath)
    if ( registration == undefined )
    { // first registration on this xpath
      // => we create a array to store registrations
      registration = new Array(observer)
      this.observers.set(xpath, registration)
    }
    else
      registration.push(observer)
  }
  else
  {
    observer.xpath = xpath
    this.childrenObservers.push(observer)
  }
  
  return observer
}

/** Notify all observers.
  *
  * @startPath      if defined limit the notification of observers registered
  *                 on a path starting by startPath. 
  * @value          new value for the given XPath. Can be undefined.
  * @ignoreObserver name of an observer to ignore. */
UIController.prototype.notifyAllObservers = function(startPath, value, ignoreObserver)
{
  for (var xpath in this.observers.items)
  {
    if ( startPath != undefined && xpath.indexOf(startPath) != 0 )
      // skip this xpath
      continue
      
    var observers = this.observers.get(xpath)
    var newValue = value
    if ( newValue == undefined || xpath!=startPath)
      // get value from the context
      newValue = getXPathValue(this.ctx, xpath)
    
    for (var i=0; i < observers.length; i++)
    {
      // get the value from the context
      var observer = observers[i]
      if ( ignoreObserver != observer.name )
        // notify the observer
        observer.method.call(observer.object, xpath, newValue)
    }
  }
  
  // notify observers registered on mode OBSERVE_CHILDREN
  var nObservers = this.childrenObservers.length;
  for (var i=0; i < nObservers; i++)
  {
    var observer = this.childrenObservers[i]
    if ( ignoreObserver != observer.name && (startPath == undefined || startPath.indexOf(observer.xpath) == 0) )
      observer.method.call(observer.object, startPath, value)
  }
}

/** Set a value in the context.
  *
  * @xpath  XPATH to modify.
  * @value  value to set. */ 
UIController.prototype.setValue = function(xpath, value, ignoreObserver, asCDATA)
{
  setXPathValue(this.ctx, xpath, value, asCDATA)
  this.notifyAllObservers(xpath, value, ignoreObserver)
}

/** Get a value from the context.
  *
  * @xpath  XPATH to get.
  * @return the value. */
UIController.prototype.getValue = function(xpath)
{
  return getXPathValue(this.ctx, xpath)
}

/** Show or hide a cell containing a container, an input or a static.
  *
  * @name name of the cell to hide.
  * @visible true or false. */
UIController.prototype.setCellVisibility = function(name, visible)
{
  function show(node, visible)
  {
    if ( node != null && node.style != undefined )
      node.style.display = visible ? "" : "none";
  }
  
  show(document.getElementById(name + "-label-left"), visible);
  show(document.getElementById(name + "-cell"), visible);
  show(document.getElementById(name + "-label-right"), visible);
}

/** Submit the page to the server.
  *
  * @strAction      action at the origin of the submition (next, previous, validate, refresh). 
  * @strTarget      target for the form submission (_blank, _parent, ...).
  * @strTransition  name of the ougoing transition in diagram design. */
UIController.prototype.submit = function(strAction, strTarget, strTransition)
{
  // display loading block
  var divOverToDisable = document.getElementById("overToDisable")
  if( divOverToDisable != null )
    divOverToDisable.style.display = ''
  var divLoading = document.getElementById("divLoading")
  if( divLoading != null )
    divLoading.style.display = ''   

  // call the method onSubmit for all registered observers
  for (var xpath in this.observers.items)
  {
    var observers = this.observers.get(xpath)
    for (var i=0; i < observers.length; i++)
      if ( observers[i].object.onSubmit != undefined )
        if ( observers[i].object.onSubmit.call(observers[i].object) == false )
          return false
  }
  
  var nObservers = this.childrenObservers.length;
  for (var i=0; i < nObservers; i++)
  {
    var observer = this.childrenObservers[i]
    if ( observer.object.onSubmit != undefined )
      if ( observer.object.onSubmit.call(observer.object) == false )
        return false
  }

  var formObject = document.getElementById("page-form");
  formObject["action"].value = strAction;
  formObject["ctx"].value    = toXMLString(this.ctx)
  if( firstChildElement(this.ctx) != undefined  
   && firstChildElement(this.ctx).getAttribute("_preview") == "true" )
  {
    var input = document.createElement("input");
    input.type = "hidden";
    input.name = "_preview";
    input.value = "true";
    formObject.appendChild(input);
    var uuid = firstChildElement(this.ctx).getAttribute("_uuid")
    if( uuid != null )
    {
      input = document.createElement("input")
      input.type = "hidden"
      input.name = "_uuid"
      input.value = uuid
      formObject.appendChild(input)
    }
    var debug = firstChildElement(this.ctx).getAttribute("_debug")
    if( debug != null )
    {
      input = document.createElement("input")
      input.type = "hidden"
      input.name = "_debug"
      input.value = "true"
      formObject.appendChild(input)
    }
  }
  if ( strTransition != undefined )
    formObject["transition"].value = strTransition
  
  if( strTarget != undefined && strTarget.length > 0 )
    formObject.target = strTarget;
    
  formObject.submit();
  return true;
}

UIController.prototype.getSessionToken = function()
{
  return getXPathValue(this.ctx, "/ctx/__sessiontoken")
}
