﻿var MAGMA = {
  EVENT: {
    APPLICATION: {
      STARTINFOAVAILABLE: "application:startinfoavailable", // 0: internally used to provide loader with optionally received startup info
      PRELOADAUTHORIZED: "application:preloadauthorized", // 1: before application load is authorized, initialize stuff needed for loader
      LOADAUTHORIZED: "application:loadauthorized", // 2: application load is authorized, loader should start
      PRELOADING: "application:preloading", // 3: before frames are loaded      
      PRELOADED: "application:preloaded", // 4: frames are loaded
      LOADED: "application:loaded", // 5: frames are loaded     
      START: "application:start", // 6: ready, frames are loaded
      LOADPROGRESS: "application:loadprogress" // a registered frame was loaded
    },
    LANGUAGE: {
      UPDATEFAILURE: "language:updatefailure"
    }    
  },
  COMPILATION: {
    SERVER: "magmaserver",
    CLIENT: "magmaclient"
  }
}
 
var MagmaLoader = new KMMagmaLoader();
var StartupInfo = null;
var ApplicationHealth = null;
Event.observe(window, "load", OnLoaderInitializeHealth);   

function OnLoaderInitializeHealth()
{    
  if (self.KMMagmaHealth) {      
    ApplicationHealth = new KMMagmaHealth(
      Values.User.Sid, 
      Values.Application.Module,
      document);
    ApplicationHealth.Start();  
  }
}

function KMMagmaLoader()
{
  var _frameCount = 0;
  var _frameList = new Array(); 
  
  this.Start = _start;
  this.RegisterFrame = _registerFrame;
  this.GetFrameCount = _getFrameCount;
  this.GetFramePosition = _getFramePosition;
  this.CheckLoaded = _checkLoaded;
  this.RegisterFrameFromDiv = _registerFrameFromDiv; 
    
  _create();
  function _create()
  {
    Event.observe(document, MAGMA.EVENT.APPLICATION.STARTINFOAVAILABLE, _OnStartUpInfoAvailable);
  }
  
  function _OnStartUpInfoAvailable(event)
  {    
    if (event.memo) {
      StartupInfo = event.memo;      
    }
  }
  
  function _start()
  {     
    _frameCount = 0;
    _framePosition = 0; 
        
    document.fire(MAGMA.EVENT.APPLICATION.PRELOADING);    
    if (_frameCount == 0) {
      alert("No frames specified.");
    } else {
      _reportProgress();
      window.setTimeout("MagmaLoader.CheckLoaded();", 100);
    }
  }
  
  function _registerFrameFromDiv(frame, div)
  {   
    frame = $(frame);
    div = $(div);
        
    if ((div) && (frame)) {
      var iframe = (frame.contentWindow) ? frame.contentWindow : (frame.contentDocument.document) ? frame.contentDocument.document : frame.contentDocument;      
      if (iframe) {
        _registerFrame(frame);
        iframe.document.open();   
        var html = div.innerHTML;
        html = html.replace(/KMHTML/gi, "HTML");
        html = html.replace(/KMHEAD/gi, "HEAD");
        html = html.replace(/KMLINK/gi, "LINK");
        html = html.replace(/KMSCRIPT/gi, "SCRIPT");
        html = html.replace(/KMBODY/gi, "BODY");
                       
        iframe.document.write(html);      
        iframe.document.close();    
      }
    }
  }
   
  function _registerFrame(frame, url)
  {    
    if (typeof frame == "string") {
      frame = $(frame);
    }
    
    if (frame) {            
      var varregistered = false;
      eval("if (typeof " + frame.name + "_loaded == 'undefined') { " +
        "alert('Frame loaded variabele not defined: " + frame.name + "_loaded'); } else { " +
        frame.name + "_loaded = false; varregistered = true; }");
            
      if (varregistered) {      
        _frameCount++;
        _frameList.push(frame);
        Event.observe(frame, "load", _frameLoaded);
        if ((url != null) && (url !== "")) {
          frame.src = url;
        }      
      }
    }  
  }
  
  function _frameLoaded(event)
  {   
    if ((event) && (event.target) && (event.target.name)) {
      eval(event.target.name + "_loaded = true;");
    }   
  }
  
  var _passCount = 0;
  function _checkLoaded()
  {
    if (_frameList) {
      var loadedcount = 0;  
      try {         
        _frameList.each(function(frame) {
          eval("if (" + frame.name + "_loaded) { loadedcount++; }");
        });
      } catch(ex) {      
      }  
      
      _framePosition = loadedcount;
      _reportProgress();
      if (_framePosition >= _frameCount) {    
        _loaded();
      } else {
        _passCount++;
        if (_passCount > (6000 / 250)) {
          // Still not loaded after n seconds, attempt raw start
          alert("Time out while loading registered frames. Attempting raw start...");
          _loaded();
        } else {                
          window.setTimeout("MagmaLoader.CheckLoaded();", 250);
        }
      }        
    }
  }
  
  function _reportProgress()
  {
    document.fire(MAGMA.EVENT.APPLICATION.LOADPROGRESS, {Count: _frameCount, Position: _framePosition});
  }
  
  function _loaded()
  {      
    try {
      if (!Proxy.Initialize()) {
        alert("Unable to initialize proxy.");
      } else {         
        // Call OnApplicationPreLoaded on all registered frames (and childs)            
        _frameList.each(function(frame) {                    
          _iterateFrames(frame.contentWindow, _callOnApplicationPreLoaded);
        });        
        //_callOnApplicationPreLoaded(Proxy.GetContext());
        document.fire(MAGMA.EVENT.APPLICATION.PRELOADED); 
        
        // Call OnApplicationLoaded on all registered frames (and childs)             
        _frameList.each(function(frame) {                    
          _iterateFrames(frame.contentWindow, _callOnApplicationLoaded); 
        });
        //_callOnApplicationLoaded(Proxy.GetContext());
        
        _frameList = null;
        document.fire(MAGMA.EVENT.APPLICATION.LOADED);      
        document.fire(MAGMA.EVENT.APPLICATION.START);                 
        Proxy.Delta.Execute(new Hash({kernelaction: "delayedrequest"})); 
        window.setTimeout("_logBrowserFeatures();", 1000);
      }
    } catch(ex) {
      alert("Exception while initializing proxy. " + ex.message);
    }
  }  
  
  function _callOnApplicationLoaded(context)
  {    
    if ((context != null) && (Object.isFunction(context.OnApplicationLoaded))) {  
      try {    
      context.OnApplicationLoaded(self);       
      } catch(ex) {
        var title = "unknown";
        if (context.location) {
          title = context.location;
        }       
        alert("OnApplicationLoaded Exception for " + title + " - " + ex.message);
      }
    }
  }
  
  function _callOnApplicationPreLoaded(context)
  {
    if ((context != null) && (Object.isFunction(context.OnApplicationPreLoaded))) {  
      try {    
        context.OnApplicationPreLoaded(self);      
      } catch(ex) {        
        var title = "unknown";
        if (context.location) {
          title = context.location;
        }        
        alert("OnApplicationPreLoaded Exception for " + title + " - " + ex.message);
      }
    }
  }
  
  function _iterateFrames(context, callBackMethod) 
  {
    if ((context != null) && (callBackMethod != null)) {
      callBackMethod(context);
      
      for (var index = 0;index < context.frames.length;index++) {
        _iterateFrames(context.frames[index], callBackMethod);
      }
    }
  }  
  
  function _getFrameCount()
  {
    return _frameCount;
  }
  
  function _getFramePosition()
  {
    return _framePosition;
  }  
}

function _logBrowserFeatures()
{         
  try {
    if ((self.KMBrowserFeatures) && (self.Proxy) && (self.KMMagmaLogging) &&
        (Proxy.GetValues().Application.IsServer) &&        
        (Proxy.GetValues().Session.BrowserFeaturesLogged != "true") &&           
        (KMBrowserFeatures.Initialize())) {
      var list = new Hash({ session_browserfeatureslogged: "true" });
      list = list.merge(KMBrowserFeatures.GetBrowserFeatures());        
      
      new KMMagmaLogging(Proxy.GetValues().User.Sid, 
        Proxy.GetValues().Application.Module, list);
    }
  } catch(ex) {
  }
}

var Proxy = { 
  Initialize: function()
  {   
    if ((Proxy.IsContext(self)) && (!Proxy.Initialized)) {
      if ((self.Knowmax) && (self.Knowmax.SingleInstanceSupport)) {
        Proxy.SingleInstance = new Knowmax.SingleInstanceSupport(Proxy.GetEventSink());        
      }
    
      Proxy.Initialized = true;             
      return true;
    } 
    return false;    
  },
  Health: null,
  Initialized: false,
  GetContext: function()
  {
    var maxlevels = 10;
    var context = self;
    while ((!Proxy.IsContext(context)) &&
           (maxlevels > 0) && (context != null)) {
      context = context.parent;
      maxlevels--;
    }
    
    if (!Proxy.IsContext(context)) {
      return null;
    } else {
      return context;
    }
  },
  IsContext: function(context)
  {
    return ((context != null) && (context.$) && 
            (Proxy.GetDefaultBodyFromContext(context) != null));
  },
  GetDefaultBodyFromContext: function(context)
  {
    if (context != null) {
      return context.$("DefaultBody");
    } else {
      return null;
    }
  },
  GetEventSink: function()
  {
    var context = Proxy.GetContext();
    if ((context != null) && (context.document)) {
      return context.document;
    } else {
      return null;
    }   
  },  
  GetValues: function() 
  {
    var context = Proxy.GetContext();
    if ((context != null) && (context.Values)) {
      return context.Values;
    } else {
      return null;
    }  
  }, 
  GetStartupInfo: function()
  {
    var context = Proxy.GetContext();
    if ((context != null) && (context.StartupInfo)) {
      return context.StartupInfo;
    } else {
      return null;
    }
  },
  GetConstants: function()
  {
    var context = Proxy.GetContext();
    if (context) {
      return context.MAGMA;
    }
    return null;
  },
  Ajax: {
    Execute: function(request, onSuccess, onFailure, method)
    {      
      if ((request != null) && (!Object.isHash(request))) {
        request = new Hash(request);
      }    
    
      if (Object.isHash(request)) {
        var list = new Hash({ "sid": Proxy.GetValues().User.Sid, "ajax": "true" });	
        list = list.merge(request);
             
        if (typeof method != "string") {
          method = "get";
        }
                  
        try { 
          new Ajax.Request(Proxy.GetValues().Application.Module,
          {
            method: method,
            evalJSON: true,
            parameters: list.toQueryString(),
            onSuccess: function(result) {
              if (Object.isFunction(onSuccess)) {
                onSuccess(result.responseJSON);
              }
            },			
            onFailure: function(result) {		
              if (Object.isFunction(onFailure)) {
                onFailure(result);
              }                        
            }
          });		  
        } catch(ex) {
          if (Object.isFunction(onFailure)) {
            onFailure(result);
          } 
        }     
      } else if (Object.isFunction(onFailure)) {
        onFailure();
      }       
    }
  },
  Delta: {
    Execute: function(request, frame, readOnly)
    {          
      if ((frame != null) && (typeof frame == "string")) {
        frame = Proxy.Frames.ByName(frame);
      } else if ((frame == null) || (typeof frame == "undefined")) {
        frame = Proxy.Frames.Delta();        
      } 
      
      if ((request != null) && (typeof request != "string") && (request.toQueryString)) {
        request = request.toQueryString();
      }
      
      if ((frame) && (request) && (typeof request == "string")) {  
        var readonlyrequest = "";
        if ((typeof readOnly == "boolean") && (readOnly)) {
          readonlyrequest = "&_sro=true";           
        }

        var url;
        if (Proxy.GetValues().Application.IsServer) {        
          url = Proxy.GetValues().Application.RootUrl;
        } else {
          url = Proxy.GetValues().Application.Module;
        }
        
        frame.location.replace(url + "?sid=" + 
          Proxy.GetValues().User.Sid + readonlyrequest + "&" + request);              
        return true;
      } else {
        return false;
      }
    },
    CreateIFrameObject: function()
    {                  
      var frame = Proxy.GetContext().document.createElement("iframe"); 
      Element.hide(frame);         
      Proxy.GetDefaultBodyFromContext(Proxy.GetContext()).appendChild(frame);
      return frame;
    },
    CreateIFrame: function()
    {                 
      var frame = Proxy.Delta.CreateIFrameObject();    
      if (frame) {
        return frame.contentWindow;
      } else {
        return null;
      }
    }    
  },
	Resources: {
	  ReferenceFree: function(id)
		{
		  if (typeof id == "string") {
			  if (Proxy.GetValues().Application.IsClient) {
				  return "?id=" + id + "&action=res";
				} else {
				  return id;
				}
			} else {
			  return null;
			}
		}
	},
  Frames: {
    ByName: function(name)
    {
      return Proxy.Frames._IterateFrames(Proxy.GetContext(), name);
    },
    _IterateFrames: function(context, name)
    {      
      if ((context != null) && (name != null) && (typeof name == "string")) {
        var frame = context.frames[name];
        if (frame != null) {
          return frame;
        } else {        
          for (var index = 0;index < context.frames.length;index++) {
            try {
              frame = Proxy.Frames._IterateFrames(context.frames[index], name);
              if (frame != null) {
                return frame;
              }
            } catch(ex) {
            }
          }
        }
      } 
      return null;
    },  
    ToObject: function(frame)
    {
      if ((frame != null) && (frame.parent)) {        
        return frame.parent.document.getElementById(frame.name);            
      } else {
        return null;
      }
    },
    ToDomFrame: function(frameObject)
    {
      if (Object.isElement(frameObject) != null) {
        return (frameObject.contentWindow) ? frameObject.contentWindow : (frameObject.contentDocument.document) ? frameObject.contentDocument.document : frameObject.contentDocument;
      } else {
        return null;
      }
    },
    ObjectById: function(id)
    {
      if ((id != null) && (typeof id == "string")) {                
        frame = Proxy.Frames.ByName(id);
        if (frame) {
          if (frame.parent) {
            return frame.parent.document.getElementById(frame.name);
          } else {
            return Proxy.GetContext().document.getElementById(id);
          }
        }
      }
      return null;
    }, 
    Delta: function()
    {
      return Proxy.Frames.ByName("deltaframe");
    }
  },
  Application: {
    Reload: function(parameters)
    {    
      if (!Proxy.IsContext(self)) {        
        Proxy.GetContext().Proxy.Application.Reload(parameters);
      } else {                  
        var list = parameters;
        if ((!document.cookie) || (Proxy.GetValues().Application.IsClient)) {
          list = new Hash({"sid": Proxy.GetValues().User.Sid});
        }
        
        if (parameters != null) {
    	 	  list.update(parameters.toObject());                      
        }        
        Proxy.Application.Restart(list, parameters);
      }
    },
    Restart: function(parameters, originalParameters)
    {
      if (!Proxy.IsContext(self)) {        
        Proxy.GetContext().Proxy.Application.Restart(parameters);
      } else {
        var url;
        if (Proxy.GetValues().Application.IsServer) {        
          url = Proxy.GetValues().Application.RootUrl;
        } else {
          url = Proxy.GetValues().Application.Module;
        }        
        
        if (parameters != null) {                    
          url += "?" + parameters.toQueryString();
          if (originalParameters != null) {
            url += "&kmmagmaplatformrequesttype=firstauthorized";          
          }
        }               
        Proxy.GetContext().document.location.replace(url);        
      }
    },
    PostRestart: function(parameters)
    {
      if (!Proxy.IsContext(self)) {        
        Proxy.GetContext().Proxy.Application.PostRestart(parameters);
      } else {            
        var url;
        if (Proxy.GetValues().Application.IsServer) {        
          url = Proxy.GetValues().Application.RootUrl;
        } else {
          url = Proxy.GetValues().Application.Module;
        } 
        
        var form = new Element('form', {method: 'post', action: url});
        if ((parameters != null) && (parameters.each)) {
          parameters.each(function(pair) {
            form.insert(new Element('input',
              {name: pair.key, value: pair.value, type: 'hidden'}));            
          });
        }
        $(document.body).insert(form);
        form.submit();
      }  
    }      
  },
  Storage: {
    Store: function(id, value)
    {
      if (!Proxy.IsContext(self)) {
        Proxy.GetContext().Proxy.Storage.Store(id, value);
      } else {
        Element.store(document, id, value);
      }
    },
    Retrieve: function(id, defaultValue)
    {
      if (!Proxy.IsContext(self)) {
        return Proxy.GetContext().Proxy.Storage.Retrieve(id, defaultValue);
      } else {
        return Element.retrieve(document, id, defaultValue);
      }    
    }
  },
  GAnalytics: {
    GetConfiguration: function()
    {
      if (!Proxy.IsContext(self)) {
        return Proxy.GetContext().Proxy.GAnalytics.GetConfiguration();
      } else {
        return self.GAnalytics;
      }
    },
    GetGaq: function() 
    {
      if (!Proxy.IsContext(self)) {
        return Proxy.GetContext().Proxy.GAnalytics.GetGaq();
      } else if (self._gaq) {
        return _gaq;
      } else {
        return null;
      }
    },    
    Push: function(value)
    {
      var gaq = Proxy.GAnalytics.GetGaq();
      if ((gaq) && (value)) {
        gaq.push(value);              
      }      
    }
  }
}

function OnLoadKMMagmaLanguage()
{      
  if ((self.MAGMA) && (MAGMA.EVENT)) {
    MAGMA.EVENT.LANGUAGE = LANGUAGE;
  }  
}

function KMMagmaLanguage()
{
  this.UpdateLanguage = _UpdateLanguage;
  
  function _UpdateLanguage(language)
  {
    var list = new Hash({ "sid": Proxy.GetValues().User.Sid, 
      "kmmagmaplatformrequesttype": "ajaxupdatelanguage", "language": language });	
    	  
    try { 
    	new Ajax.Request(Proxy.GetValues().Application.Module,
    	{
    	  method: 'get',
        evalJSON: true,
    		parameters: list.toQueryString(),
    		onSuccess: _UpdateLanguageSuccess,			
    	  onFailure: function(value) {			  	  				    	
          _UpdateLanguageFailure(value);
      	}
    	});		  
    } catch(ex) {
      _UpdateLanguageFailure(ex.message);
    }    
  }
  
  function _UpdateLanguageSuccess(result)
  {           
    try {            
      if (result.responseJSON.Failure === false) {
        Proxy.Application.Reload();        
      } else {        
        _UpdateLanguageFailure(result.responseJSON.FailReason);
      }      
    } catch(ex) {      
      _UpdateLanguageFailure(ex.message);
    }
  }
  
  function _UpdateLanguageFailure(error)
  {
    Proxy.GetEventSink().fire(MAGMA.EVENT.LANGUAGE.UPDATEFAILURE, error);    
  }
}

function KMMagmaLanguageListUI(list, host)
{
  // Supports language selection list using instance of KMMagmaPlatformDeltaListUI
  var _listUI = null; 
  this.ListUI = _listUI;
  
  _Initialize(list, host);  
  
  function _Initialize(list, host)
  {      
    _listUI = new KMMagmaPlatformDeltaListUI({Id: "languagelist", List: list, Host: host});       
    _listUI.SetOnItemSelected(_OnItemSelected); 
  }
  
  function _OnItemSelected(item)
  {    
    var language = new KMMagmaLanguage();
    language.UpdateLanguage(item.Id);   
  }   
}

function KMMagmaLanguageSelectListUI(languageList)
{
  // Support object to allow language selection using HTML select element
  var _languageList = $(languageList);    
  var _updating = false;
  _Initialize();
  
  function _Initialize()
  {    
    if (Object.isElement(_languageList)) {  
      _SetCurrentLanguage(Proxy.GetValues().Application.Language.Id);
      Event.observe(_languageList, 'change', _OnLanguageListChange);
      Proxy.GetEventSink().observe(MAGMA.EVENT.LANGUAGE.UPDATEFAILURE, _OnUpdateFailure);      
    }
  }
  
  function _OnUpdateFailure(error)
  {        
    _SetCurrentLanguage(Proxy.GetValues().Application.Language.Id);
  }
  
  function _SetCurrentLanguage(language)
  {
    if ((language != null) && (_languageList != null)) {
      _updating = true;
      try {
        for (index = 0; index < _languageList.options.length; index++) {
  		    if (_languageList.options[index].value == language) {
  		  	  _languageList.options[index].selected = true;
  		  	  break;
  		    }
  		  }  
      } catch(ex) {
      } finally {
        _updating = false;
      }      
    }
  }
  
  function _OnLanguageListChange(event)
  {    
    if (!_updating) {
      var element = event.element();
      var language = new KMMagmaLanguage();
      language.UpdateLanguage(element.options[element.selectedIndex].value);   
    }
  }
}

function KMMagmaPlatformDeltaListUI(options)
{
  // Universal component to support full delta feeded lists
  if (options == null) {
    alert("No options for KMMagmaPlatformDeltaListUI given.");
    return;
  }
  var _options = options;  
  var _listId = _options.Id;  
  var _list = $(_options.List);  
   if (_options.Host == null) {
    _options.Host = self;
  }
  var _OnItemSelected = null;
  var _OnItemCommand = null;
  var _selectedItem = null;
  var _selectedItemSelectable = true;
  var _useEffects = true;
  var _maxItemCount = -1;
  
  this.ListId = _listId;
  this.GetList = _GetList;  
  this.Clear = _Clear;
  this.DeleteItem = _DeleteItem;  
  this.SetSelectedItemSelectable = _SetSelectedItemSelectable
  this.SetUseEffects = _SetUseEffects;
  this.SetOnItemSelected = _SetOnItemSelected;
  this.SetOnItemCommand = _SetOnItemCommand;
  this.SetMaxItemCount = _SetMaxItemCount;
  this.SetSelected = _SetSelected;
   
  _Create();  
  function _Create()
  { 
    if (Object.isString(_options.UpdateEventId)) {
      _options.Host.Proxy.GetEventSink().observe(_options.UpdateEventId, _OnListUpdated);      
    }
  
    _HookList();
  } 
  
  function _SetMaxItemCount(value) 
  {
    if (typeof value == "number") {
      _maxItemCount = value;
      if (_maxItemCount < -1) {
        _maxItemCount = -1;
      }
    }
  }
  
  function _SetUseEffects(value)
  {
    if (typeof value == "boolean") {
      _useEffects = value;
    }
  }
  
  function _SetSelectedItemSelectable(value)  
  {
    if (typeof value == "boolean") {
      _selectedItemSelectable = value;
    }
  }
  
  function _SetOnItemSelected(value)
  {
    _OnItemSelected = value;
  }  
   
  function _SetOnItemCommand(value)
  {
    _OnItemCommand = value;
  } 

  function _GetList()
  {
    return _list;
  }  
  
  function _OnListUpdated(event)
  {    
    if ((event.memo.HasData) && (event.memo.Source) && (event.memo.Id)) {
      var deltalist = event.memo.Source.$(event.memo.Id);      
      if ((deltalist) && (_list)) {
        _UnHookList();
        _list.innerHTML = deltalist.innerHTML;
        _FixMaxItemCount();
        _HookList();
        updated = true;
      }
    }
  }
  
  function _FixMaxItemCount()
  {
    if ((_list) && (_maxItemCount > 0)) {
      var count = 0;
      var itemlist = Element.select(_list, "[itemid]");            
      itemlist.each(function(item) {
        count++;
        if (count > _maxItemCount) {
          Element.hide(item);  
        }
      });      
    }
  }
  
  function _Clear()
  {    
    if (_list) {               
      _UnHookList();
      _list.innerHTML = "";      
    }
  }
  
  function _DeleteItem(item, afterDelete)
  {
    var itemelement;
    if ((!Object.isElement(item)) && (item) && (item.Element)) {
      itemelement = item.Element;
    } else {
      itemelement = item;
    }
  
    if (itemelement) {                
      if (!Object.isFunction(afterDelete)) {        
        afterDelete = null;        
      }
            
      if ((self.Effect) && (_useEffects)) {                
        Effect.Fade(itemelement, {duration: 0.5, afterFinish: afterDelete});
      } else if (afterDelete) {
        afterDelete();
      }
    }
  }
  
  function _GetItemInfo(element)
  {      
    var item = _GetItemElementFromElement(element);
    if (item != null) {      
      var itemid = item.getAttribute("itemid");
      var selected = item.getAttribute("itemselected");
      selected = ((selected === "true") || (selected == "True") || (selected === true));
      var enabled = item.getAttribute("itemenabled");            
      enabled = ((enabled === "true") || (enabled === "True") || (enabled === true) || (enabled === "") || (enabled == null));                       
      if (typeof itemid == "string") {
        return {Id: itemid, Selected: selected, Enabled: enabled, Element: item};
      } else {
        return null;
      }
    } else {
      return null;
    }
  }
  
  function _GetItemElementFromElement(element)
  {
    while ((element) && (typeof element == "object")) {      
      if (element.readAttribute("itemid") != null) {
        return element;
      }
      element = element.up();
    }    
    return null;
  }
  
  function _HookList()
  {
    if (_list) {
      var itemlist = Element.select(_list, "[itemid]");            
      itemlist.each(function(item) {
        var iteminfo = _HookUnHookItem(item, Event.observe);  
        if ((iteminfo != null) && (iteminfo.Selected)) {
          _selectedItem = iteminfo.Element;
          _UpdateItemProperties(iteminfo.Element, "selected", true);        
        }
      });  
    }
  }
  
  function _UnHookList()
  {
    if (_list) {
      var itemlist = Element.select(_list, "[itemid]");
      itemlist.each(function(item) {
        _HookUnHookItem(item, Event.stopObserving);  
      });
      _selectedItem = null;      
    }    
  }
  
  function _HookUnHookItem(item, eventMethod)
  {
    if ((item) && (Object.isFunction(eventMethod))) {      
      var iteminfo = _GetItemInfo(item); 
      if ((iteminfo != null) && (iteminfo.Enabled)) {
        try {            
          eventMethod(item, "click", _DoItemSelected);                  
          eventMethod(item, "mouseover", _DoItemMouseOver);
          eventMethod(item, "mouseout", _DoItemMouseOut);           
        } catch(ex) {          
        }
      }
      
      var commandlist = Element.select(item, "[itemcommand]");
      commandlist.each(function(command) {
        try {
          eventMethod(command, "click", _DoItemCommand);
        } catch(ex) {
        }
      });
      
      return iteminfo;
    }
  } 
  
  function _UpdateItemProperties(element, propertyId, value)
  {  
    var iteminfo = _GetItemInfo(element);    
    if ((iteminfo) && (iteminfo.Element) &&
        ((propertyId === "selected") || (propertyId === "enabled"))) {           
      // Update hooking
      _HookUnHookItem(iteminfo.Element, Event.stopObserving);               
      iteminfo.Element.setAttribute("item" + propertyId, value);       
      _HookUnHookItem(iteminfo.Element, Event.observe);              
      
      // Update style
      var oldclass, newclass;
      if (propertyId == "selected") {           
        if (value) { 
          oldclass = "notselected"; 
          newclass = "selected" 
        } else {
          oldclass = "selected";
          newclass = "notselected";
        }        
      } else if (propertyId == "enabled") {
        if (value) { 
          oldclass = "disabled"; 
          newclass = "enabled" 
        } else {
          oldclass = "enabled";
          newclass = "disabled";
        }              
      }      
      _SwapClasses(iteminfo.Element, oldclass, newclass);      
    }
  }

  function _SwapClasses(element, oldClass, newClass)
  {
    if ((element) && (oldClass) && (newClass)) {
      Element.removeClassName(element, oldClass);      
      Element.addClassName(element, newClass);         
      
      var list = Element.select(element, "." + oldClass);        
      list.each(function(e) {              
        Element.removeClassName(e, oldClass);      
        Element.addClassName(e, newClass);                 
      });    
    }
  }   

  function _SetSelected(id)
  {
    if (typeof id == "string") {
      var itemlist = Element.select(_list, "[itemid]");
      itemlist.each(function(item) {      
        var iteminfo = _GetItemInfo(item);         
        if ((iteminfo != null) && (iteminfo.Enabled) && (iteminfo.Id == id)) {                  
          _UpdateItemProperties(_selectedItem, "selected", false);
          _UpdateItemProperties(iteminfo.Element, "selected", true);  
          _selectedItem = iteminfo.Element;                                         
          throw $break;
        }
      });
    }
  }  

  function _DoItemSelected(event)
  {        
    var iteminfo = _GetItemInfo(event.element());       
    if ((iteminfo != null) && (iteminfo.Enabled) && 
        ((!iteminfo.Selected) || ((iteminfo.Selected) && (_selectedItemSelectable)))) {                  
      if ((_selectedItem) && (!iteminfo.Selected)) {      
        // Unselect currently selected item
        _UpdateItemProperties(_selectedItem, "selected", false);
            
        // Make new item selected
        _UpdateItemProperties(iteminfo.Element, "selected", true);        
      }
      _selectedItem = iteminfo.Element;
      
      if (_OnItemSelected) {
        _OnItemSelected(iteminfo);      
      }
      
      Proxy.GetEventSink().fire(Proxy.GetContext().UPLATFORM.LISTSELECTNODE, 
        {ItemInfo: iteminfo, ListId: _listId, ListUI: this}); // warning: "this" is not what we think it is!
    }
  } 
  
  function _DoItemCommand(event)
  {
    Event.stop(event);   
    var command = event.element().getAttribute("itemcommand");    
    var iteminfo = _GetItemInfo(event.element());  
    if ((_OnItemCommand) && (iteminfo) && (command)) {            
      _OnItemCommand(command, iteminfo);
    }
  }

  function _DoItemMouseOver(event)  
  {
    _UpdateItemOverClass(event.element(), true);
  }
  
  function _DoItemMouseOut(event)
  {
    _UpdateItemOverClass(event.element(), false);
  }
  
  function _UpdateItemOverClass(element, overNode)
  {    
    var iteminfo = _GetItemInfo(element);
    if ((iteminfo != null) && (!iteminfo.Selected)) {                 
      if (overNode) {
        Element.addClassName(iteminfo.Element, "over");   
      } else {
        Element.removeClassName(iteminfo.Element, "over");
      }
    }         
  }  
}