﻿/*
  Knowmax State list Utility Unit for JavaScript  

  Usage: Include in page and call .initialize() once. One
         initialized instance can be used for all child pages.
         Child pages just include the script reference and 
         will automatically locate the initialized parent
         instance of the KMStateList.

  version 1.1 - September 11 2007
    - New detection algorith for initialized instance of
      KMStateList. Element with special id no longer used.
    - Updated KMStateList.values() method to attemp to
      locate the valuelist instance of the global statelist
      that was initialized.
    - Fixed infinite loop in case no page with session page 
      element exists.

  version 1.0 - January 2007
    - initial version
    
  (c) 2007 Knowmax
*/

// Value object class.
function KMValueObject(id, value)
{  
  this.id = id;
  this.value = value;
}

KMValueObject.prototype.isValid = function()
{
  return ((this.id != null) && (this.id != ""));
}

// Value list class.
function KMValueList()
{
  this.list = new Array(); 
  this.uniquevalues = false; 
}

// Internally used to look up KMValueObject by id.
KMValueList.prototype._valueObjectById = function(id)
{
  if ((id == null) || (id == "")) {  
    return null;
  } else {        
    for (index = 0; index < this.list.length; index++) {    
      if (this.list[index].id == id) {
        return this.list[index];        
      }
    }
    
    return null;
  }
}

// Add given value pair to list. Obeys uniquevalues setting of list.
KMValueList.prototype.add = function(id, value)
{
  var valueobject = new KMValueObject(id, value);
  
  if (valueobject.isValid()) {
    if (this.uniquevalues) {
      if (!this.valueExists(id)) {
        return this.list.push(valueobject);  
      } else {
        return -1;
      }
    } else {
      return this.list.push(valueobject);  
    }
  } else {
    return -1;
  }
}

// Remove value with given id from list. Returns whether value pair with given id could be removed.
KMValueList.prototype.remove = function(id)
{
  var newlist = new Array();  
  var result = false;
  
  for (index = 0; index < this.list.length; index++) {
    if (this.list[index].id == id) {
      result = true;
    } else {
      newlist.push(this.list[index]);
    }
  }
  
  if (result) {
    this.list = newlist;
  }
  
  return result;
}

// Update existing value for value pair with given id. In case the value pair with the
// given id does not exists, this method will call the add() method.
KMValueList.prototype.update = function(id, value)
{
  var valueobject = this._valueObjectById(id);
  if (valueobject != null) {
    valueobject.value = value;
    return true;
  } else {
    return this.add(id, value);
  }  
}

// Returns value for value pair with given id. Returns null in case value is unavailable.
KMValueList.prototype.valueOf = function(id)
{
  var valueobject = this._valueObjectById(id);
  if (valueobject != null) {
    return valueobject.value;
  } else {
    return null;
  }  
}

// Determine whether value pair with given id exists.
KMValueList.prototype.valueExists = function(id)
{
  var valueobject = this._valueObjectById(id);
  if (valueobject != null) {
    return true;
  } else {
    return false;
  }  
}

var KMStateList = {  
  majorversion: function() {
    return 1;
  },
  
  minorversion: function() {
    return 1;
  },
  
  version: function() {
    return this.majorversion() + "." + this.minorversion();  
  },
  
  // Get access to instance of KMValueList. If this instance of KMStateList
  // is initialized a reference to the local value list will be returned. Otherwise
  // an attempt is made to locate the statelist instance of the page that did
  // initialize the statelist.
  values: function() {
    if (this._statelist != null) {
      return this._statelist;
    } else {
      var statelist = this.getStateList();
      if ((statelist != null) && (statelist._statelist)) {
        return statelist._statelist; 
      } else {
        return null; 
      }              
    }
  },  
  
  // Internally called to set default values.
  _construct: function() {
    this._statelist = null;
    this._initialized = false;
    this._statepageinstance = null;
    this._statelistinstance = null;    
  },
  
  // Call to initialize KMStateList. Only one page (the parent) should call this method. All
  // child pages will automatically use this instance. 
  initialize: function() {
    if (!this._initialized) {
      // Check whether a parent page already has an initialized instance
      if (KMStateList.getStatePage() != null) {
        // This is a child page, a parent was already initalized, just
        // return true so no harm is caused.
        return true; 
      } else {     
        this._statelist = new KMValueList();
        this._statelist.uniquevalues = true;
        this._initialized = true;
        return true;
      }
    } else {
      return true; 
    }
  },
  
  // Checks whether this instance of KMStateList is initialized.
  initialized: function() {
    return this._initialized;
  },
  
  // Looks up reference to (parent) page with an initialized instance 
  // of KMStateList. Iterates parent pages up to a maximum of 15 levels.
  getStatePage: function() {  
    if (this._statepageinstance != null) {
      return this._statepageinstance; 
    } else {       
      if ((self.KMStateList) && 
          (self.KMStateList.initialized())) {
        this._statepageinstance = self;
        return self;    
      } else if (parent) {
        try {
          var count = 0;
          var documentlevel = parent;        
          while ((documentlevel) && (count < 15)) {          
            if ((documentlevel.KMStateList) && 
                (documentlevel.KMStateList.initialized())) {            
              this._statepageinstance = documentlevel;
              return documentlevel;
            } else if ((documentlevel.parent) && 
                       (documentlevel != documentlevel.parent)) {
              documentlevel = documentlevel.parent;
            } else {
              documentlevel = null;          
            }
            count++;
          }
        } catch(err) {
          return null;
        }            
      }
    }
    
    return null;       
  },  
  
  // Looks up reference to an initialized instance of KMStateList
  // that could be used globally.
  getStateList: function() {
    if (this._statelistinstance) {
      return this._statelistinstance;
    } else {    
      var statepage = this.getStatePage();
      if (statepage) {
        try {
          if (statepage.KMStateList.initialized()) {
            this._statelistinstance = statepage.KMStateList;
            return this._statelistinstance;
          } else {
            return null;
          }
        } catch(err) {
          return null;
        }
      } else {
        return null;
      }
    }
  }
}  

KMStateList._construct();
