//These ArrayList functions support the observer framework
function ArrayList() { this.aList = []; }      
ArrayList.prototype.Count = function() { return this.aList.length; }
ArrayList.prototype.Clear = function() { this.aList = []; }
ArrayList.prototype.Add = function(object) { return this.aList.push( object ); }
ArrayList.prototype.GetAt = function(index) {
   if( index > -1 && index < this.aList.length )
      return this.aList[index];
   else
      return undefined;
}      
ArrayList.prototype.RemoveAt = function (index) {
   var m_count = this.aList.length;
   if ( m_count > 0 && index > -1 && index < this.aList.length ) {
      switch( index ) {
         case 0:
            this.aList.shift();
            break;
         case m_count - 1:
            this.aList.pop();
            break;
         default:
            var head   = this.aList.slice( 0, index );
            var tail   = this.aList.slice( index + 1 );
            this.aList = head.concat( tail );
            break;
      }
   }
}
ArrayList.prototype.Insert = function (object, index) {
   var m_count       = this.aList.length;
   var m_returnValue = -1;
   if ( index > -1 && index <= m_count ) {
      switch(index) {
         case 0:
            this.aList.unshift(object);
            m_returnValue = 0;
            break;
         case m_count:
            this.aList.push(object);
            m_returnValue = m_count;
            break;
         default:
            var head      = this.aList.slice(0, index - 1);
            var tail      = this.aList.slice(index);
            this.aList    = this.aList.concat(tail.unshift(object));
            m_returnValue = index;
            break;
      }
   }
   return m_returnValue;
}
ArrayList.prototype.IndexOf = function(object, startIndex) {
   var m_count       = this.aList.length;
   var m_returnValue = - 1;
   if ( startIndex > -1 && startIndex < m_count ) {
      var i = startIndex;
      while( i < m_count ) {
         if ( this.aList[i] == object ) {
            m_returnValue = i;
            break;
         }
         i++;
      }
   }
   return m_returnValue;
}
ArrayList.prototype.LastIndexOf = function(object, startIndex) {
   var m_count       = this.aList.length;
   var m_returnValue = - 1;
   if ( startIndex > -1 && startIndex < m_count ) {
      var i = m_count - 1;
      while( i >= startIndex ) {
         if ( this.aList[i] == object ) {
            m_returnValue = i;
            break;
         }
         i--;
      }
   }
   return m_returnValue;
}

// Main UI Web class
UIWeb = function(appletId) {
    this.appletId = appletId;
    this.application = new UIWeb.Application(this);
    this.process = new UIWeb.ObservedValue(this);
    this.shouldConfirmExit = true;
    this.environment = new UIWeb.ObservedValue(this);
    
    window.onbeforeunload = this.confirmExit;
}
UIWeb.prototype.applet;
UIWeb.prototype.appletId;
UIWeb.prototype.environment;
UIWeb.prototype.application;
UIWeb.prototype.process;
UIWeb.prototype.shouldConfirmExit;

// Returns true if the applet exists in the DOM
UIWeb.prototype.appletExists = function() {
    if (this.applet == null) {
        this.applet = document.getElementById(this.appletId);
    }
    
    return (this.applet != null);
}

// Returns true if the applet is listening for requests
UIWeb.prototype.isAvailable = function() {
    return (this.appletExists() && this.application.getValue() != null && this.application.getValue() != "");
}

UIWeb.prototype.confirmExit = function() {
    if (_uiWeb.isAvailable() && _uiWeb.shouldConfirmExit) {
		return "Leaving will cause you to lose any unsaved work.";
    }
}

// Uses CSS to hide the applet
UIWeb.prototype.hide = function() {
    if (this.appletExists()) {
        this.applet.style.visibility = "hidden";
    }
}

// Uses CSS to make the applet visible
UIWeb.prototype.show = function() {
    if (this.appletExists()) {
        this.applet.style.visibility = "visible";
    }
}

// Execute a process in the applet, using the application and mnemonic
UIWeb.prototype.runProcess = function(app, mnemonic) 
{
    request = new UIWeb.ProcessRequest(app, mnemonic);
    request.send();
}

// This function must be standalone, or the applet cannot find it.
// Handles all callbacks from the UI Web applet.  If additional response types are implemented, they
// can be identified and handled in here.
uiWebCallback = function(response) {
    try {

        response = JSON.decode(response);
        
        _uiWeb.application.setValue(response.application);
        
  	    if (response.id == "STATUS") {
            _uiWeb.process.setValue(response.arguments.process);
            _uiWeb.environment.setValue(response.environment);    
	    }
    }
    catch (error) {
        alert("Invalid response from applet: \n\n"+error);
    }
};

// Base class for all requests to the UI Web applet.
// id - unique ID for the request type
// arguments - object containing any custom args for the request type
UIWeb.Request = function(id, arguments) {
    this.id = id;
    if (arguments != null) {
        this.arguments = arguments;
    }    
      
    return this;
}
UIWeb.Request.prototype.id;
UIWeb.Request.prototype.arguments;
UIWeb.Request.prototype.callback;

// Sends request to the applet
UIWeb.Request.prototype.send = function() {
    if (_uiWeb.isAvailable()) {
        _uiWeb.shouldConfirm = true;
		_uiWeb.applet.raiseScriptEvent("WebExchange", JSON.encode(this));
    }
    else {
        throw "The applet is not ready to receive requests";
    }
}

// Request to start a process in the applet
// application - The application of the process
// process - The mnemonic of the process
UIWeb.ProcessRequest = function(application, process) {
    arguments = {"application":application, "process":process};
    UIWeb.Request.call(this, "PROCESS", arguments);
}
UIWeb.ProcessRequest.prototype = new UIWeb.Request();

// Request to switch applications in the applet
// application - Mnemonic of the application to open
UIWeb.LoadApplicationRequest = function(application) {
    arguments = {"application":application, "process":application+"-"};
    UIWeb.Request.call(this, "PROCESS", arguments);
}
UIWeb.LoadApplicationRequest.prototype = new UIWeb.Request();


// Used to register observers/event handlers for a custom event.
// Observers are functions that take a single parameter ('context').
UIWeb.ObservedObject = function() {
    this.observers = new ArrayList();
}
UIWeb.ObservedObject.prototype.observers;

// When the event occurs, this function will notify all observers
UIWeb.ObservedObject.prototype.fire = function(context) {
   var m_count = this.observers.Count();
   for( var i = 0; i < m_count; i++ )
      this.observers.GetAt(i).call(this, context);
}

// Add a delegate to the list of observers
UIWeb.ObservedObject.prototype.addObserver = function(observer) {
   this.observers.Add( observer );
   this.onAddObserver(observer);
}
// Can be overridden to take action when an observer is added
UIWeb.ObservedObject.prototype.onAddObserver = function(observer) {}

// Remove a delegate from the list of observers
UIWeb.ObservedObject.prototype.removeObserver = function(observer) {
   this.observers.RemoveAt(this.observers.IndexOf(observer, 0));
   this.onRemoveObserver(observer);
}
// Can be overridden to take action when an observer is removed
UIWeb.ObservedObject.prototype.onRemoveObserver = function(observer) {}

// Extends ObservedObject to fire an event whenever an object's value changes
UIWeb.ObservedValue = function() {
    UIWeb.ObservedObject.call(this);
}
UIWeb.ObservedValue.prototype = new UIWeb.ObservedObject();
UIWeb.ObservedValue.prototype.value;

// Get the value of the object being watched
UIWeb.ObservedValue.prototype.getValue = function() { return this.value; }
// Set the object's value to a new value, and fire an event to notify any observers
UIWeb.ObservedValue.prototype.setValue = function(newValue) {
    if (this.value == null || this.value != newValue) {
        this.value = newValue;
        this.fire(newValue);
    }
}

// The current application of the applet is a value that can be observed
UIWeb.Application = function() 
{
    UIWeb.ObservedValue.call(this);
}
UIWeb.Application.prototype = new UIWeb.ObservedValue();
UIWeb.Application.prototype.parent;

// Ask the applet to load a new application.  (This does not change the value.  The
// value only changes when the applet confirms that application has changed.)
UIWeb.Application.prototype.load = function(newApp) 
{
    req = new UIWeb.LoadApplicationRequest(newApp);
    req.send();
}

var _uiWeb = new UIWeb("wapplet");

/* Set UI Web Title Bar */
function setUIWebTitle(environment,application) {
	document.title =  environment + " - "+ application + " - Datatel Colleague";
}

/* Initialization for Standalone UI Web */
function standaloneInit() {
	window.onbeforeunload = function() { return "Leaving will cause you to lose any unsaved work."; };
}

//_uiWeb.application.addObserver(setUIWebTitle);