



/* Event.onDOMReady */

Object.extend(Event, {
	_domReady : function() {
    	if (arguments.callee.done) return;
		arguments.callee.done = true;

    	if (this._timer)  clearInterval(this._timer);
    
    	this._readyCallbacks.each(function(f) { f() });
    	this._readyCallbacks = null;
	},
  	
	onDOMReady : function(f) {
    	if (!this._readyCallbacks) {
      		var domReady = this._domReady.bind(this);
      
      		if (document.addEventListener)
        		document.addEventListener("DOMContentLoaded", domReady, false);
        
        	/*@cc_on @*/
        	/*@if (@_win32)
            document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
            document.getElementById("__ie_onload").onreadystatechange = function() {
                if (this.readyState == "complete") domReady(); 
            };
        	/*@end @*/
        
        	if (/WebKit/i.test(navigator.userAgent)) { 
          		this._timer = setInterval(function() {
            		if (/loaded|complete/.test(document.readyState)) domReady(); 
          		}, 10);
        	}
        
        	Event.observe(window, 'load', domReady);
        	Event._readyCallbacks =  [];
    	}
    	Event._readyCallbacks.push(f);
  	}
});



/* Ajax.LoadScript */

Ajax.LoadScript = Class.create();

Object.extend(Object.extend(Ajax.LoadScript.prototype, Ajax.Request.prototype), {
  initialize: function(url, options) {
    this.transport = Ajax.getTransport();
    this.setOptions(options);

    var onComplete = this.options.onComplete || Prototype.emptyFunction;
    this.options.onComplete = (function(transport, param) {
      this.executeScript();
      onComplete(transport, param);
    }).bind(this);

    this.request(url);
  },

  executeScript: function() {
    var response = this.transport.responseText;

	if (this.success()) {
		if (window.execScript) 
			window.execScript(response);
		else 
			window.setTimeout(response, 0);
	}
  }
});


/* Element.scrollTo */

Element.scrollTo = function(element) {
	element = $(element);

	var parent  = element.parentNode;
	var elementHeight = element.offsetHeight;
	var elementWidth = element.offsetWidth;
	var elementPosition = Position.cumulativeOffset(element);
	var scrollTop = 0;
	var scrollLeft = 0;
	
	while (parent.tagName != 'BODY') {
		if (parent.offsetWidth != parent.scrollWidth || parent.offsetHeight != parent.scrollHeight) {

			var currentPosition = Position.cumulativeOffset(parent);
			var x = elementPosition[0] - currentPosition[0];
			var y = elementPosition[1] - currentPosition[1];
			
			if (x > parseInt(parent.offsetWidth / 2) - elementWidth) {
				parent.scrollLeft = x - parseInt(parent.offsetWidth / 2) + elementWidth;
			}
			
			if (y > parseInt(parent.offsetHeight / 2) - elementHeight) {
				parent.scrollTop = y - parseInt(parent.offsetHeight / 2) + elementHeight;
			}
		}
		
		scrollTop += parent.scrollTop;
		scrollLeft =+ parent.scrollLeft;
		
		element = parent;
		parent = element.parentNode;
	}
	
	var offsetLeft = elementPosition[0] - scrollLeft;
	var offsetTop = elementPosition[1] - scrollTop;

	if (window.innerWidth) {
		var windowWidth = window.innerWidth;
		var windowHeight = window.innerHeight;
	} else if (document.documentElement && document.documentElement.clientWidth) {
		var windowWidth = document.documentElement.clientWidth;
		var windowHeight = document.documentElement.clientHeight;
	} else {
		var windowWidth = document.body.offsetWidth;
		var windowHeight = document.body.offsetHeight
	}

	if (offsetTop < windowHeight) {
		offsetTop = 0;	
	}

	if (offsetLeft < windowWidth) {
		offsetLeft = 0;	
	}
	
	window.scrollTo(offsetLeft, offsetTop);	
}




Event.onDOMReady(function() {
					
	$$('#content tr:nth-of-type(2n-1)').each(function(element) {
		element.addClassName('odd');													
	});

	$$('#content td:last-of-type').each(function(element) {
		element.addClassName('last');													
	});
	
	if (Prototype.Browser.IE) {
		
		$$('li').each(function(item) {
			Event.observe(item, 'mouseover', function(e) {
				Element.addClassName(Event.findElement(e, 'li'), 'hover');
			}.bindAsEventListener(this));
			
			Event.observe(item, 'mouseout', function(e) {
				Element.removeClassName(Event.findElement(e, 'li'), 'hover');
			}.bindAsEventListener(this));				  
		});
	}
});


/**
 * PLUGIN FRAMEWORK, Version 0.5
 * For details, see the Knallgrau web site: http://www.knallgrau.code/prototype/plugins_js
 * Copyright (c) 2006 Matthias Platzer <matthias@knallgrau.at>
 * This code is freely distributable under the terms of an MIT-style license.
/*--------------------------------------------------------------------------*/

var PluginFactory = function() {

  // Returns if plugin with identifier name is installed
  // @see Plugin.getInfo
  this.isInstalled = function(name) {
    return Plugin.getInfo(name).isInstalled;
  }

  // Returns version number of plugin if available
  // @see Plugin.getInfo
  this.getVersion = function(name) {
    return Plugin.getInfo(name).version;
  }

  // Returns an Array of plugin identifier names, 
  // that can handle this mimeType.
  this.getPluginsForMimeType = function(mimeType) {
    var result = [];
    if (supportsNavigatorPlugins()) {
      // navigator.mimeTypes
      for (var i=0; i<navigator.mimeTypes.length; i++) {
        if (navigator.mimeTypes[i].type.indexOf(mimeType) == 0 && navigator.mimeTypes[i].enabledPlugin) {
          var pluginName = (findPluginName(navigator.mimeTypes[i].enabledPlugin.name) || navigator.mimeTypes[i].enabledPlugin.name);
          if (result.indexOf(pluginName) == -1) result.push(pluginName);
        }
      }
    } else {
      // Code for IE using ActiveX
      for (var pluginName in Plugin.PLUGINS) {
        var mimeTypes = Plugin.PLUGINS[pluginName].acceptedMimeTypes;
        if (!mimeTypes) continue;
        for (var j=0; j<mimeTypes.length; j++) {
          if (mimeTypes[j].type.indexOf(mimeType) == 0 && Plugin.isInstalled(pluginName)) {
            if (result.indexOf(pluginName) == -1) result.push(pluginName);
          }
        }
      }    
    }
    return result;
  }

  // Returns an Array of plugin identifier names, 
  // that can handle a file with this suffix.
  this.getPluginsForFileSuffix = function(suffix) {
    var result = [];
    if (supportsNavigatorPlugins()) {
      // navigator.mimeTypes
      for (var i=0; i<navigator.mimeTypes.length; i++) {
        if ((","+navigator.mimeTypes[i].suffixes+",").indexOf(","+suffix+",") != -1 && navigator.mimeTypes[i].enabledPlugin) {
          var pluginName = (findPluginName(navigator.mimeTypes[i].enabledPlugin.name) || navigator.mimeTypes[i].enabledPlugin.name);
          if (result.indexOf(pluginName) == -1) result.push(pluginName);
        }
      }
    } else {
      // Code for IE using ActiveX
      for (var pluginName in Plugin.PLUGINS) {
        var mimeTypes = Plugin.PLUGINS[pluginName].acceptedMimeTypes;
        if (!mimeTypes) continue;
        for (var j=0; j<mimeTypes.length; j++) {
          if ((","+mimeTypes[j].suffixes+",").indexOf(","+suffix+",") != -1 && Plugin.isInstalled(pluginName)) {
            if (result.indexOf(pluginName) == -1) result.push(pluginName);
          }
        }
      }    
    }
    return result;
  }

  // Returns general information about a plugin.
  // accepts: Acrobat, QuickTime, DivX, Director, 'Windows Media', 
  //          Flash, Java, RealPlayer, VLC
  this.getInfo = function(name) {

    var info = Plugin.PLUGINS[name];
    var isInstalled = false;
    var version = null;

    if (supportsNavigatorPlugins()) {
      // navigator.plugins
      var plugin = findNavigatorPluginByName((name == "RealPlayer") ? "RealPlayer Version Plugin" : name);
      if (plugin) {
        isInstalled = true;
        version = getVersionFromPlugin(plugin);
      }

    } else {
      // Code for IE using ActiveX
      isInstalled = hasActiveXObject(Plugin.PLUGINS[name] && Plugin.PLUGINS[name].progID);
      if (isInstalled) {
        if (Plugin.PLUGINS[name].getActiveXVersionInfo) {
          version = Plugin.PLUGINS[name].getActiveXVersionInfo();
        } else {
          // assume that the progID contains the version number
          // this is not always correct
          var progID = getProgIdForActiveXObject(Plugin.PLUGINS[name].progID);
          version = getVersionFromPlugin(progID);
        }
      } else {
        version = getActiveXPluginByClassId(Plugin.PLUGINS[name] && Plugin.PLUGINS[name].classID);
        if (version) version = version.replace(/,/g, ".");
        isInstalled = (version!=undefined);
      }

    }

    var result = {};
    for (var i in info) {
      result[i] = info[i];
    }
    result["isInstalled"] = isInstalled;
    result["version"] = version;
    result["name"] = name;

    return result;
  }

/**
 * writes an embed or object tag to document.write or target.
 * @param plugin   name of the plugin to be used
 * @param options  options for embed respectivly object tag.
 *   .src,.width,.height,.type,.activeXType will get a special treatment
 *   all other properties of options will be added to the 
 *   embed tag as attributes resp. to the object tag as param(eters).
 *   option names should be lower case!
 * @param target   optional (id of) container element for the embed/object tag
 */
  this.embed = function(plugin, options, target) {
    var embedOptions = Object.extend({
	}, options || {});
    
	var src = embedOptions.src;
    delete embedOptions.src;
    
	var id = embedOptions.id;
    delete embedOptions.id;
    
	var name = embedOptions.name || id;
    delete embedOptions.name;
    
	var width = embedOptions.width;
    delete embedOptions.width;
    
	var height = embedOptions.height;
    delete embedOptions.height;
    
	var type = embedOptions.type || (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].mimeType) || "";
    delete embedOptions.type;
    
	var activeXType = embedOptions.activeXType || (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].activeXType) || type;
    delete embedOptions.activeXType;
    
	var forceEmbedTag = (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].forceEmbedTag === true) ? true : false;
    var forceObjectTag = (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].forceObjectdTag === true) ? true : false;
    var embedOptions = Object.extend(((Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].standardEmbedAttributes) || {}), embedOptions);

	switch (plugin) {
      case "QuickTime":
        // get space for controls
        if (embedOptions.controller == "true" && (height+"").indexOf("%") == -1) {
          height += 16;
        }
        if (!options.activeXType) {
          activeXType = null;
        }
        break;

      case "DivX":
        // get space for controlls
        if ((height+"").indexOf("%") == -1) {
          if (embedOptions.mode == "mini") height += 20;
          else if (embedOptions.mode == "large") height += 65;
          else if (embedOptions.mode == "full") height += 90;
        }
        break;

      case "Windows Media":
        // check if ActiveX for Firefox is installed
        // http://help.yahoo.com/help/us/launch/videos/videos-07.html
        if (!supportsNavigatorPlugins() || window.GeckoActiveXObject) {
           forceObjectTag = true;
        }
        // get space for controlls
        if ((window.ActiveXObject || window.GeckoActiveXObject || window.opera) &&
            (height+"").indexOf("%") == -1) {
          height += 45;
        }
        break;

      case "Flash":
        // flash wants the src to be named "movie" if passed as object param
        if (!supportsNavigatorPlugins()) {
          embedOptions.movie = src;
          src = null;
        }
        break;

      case "VLC":
        // VLC wants the src to be named "target"
        // update: that's actualy wrong, even it's documented like that!
        if (supportsNavigatorPlugins()) {
          embedOptions.target = src;
        }
        break;

      case "RealPlayer":
        break;        

      default: 
        // do nothing
        break;
    }

    // prepare html code
    var html = "";
    if ((supportsNavigatorPlugins() && ! forceObjectTag) || forceEmbedTag) {
      // Netscape Plugin embed Tag
      html += '<embed' + getAttributeHtml("src", src)  + getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("pluginspage", Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].pluginsPage) + getAttributeHtml("type", type);
      for (var i in embedOptions) {
        html += ' '+i+'="'+embedOptions[i]+'"';
      }
      html += '></embed>\n';
	} else if (supportsNavigatorPlugins()) {
      // Standards compliant object tag
      html += '<object ';
      html += getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("type", type) + '>\n';
      html += (src) ? '  <param name="src" value="'+src+'">\n' : '';
      for (var i in embedOptions) {
        html += '  <param name="'+i+'" value="'+embedOptions[i]+'" />';
      }
      html += '</object>\n';
	} else {
      // ActiveX object tag
      html += '<object classid="clsid:'+(Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].classID)+'"';
      html += getAttributeHtml("id", id) + getAttributeHtml("name", name) + getAttributeHtml("width", width) + getAttributeHtml("height", height) + getAttributeHtml("codebase", (Plugin.PLUGINS[plugin] && Plugin.PLUGINS[plugin].codeBase)) + getAttributeHtml("type", activeXType) + '>\n';
      html += (src) ? '  <param name="src" value="'+src+'">\n' : '';
      for (var i in embedOptions) {
        html += '  <param name="'+i+'" value="'+embedOptions[i]+'" />';
      }
      html += '</object>\n';
    }

	if (target) {
      if (typeof target == "string") target = document.getElementById(target);
      target.innerHTML = html;
    } else {
      document.write(html);
    }
  }

  var getAttributeHtml = function(name, value) {
    return (value) ? (" " + name + "=\"" + value + "\"") : "";
  }

  // Info about known plugins
  this.PLUGINS = {
    "Acrobat": {
      description: "Adobe Acrobat Plugin",
      progID: ["PDF.PdfCtrl.7", "PDF.PdfCtrl.6", "PDF.PdfCtrl.5", "PDF.PdfCtrl.4", "PDF.PdfCtrl.3", "AcroPDF.PDF.1"],
      classID: "CA8A9780-280D-11CF-A24D-444553540000",
      pluginsPage: "http://www.adobe.com/products/acrobat/readstep2.html",
      acceptedMimeTypes: [
        { type: "application/pdf", suffixes: "pdf" },
        { type: "application/vnd.fdf", suffixes: "fdf" },
        { type: "application/vnd.adobe.xfdf", suffixes: "xfdf" },
        { type: "application/vnd.adobe.xdp+xml", suffixes: "xdp" },
        { type: "application/vnd.adobe.xfd+xml", suffixes: "xfd" }
      ]
    },
    "QuickTime": {
      description: "QuickTime Plug-in",
      progID: ["QuickTimeCheckObject.QuickTimeCheck.1", "QuickTime.QuickTime"],
      classID: "02BF25D5-8C17-4B23-BC80-D3488ABDDC6B",
      pluginsPage: "http://www.apple.com/quicktime/download/",
      codeBase: "http://www.apple.com/qtactivex/qtplugin.cab#version=6,0,2,0",
      mimeType: "video/quicktime",
      standardEmbedAttributes: {
        autoplay: "false"
      },
      // embedInfo: http://www.apple.com/quicktime/tutorials/embed.html 
      //            http://developer.apple.com/quicktime/compatibility.html
      getActiveXVersionInfo: function() { 
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["QuickTime"].progID); 
        var obj = new ActiveXObject(progID);
        var version = (obj && obj.QuickTimeVersion) ? obj.QuickTimeVersion.toString(16) : "";
        return version.substring(0,1) + '.' + version.substring(1,2) + '.' + version.substring(2,3);
      },
      acceptedMimeTypes: [
        { type: "image/tiff", suffixes: "tif,tiff" },
        { type: "image/x-tiff", suffixes: "tif,tiff" },
        { type: "video/x-m4v", suffixes: "m4v" },
        { type: "image/x-macpaint", suffixes: "pntg,pnt,mac" },
        { type: "image/pict", suffixes: "pict,pic,pct" },
        { type: "image/x-pict", suffixes: "pict,pic,pct" },
        { type: "image/x-quicktime", suffixes: "qtif,qti" },
        { type: "image/x-sgi", suffixes: "sgi,rgb" },
        { type: "image/x-targa", suffixes: "targa,tga" },
        { type: "audio/3gpp", suffixes: "3gp,3gpp" },
        { type: "video/3gpp2", suffixes: "3g2,3gp2" },
        { type: "audio/3gpp2", suffixes: "3g2,3gp2" },
        { type: "video/sd-video", suffixes: "sdv" },
        { type: "application/x-mpeg", suffixes: "amc" },
        { type: "video/mp4", suffixes: "mp4" },
        { type: "audio/mp4", suffixes: "mp4" },
        { type: "audio/x-m4a", suffixes: "m4a" },
        { type: "audio/x-m4p", suffixes: "m4p" },
        { type: "audio/x-m4b", suffixes: "m4b" },
        { type: "video/mpeg", suffixes: "mpeg,mpg,m1s,m1v,m1a,m75,m15,mp2,mpm,mpv,mpa" },
        { type: "audio/mpeg", suffixes: "mpeg,mpg,m1s,m1a,mp2,mpm,mpa,m2a" },
        { type: "audio/x-mpeg", suffixes: "mpeg,mpg,m1s,m1a,mp2,mpm,mpa,m2a" },
        { type: "video/3gpp", suffixes: "3gp,3gpp" },
        { type: "audio/x-gsm", suffixes: "gsm" },
        { type: "audio/AMR", suffixes: "AMR" },
        { type: "audio/aac", suffixes: "aac,adts" },
        { type: "audio/x-aac", suffixes: "aac,adts" },
        { type: "audio/x-caf", suffixes: "caf" },
        { type: "video/x-mpeg", suffixes: "mpeg,mpg,m1s,m1v,m1a,m75,m15,mp2,mpm,mpv,mpa" },
        { type: "audio/aiff", suffixes: "aiff,aif,aifc,cdda" },
        { type: "audio/x-aiff", suffixes: "aiff,aif,aifc,cdda" },
        { type: "audio/basic", suffixes: "au,snd,ulw" },
        { type: "audio/mid", suffixes: "mid,midi,smf,kar" },
        { type: "audio/x-midi", suffixes: "mid,midi,smf,kar" },
        { type: "audio/midi", suffixes: "mid,midi,smf,kar" },
        { type: "audio/vnd.qcelp", suffixes: "qcp" },
        { type: "application/sdp", suffixes: "sdp" },
        { type: "application/x-sdp", suffixes: "sdp" },
        { type: "application/x-rtsp", suffixes: "rtsp,rts" },
        { type: "video/quicktime", suffixes: "mov,qt,mqv" },
        { type: "video/flc", suffixes: "flc,fli,cel" },
        { type: "audio/x-wav", suffixes: "wav,bwf" },
        { type: "audio/wav", suffixes: "wav,bwf" }
      ]
    },
    "DivX": {
      description: "DivX Browser Plugin",
      progID: ["npdivx.DivXBrowserPlugin.1", "npdivx.DivXBrowserPlugin"],
      classID: "67DABFBF-D0AB-41fa-9C46-CC0F21721616",
      codeBase: "http://go.divx.com/plugin/DivXBrowserPlugin.cab",
      pluginsPage: "http://go.divx.com/plugin/download/",
      mimeType: "video/divx",
      standardEmbedAttributes: {
        mode: "mini",
        minversion: "1.0.0"
      },
      // embedInfo: Beta1: http://labs.divx.com/archives/000072.html
      //            SDK&Doc: http://download.divx.com/labs/Webmaster_SDK.zip
      getActiveXVersionInfo2: function() {
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["DivX"].progID); 
        return "1.0.0"; // that's the only currently available
      },
      acceptedMimeTypes: [
        { type: "video/divx", suffixes: "dvx,divx" }
      ]
    },
    "Director": {
      description: "Macromedia Director",
      progID: ["SWCtl.SWCtl.11","SWCtl.SWCtl.10","SWCtl.SWCtl.9","SWCtl.SWCtl.8","SWCtl.SWCtl.7","SWCtl.SWCtl.6","SWCtl.SWCtl.5","SWCtl.SWCtl.4"],
      classID: "166B1BCA-3F9C-11CF-8075-444553540000",
      pluginsPage: "http://www.macromedia.com/shockwave/download/",
      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/director/sw.cab#version=8,5,1,0",
      mimeType: "application/x-director"
    },         
    "Flash": {
      description: "Macromedia Shockwave Flash",
      progID: ["ShockwaveFlash.ShockwaveFlash.9", "ShockwaveFlash.ShockwaveFlash.8.5", "ShockwaveFlash.ShockwaveFlash.8", "ShockwaveFlash.ShockwaveFlash.7", "ShockwaveFlash.ShockwaveFlash.6", "ShockwaveFlash.ShockwaveFlash.5", "ShockwaveFlash.ShockwaveFlash.4"],
      classID: "D27CDB6E-AE6D-11CF-96B8-444553540000",
      pluginsPage: "http://www.macromedia.com/go/getflashplayer",
      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0",
      mimeType: "application/x-shockwave-flash",
      standardEmbedAttributes: {
        quality: "high"
      },
      // embedInfo: http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_4150
      //            http://www.macromedia.com/cfusion/knowledgebase/index.cfm?id=tn_12701
      acceptedMimeTypes: [
        { type: "application/x-shockwave-flash", suffixes: "swf" },
        { type: "application/futuresplash", suffixes: "spl" }
      ]
    }, 
    "VLC": {
      description: "VLC multimedia plugin",
      progID: [],
      classID: "",
      pluginsPage: "http://www.videolan.org/doc/play-howto/en/ch02.html#id287569",
      codeBase: "http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0",
      mimeType: "application/x-vlc-plugin",
      standardEmbedAttributes: {
        quality: "high",
        autoplay: "no"
      },
      // embedInfo: http://www.videolan.org/doc/vlc-user-guide/en/ch07.html
      //            http://www.videolan.org/doc/play-howto/en/ch04.html#id293251
      acceptedMimeTypes: [
        { type: "audio/mpeg", suffixes: "mp2,mp3,mpga,mpega" },
        { type: "audio/x-mpeg", suffixes: "mp2,mp3,mpga,mpega" },
        { type: "video/mpeg", suffixes: "mpg,mpeg,mpe" },
        { type: "video/x-mpeg", suffixes: "mpg,mpeg,mpe" },
        { type: "video/mpeg-system", suffixes: "mpg,mpeg,vob" },
        { type: "video/x-mpeg-system", suffixes: "mpg,mpeg,vob" },
        { type: "video/mpeg4", suffixes: "mp4,mpg4" },
        { type: "audio/mpeg4", suffixes: "mp4,mpg4" },
        { type: "application/mpeg4-iod", suffixes: "mp4,mpg4" },
        { type: "application/mpeg4-muxcodetable", suffixes: "mp4,mpg4" },
        { type: "video/x-msvideo", suffixes: "avi" },
        { type: "video/quicktime", suffixes: "mov,qt" },
        { type: "application/x-ogg", suffixes: "ogg" },
        { type: "application/x-vlc-plugin", suffixes: "*" },
        { type: "video/x-ms-asf-plugin", suffixes: "asf,asx,*" },
        { type: "video/x-ms-asf", suffixes: "asf,asx,*" },
        { type: "application/x-mplayer2", suffixes: "dvx,divx,ivx,xvid,ivf,*" },
        { type: "video/x-ms-wmv", suffixes: "wmv,*" },
        { type: "application/x-google-vlc-plugin", suffixes: "*" }      
      ]
    },
    "Windows Media": {
      description: "Windows Media Player Plug-in Dynamic Link Library",
      progID: ["WMPlayer.OCX", "MediaPlayer.MediaPlayer.1"],
      classID: "22D6f312-B0F6-11D0-94AB-0080C74C7E95", // WMP6 -> semms to work a lot better, don't know why
      // classID: "6BF52A52-394A-11D3-B153-00C04F79FAA6", // WMP7+ -> doesn't work for me
      pluginsPage: "http://www.microsoft.com/windows/windowsmedia/",
      codeBase: "http://activex.microsoft.com/activex/controls/mplayer/en/nsmp2inf.cab#Version=6,0,02,902",
      mimeType: "application/x-mplayer2",
      activeXType: "application/x-oleobject",
      standardEmbedAttributes: {
        autoplay: "false"
      },
      // embedInfo: http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/samples/internet/imedia/netshow/crossbrowserembed/default.asp
      getActiveXVersionInfo: function() { 
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["Windows Media"].progID); 
        var obj = new ActiveXObject(progID);
        return (obj && obj.versionInfo) ? obj.versionInfo : "";
      },
      acceptedMimeTypes: [
        { type: "application/asx", suffixes: "*" },
        { type: "video/x-msvideo", suffixes: "avi" },
        { type: "video/x-ms-asf-plugin", suffixes: "*" },
        { type: "application/x-mplayer2", suffixes: "dvx,divx,ivx,xvid,ivf,*" },
        { type: "video/x-ms-asf", suffixes: "asf,asx,*" },
        { type: "video/x-ms-wm", suffixes: "wm,*" },
        { type: "audio/x-ms-wma", suffixes: "wma,*" },
        { type: "audio/x-ms-wax", suffixes: "wax,*" },
        { type: "video/x-ms-wmv", suffixes: "wmv,*" },
        { type: "video/x-ms-wvx", suffixes: "wvx,*" }
      ]
    },
    "Java": {
      description: "Java Virtual Machine",
      progID: [],
      classID: "08B0E5C0-4FCB-11CF-AAA5-00401C608500",
      pluginsPage: "http://www.java.com/de/download/manual.jsp",
      acceptedMimeTypes: [
        { type: "application/x-java-applet", suffixes: "" },
        { type: "application/x-java-bean", suffixes: "" },
        { type: "application/x-java-vm", suffixes: " " }
      ]
    },          
    "RealPlayer": {
      description: "RealPlayer Version Plugin",
      progID: ["RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)", "RealVideo.RealVideo(tm) ActiveX Control (32-bit)", "rmocx.RealPlayer G2 Control"],
      classID: "CFCDAA03-8BE4-11cf-B84B-0020AFBBCCFA",
      mimeType: "audio/x-pn-realaudio-plugin",
      pluginsPage: "http://www.real.com/freeplayer/?rppr=rnwk",
      forceEmbedTag: true,
      standardEmbedAttributes: {
        controls: "ControlPanel",
        nojava: "true",
        autostart: "false"
      },
      // embedInfo: http://service.real.com/help/library/guides/realone/ProductionGuide/HTML/realpgd.htm?page=htmfiles/embed.htm
      // couldn't find any info about the object tag!
      getActiveXVersionInfo: function() { 
        var progID = getProgIdForActiveXObject(Plugin.PLUGINS["RealPlayer"].progID); 
        var obj = new ActiveXObject(progID);
        var version = (obj) ? obj.GetVersionInfo() : "";
        return version;
      },
      acceptedMimeTypes: [
        { type: "audio/x-pn-realaudio-plugin", suffixes: "rpm" },
        { type: "application/vnd.rn-realplayer-javascript", suffixes: "rpj" }
      ]
    }
  }

  var supportsNavigatorPlugins = function() {
    return (navigator.plugins && (navigator.plugins.length > 0));
  }

  var supportsActiveX = function() {
    return ((typeof 'ActiveXObject' != 'undefined') && (navigator.userAgent.indexOf('Win') != -1));
  }

  var findNavigatorPluginByName = function(name) {
    if (supportsNavigatorPlugins()) {
      for(var i=0;i<navigator.plugins.length;++i) {
        var plugin = navigator.plugins[i];
        if (plugin.name.indexOf(name) != -1) {
          return plugin;
        }
      }
    }
    return null;
  }

  var findPluginName = function(str) {
    for (var pluginName in Plugin.PLUGINS) {
      if (str.indexOf(pluginName) != -1) {
        return pluginName;
      }
    }
    return null;
  }

  var getIEClientCaps = function() {
    var clientcaps = document.getElementById("__Plugin_ClientCaps");
    if (!clientcaps) {
      var clientcaps = document.createElement("DIV");
      clientcaps.id = "__Plugin_ClientCaps";
      if (clientcaps.addBehavior) {
        clientcaps.addBehavior("#default#clientCaps");
        document.body.appendChild(clientcaps);
      }
      clientcaps = document.getElementById("__Plugin_ClientCaps");
    }
    return clientcaps;    
  }

  var getActiveXPluginByClassId = function(classID) {
    if (!classID) return null;
    if (!classID.match(/{[^}]+}/)) classID = "{" + classID + "}";
    var clientcaps = getIEClientCaps();
    try {
      var result = clientcaps.getComponentVersion(classID, "ComponentID")
      return result || null;
    } catch (err) { }
    return null;
  }

  var hasActiveXObject = function(progID) {
    progID = getProgIdForActiveXObject(progID);
    return (progID != null);
  }

  var getProgIdForActiveXObject = function(progID) {
    if (!progID) return null;
    for (var i=0; i<progID.length; i++) {
      try {
        var obj = new ActiveXObject(progID[i]);
        return progID[i] || null;
      }
      catch(e) { }
    }
    return null;
  }

  // accepts plugin or string
  var getVersionFromPlugin = function(plugin) {
    if (!plugin.name) plugin = { name: plugin, description: name };
    var matches = /[\d][\d\.]*/.exec(plugin.name);
    if (matches && plugin.name.indexOf("Java") == -1) return matches[0];
    matches = /[\d\.]+/.exec(plugin.description);
    return matches ? matches[0] : "";
  }
  
};

if (!window.Plugin) {
  var Plugin = new Object();
}
Object.extend(Plugin, (new PluginFactory()));


// Copyright (c) 2006 Sébastien Gruhier (http://xilinus.com, http://itseb.com)
// 
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// VERSION 0.26

var Carousel = Class.create();
Carousel.prototype = {
  // Constructor
  initialize: function(carouselElemID) {
    this.carouselElemID = carouselElemID;
    
    this.options = Object.extend({
      numVisible:           4,
      scrollInc:            3,
      animParameters:      {},
      buttonStateHandler:  null,
      animHandler:         null,
      ajaxHandler:         null,
      initDoneHandler:     null,
      queue:               "carousel",
      size:                0,
      prevElementID:       "prev-arrow",
      nextElementID:       "next-arrow",
      ajaxParameters:      null,
      url:                 null
		}, arguments[1] || {});

		this.initDone = false;
		this.animRunning = "none";
    this.requestIsRunning = false;
    
		// add afterFinish options to animParameters (store old function)
		this.animAfterFinish = this.options.animParameters.afterFinish;
		Object.extend(this.options.animParameters, {afterFinish:  this._animDone.bind(this), queue: { position:'end', scope: this.options.queue }});
	  
		// Event bindings
		this.prevScroll = this._prevScroll.bindAsEventListener(this);
		this.nextScroll = this._nextScroll.bindAsEventListener(this);
		this.onComplete = this._onComplete.bindAsEventListener(this);
		this.onFailure  = this._onFailure.bindAsEventListener(this);

		Event.observe(this.options.prevElementID, "click", this.prevScroll);
		Event.observe(this.options.nextElementID, "click", this.nextScroll);
		
		// Get DOM UL element
		var carouselListClass = "carousel-list";
		this.carouselList = document.getElementsByClassName(carouselListClass, $(carouselElemID))[0]
		this.options.size =  $(this.carouselList.getElementsByTagName("li")).length;
		// Init data
		this._init();
  },
  
  // Destructor
 	destroy: function() {
  	Event.stopObserving(this.options.prevElementID, "click", this.prevScroll);
  	Event.stopObserving(this.options.nextElementID, "click", this.nextScroll);
	},
	
	scrollTo: function(newStart) {
		var old_inc = this.options.scrollInc;
		this.ignoreNoMoreImages = true;
		if(newStart > this.currentIndex) {
			this.options.scrollInc = newStart - this.currentIndex;
			this._nextScroll(this);
		} else {
			this.options.scrollInc = this.currentIndex - newStart;
			this._prevScroll(this);
		}
    this.options.scrollInc = old_inc;
	},
	
  /* "Private" functions */
  _init: function() {
    this.currentIndex = 0;
      
    // Ajax content
    if (this.options.url)
  	  this._request(this.currentIndex, this.options.numVisible);
	  // Static content
  	else {
  	  this._getLiElementSize();
  		this._updateButtonStateHandler(this.options.prevElementID, false);
  		this._updateButtonStateHandler(this.options.nextElementID, this.options.size > this.options.numVisible);
  	}
  },
  
  _prevScroll: function(event) {
    if (this.animRunning != "none" || this.currentIndex == 0)
      return;

    var inc = this.options.scrollInc;

    if (this.currentIndex - inc < 0)
      inc = this.currentIndex;

    this._scroll(inc)		  
	  return false;
  },
  
  _nextScroll: function(event) {    
    if (this.animRunning != "none")
      return false;
            
    // Check if there are enough elements in cache
    if (this.currentIndex + this.options.numVisible + this.options.scrollInc <= this.options.size) 
      this._scroll(-this.options.scrollInc);
    else {
      // Compute how many are in the cache
      this.nbInCache = this.options.size - (this.currentIndex + this.options.numVisible);
      if (this.options.url && this.noMoreImages == false) 
		    this._request(this.currentIndex + this.options.numVisible + this.nbInCache, this.options.scrollInc - this.nbInCache);
	    else  {
	      if (this.nbInCache > 0)
          this._scroll(-this.nbInCache);
        }
	  }
	  return false;
  },
  
  _request: function(start, nb) {
    if (this.options.url && ! this.requestIsRunning) {
      this.requestIsRunning = true;
      
      if (this.options.ajaxHandler)
        this.options.ajaxHandler(this, "before");
      
      var params = "start=" + start + "&nb=" + nb;
      if (this.options.ajaxParameters != null)
        params += "&" + this.options.ajaxParameters
      
  		new Ajax.Request(this.options.url, {parameters: params, onComplete: this.onComplete, onFailure: this.onFailure});
		}
  },
  
  _onComplete: function(originalRequest){
    this.requestIsRunning = false;
    this.carouselList.innerHTML += originalRequest.responseText;
    // Compute how many new elements we have
    var size = this.options.size;
    this.options.size = this.carouselList.getElementsByTagName("li").length;
    var inc = this.options.size - size;
    
		// First run, compute li size
		if (this.initDone == false) {
  		this._getLiElementSize()
  		this.currentIndex = 0;
  		this.initDone = true;
      if (this.options.initDoneHandler) 
        this.options.initDoneHandler(this);
         
  		// Update button states
		  this._updateButtonStateHandler(this.options.prevElementID, false);
		  this._updateButtonStateHandler(this.options.nextElementID, this.options.size == this.options.numVisible);
		  this.noMoreImages = this.options.size < this.options.numVisible
		}
		// Add images
		else {
		  if (!this.ignoreNoMoreImages)
		    this.noMoreImages = inc != this.options.scrollInc;
		  else
		    this.ignoreNoMoreImages = false;
		  // Add images
		  if (inc > 0) {
        this._scroll(-inc, this.noMoreImages)
      }
      // No more images, disable next button
		  else {
		    if (this.nbInCache >0)
          this._scroll(-this.nbInCache, true);
		    
		    this._updateButtonStateHandler(this.options.nextElementID, false);
	    }
		}
		if (this.options.ajaxHandler)
      this.options.ajaxHandler(this, "after");
  },
  
  _onFailure: function(originalRequest){    
    this.requestIsRunning = false;
  },

  _animDone: function(event){   
    if (this.options.animHandler)
      this.options.animHandler(this.carouselElemID, "after", this.animRunning);
     
    this.animRunning = "none";
    // Call animAfterFinish if exists
    if (this.animAfterFinish)
      this.animAfterFinish(event);
  },
  
  _updateButtonStateHandler: function(button, state) {
		if (this.options.buttonStateHandler) 
		    this.options.buttonStateHandler(button, state)
   },
  
  _scroll: function(delta, forceDisableNext) {      
    this.animRunning = delta > 0 ? "prev" : "next";
    
    if (this.options.animHandler)
      this.options.animHandler(this.carouselElemID, "before", this.animRunning);

    new Effect.MoveBy(this.carouselList, 0, delta * this.elementSize, this.options.animParameters);
    this.currentIndex -= delta;
    this._updateButtonStateHandler(this.options.prevElementID, this.currentIndex != 0);
    
    if (this.options.url && this.noMoreImages == false)
      enable = true;
    else
      enable = (this.currentIndex + this.options.numVisible < this.options.size);
    this._updateButtonStateHandler(this.options.nextElementID, (forceDisableNext ? false : enable));
  },
  
  _getLiElementSize: function() {
    var li = $(this.carouselList.getElementsByTagName("li")[0]);
		this.elementSize = li.getDimensions().width + parseFloat(li.getStyle("margin-left")) + parseFloat(li.getStyle("margin-right"));
  }
}
	






var Boxable = Class.create();
Boxable.prototype = {
	
	initialize: function(element) {
    	var options = Object.extend({
      		handle: false,
      		left: 0,
      		right: 0,
      		top: 0,
      		bottom: 0,
      		endeffect: false
    	}, arguments[1] || {});
    
		this.element      = $(element);
		this.element.drag = this;
		this.handle       = options.handle ? $(options.handle) : this.element;
		
		this.offsetTop = 0;
		this.offsetLeft = 0;
	
		oo = this.element;
		while (oo.tagName != 'BODY') {
			if (oo.offsetTop) this.offsetTop += oo.offsetTop;
			if (oo.offsetLeft) this.offsetLeft += oo.offsetLeft;
			oo = oo.offsetParent;
		}
	
		this.startX       = 0;
		this.startY       = 0;
    
		this.left         = options.left;
		this.right        = options.right;
		this.top          = options.top;
		this.bottom       = options.bottom;
		
		this.options      = options;
		this.active       = false;
		this.dragging     = false;
		this.rect         = false;
		this.outerRect    = false;
		this.innerRect    = false;
		
		Event.observe(this.handle, "mousedown", this.startDrag.bindAsEventListener(this));
		Event.observe(document, "mouseup", this.endDrag.bindAsEventListener(this));
		Event.observe(document, "mousemove", this.update.bindAsEventListener(this));
		
		// Create inner structure...
		this.innerRect = document.createElement('div');
		this.outerRect = document.createElement('div');
		this.outerRect.style.position = 'relative';
		this.outerRect.style.display = 'none';
		this.outerRect.appendChild(this.innerRect);
		this.element.appendChild(this.outerRect);
	
		// Draw current structure...
		this.draw();
		if(this.options.change) this.options.change(this);
  	},

	startDrag: function(event) {
    	if(Event.isLeftClick(event)) {
      		this.active = true;

			this.startX = parseInt(Event.pointerX(event) - this.offsetLeft);
			this.startY = parseInt(Event.pointerY(event) - this.offsetTop);
			this.left = this.right = this.startX;
			this.top = this.bottom = this.startY;
			Event.stop(event);
		}
  	},
  
  	endDrag: function(event) {
    	if (this.active && this.dragging) {
      		this.active = false;
      		this.dragging = false;
    
			if (this.left + 10 > this.right || 
				this.top + 10 > this.bottom) {
				
				this.top = this.bottom = this.left = this.right = 0;
				this.draw();
				if(this.options.change) this.options.change(this);
			}

			Event.stop(event);
    	}
  	},
  
  	draw: function() {
    	var outerStyle = this.outerRect.style;
    	var innerStyle = this.innerRect.style;

    	if (this.left != 0 || this.right != 0 || this.top != 0 || this.bottom != 0)
    	{
    		var width = this.right - this.left;
      		var height = this.bottom - this.top;
      
      		outerStyle.left = this.left + 'px';
      		outerStyle.width = (width - 2 > 0 ? width - 2 : 0) + 'px';   
      		outerStyle.top = this.top + 'px';
      		outerStyle.height = (height - 2 > 0 ? height - 2 : 0) + 'px';   

      		innerStyle.width = (width - 4 > 0 ? width - 4 : 0) + 'px';
      		innerStyle.height = (height - 4 > 0 ? height - 4 : 0) + 'px';

      		outerStyle.display = 'block';
    	} 
		else 
		{
			if(this.options.endeffect) 
        		this.options.endeffect(this.outerRect);
      		else
        		outerStyle.display = 'none';   
    	}
  	},
  
  	update: function(event) {
   		if(this.active) {
      		if(!this.dragging) {
        		this.dragging = true;
      		}
      
			var newX = parseInt(Event.pointerX(event) - this.offsetLeft);
			var newY = parseInt(Event.pointerY(event) - this.offsetTop);
      
			if (newX > this.startX) {
				this.left = this.startX; 
				this.right = newX;
			} else {
				this.left = newX;
				this.right = this.startX;
			}
      
			if (newY > this.startY) {
				this.top = this.startY; 
				this.bottom = newY;
			} else {
				this.top = newY;
				this.bottom = this.startY;
			}
      
			if (this.left < 0) this.left = 0;
			if (this.top < 0) this.top = 0;
			if (this.right > this.element.offsetWidth) this.right = parseInt(this.element.offsetWidth);
			if (this.bottom > this.element.offsetHeight) this.bottom = parseInt(this.element.offsetHeight);
			
			this.draw();
			
			if(this.options.change) this.options.change(this);
			
			Event.stop(event);
		}
  	}
}

Contents = Class.create();
Contents.prototype = {
  initialize: function(element) {
    var options = Object.extend({
      handle: false
    }, arguments[1] || {});

    this.element      = $(element);
    this.handle       = options.handle ? $(options.handle) : this.element;
    this.contents     = options.text ? options.text : this.element.alt;
    this.parser       = document.createElement('div');
	this.parser.innerHTML = this.contents;

	Event.observe(this.element, "mousemove", this.set.bindAsEventListener(this));
    Event.observe(this.element, "click", this.cancel.bindAsEventListener(this));
  },
  set: function(event) {
	if (this.handle.innerHTML != this.parser.innerHTML)
	    this.handle.innerHTML = this.parser.innerHTML;
    Event.stop(event);
  },
  clear: function(event) {
    this.handle.innerHTML = '';
  },
  cancel: function(event) {
	Event.stop(event);
  }
}

Effect.ShakeAway = function(element) {
  new Effect.Parallel(
    [ new Effect.Shake(element, {}), new Effect.Fade(element, {}) ]
  );
}



	var Overlay = Class.create();
	Overlay.prototype = {
		initialize: function(options) {
			this.options = Object.extend({
				opacity:	0.6,
				animate:	true,
				onHide:		null
			}, options || {});

			if (document.documentElement) {
				var pageHeight = Math.max(document.documentElement.scrollHeight, document.documentElement.clientHeight);
			} else if (window.innerHeight && window.scrollMaxY) {
				var pageHeight = window.innerHeight + window.scrollMaxY;
			} else {
				var pageHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight);
			}
			
			// Iframe to block form elements and plugins
			this.iframe  = document.createElement("iframe");
			this.iframe.setAttribute('id', 'dashboardIframe');
			this.iframe.setAttribute('frameborder', 0);
			Element.hide(this.iframe);
			document.body.appendChild(this.iframe);		

      		Position.absolutize(this.iframe);
			Element.setStyle(this.iframe, { 
				height: pageHeight + 'px',
				width: '100%',
				left: '0px',
				top: '0px',
				backgroundColor: '#ffffff',
				zIndex: 998
			});
			
			Element.setOpacity(this.iframe, 0);
			Element.show(this.iframe);

			// Overlay with opacity
			this.overlay = document.createElement("div");
			Element.hide(this.overlay);
			document.body.appendChild(this.overlay);		

      		Position.absolutize(this.overlay);
			Element.setStyle(this.overlay, { 
				height: pageHeight + 'px',
				width: '100%',
				left: '0px',
				top: '0px',
				backgroundColor: '#000000',
				zIndex: 999
			});
			
			Element.setOpacity(this.overlay, this.options.opacity);
			Element.show(this.overlay);

			if (this.options.onHide) {
				Event.observe(this.overlay, 'click', this.options.onHide);
			}
		},
		
		destroy: function() {
			if (this.options.animate) {
				new Effect.Fade(this.overlay, {
					duration: 0.4,
					afterFinish: function(e) {
						Element.remove(this.overlay);
						Element.remove(this.iframe);
					}.bind(this)
				});
			} else {
				Element.remove(this.overlay);
				Element.remove(this.iframe);
			}
		}
	};



var DashboardTree = Class.create();
DashboardTree.prototype = {

	initialize: function(options) {
		this.options = Object.extend({
			url:				null,
			title:				'',
			id:					'tree',
			top:				0,
			left:				0
		}, options || {});
		
		this.container = Builder.node('div');
		
		this.dialog = Builder.node('div', {id: this.options.id}, [
			this.container
		]);
		
		if (this.options.top > 0 || this.options.left > 0) {
			Element.setStyle(this.dialog, {
				top:  this.options.top + 'px',
				left: this.options.left + 'px'
			});
		}
	
		document.body.appendChild(this.dialog);
		
		if (this.options.url) {
			new Ajax.Updater(this.container, this.options.url, {method: 'get', onComplete: this.complete.bind(this)});
		}
	},
	
	complete: function() {
		if (/\/edit\//.test(window.location.href)) {
			var tab = window.location.href;

			if (tab = tab.match(/\/edit\/.*\/(.*)/)) {
				tab = tab[1];	
			}
			
			$$('#tree a').each(function(element) {
				element.href = element.href.replace(/\/view\//, '/edit/');
				
				if (tab) {
					element.href += '/' + tab;	
				}
			});
		}
		
		var selected = $$('#' + this.options.id + ' .selected');
		if (selected) {
			selected = selected[0];
			Element.scrollTo(selected);
			selected.focus();
		}
	},
	
	destroy: function() {
		if (this.dialog) {
			Element.remove(this.dialog);	
			this.dialog = null;
		}
	}
};

var DashboardLanguage = Class.create();
DashboardLanguage.prototype = {

	initialize: function(options) {
		this.options = Object.extend({
			url:				null,
			title:				'',
			id:					'tree',
			top:				0,
			left:				0
		}, options || {});
		
		this.container = Builder.node('div');
		
		this.dialog = Builder.node('div', {id: this.options.id}, [
			this.container
		]);
		
		if (this.options.top > 0 || this.options.left > 0) {
			Element.setStyle(this.dialog, {
				top:  this.options.top + 'px',
				left: this.options.left + 'px'
			});
		}
	
		document.body.appendChild(this.dialog);
		
		if (this.options.url) {
			new Ajax.Updater(this.container, this.options.url, {method: 'get', onComplete: this.complete.bind(this)});
		}
	},
	
	complete: function() {
		var selected = $$('#' + this.options.id + ' .selected');
		if (selected) {
			selected = selected[0];
			Element.scrollTo(selected);
			selected.focus();
		}
	},
	
	destroy: function() {
		if (this.dialog) {
			Element.remove(this.dialog);	
			this.dialog = null;
		}
	}
};

var DashboardSelector = Class.create();
DashboardSelector.prototype = {
	
	initialize: function(element, parentField, languageField, button) {
		this.element = $(element);
		this.parentField = $(parentField);
		this.languageField = $(languageField);
		this.button = $(button);
		this.selected = null;

		if (this.element) {
			Event.observe(this.element, 'click', this.click.bindAsEventListener(this));
			new Tree(this.element);
		}

		this.button.disabled = true;
	},
	
	click: function(e) {
		Event.stop(e);

		var element = Event.findElement(e, 'a');
		if (element.tagName) {
			this.unselect();
			this.select(Event.element(e));
		}
	},

	select: function(element) {
		var matches = /moveto_([^_]+)(_(.+))?/.exec(element.id);
		if (matches) {
			if (matches[1]) {
				this.parentField.value = matches[1];

				if (matches[3]) 
					this.languageField.value = matches[3];
				else
					this.languageField.value = '';
	
				Element.addClassName(element, 'selected');
				this.selected = element;
				this.button.disabled = false;
			}
		}
	},

	unselect: function() {
		this.button.disabled = true;
		this.parentField.value = '';
		Element.removeClassName(this.selected, 'selected');
	}
};

var DashboardForm = Class.create();
DashboardForm.prototype = {
	
	initialize: function(options) {
		this.options = Object.extend({
			url:				null,
			title:				'',
			id:					'dialog',
			top:				0,
			left:				0,
			wide:				false,
			onComplete:			null
		}, options || {});
		
		this.container = Builder.node('div');
		
		this.dialog = Builder.node('div', {id: this.options.id}, [
			Builder.node('h2', this.options.title),
			this.container
		]);
		
		if (this.options.wide) {
			Element.addClassName(this.dialog, 'wide');
		}
		
		if (this.options.top > 0 || this.options.left > 0) {
			Element.setStyle(this.dialog, {
				top:  this.options.top + 'px',
				left: this.options.left + 'px'
			});
		}
	
		document.body.appendChild(this.dialog);
		
		if (this.options.url) {
			new Ajax.Updater(this.container, this.options.url, {method: 'get', onComplete: this.complete.bind(this)});
		}
	},
	
	complete: function() {
		if (this.options.onComplete) {
			this.options.onComplete();
		}

		var form = this.container.getElementsByTagName('form');
		if (form) {
			var first = form[0].findFirstElement();
			if (first) {
				first.activate();	
			}
		}
	},
	
	destroy: function() {
		if (this.dialog) {
			Element.remove(this.dialog);	
			this.dialog = null;
		}
	}
};


var DashboardConfirm = Class.create();
DashboardConfirm.prototype = {
	
	initialize: function(options) {
		this.options = Object.extend({
			title:				'',
			okLabel:			'OK',
			cancelLabel:   		'Cancel',
			message:			'Are you sure?',
			id:					'dialog',
			messageClass:		'message',
			buttonsClass:		'buttons',
			onOk:				function () {},
			onCancel:			function () {},
			top:				0,
			left:				0
		}, options || {});		
		
		
		this.okButton = Builder.node('button', this.options.okLabel);
		this.cancelButton = Builder.node('button', this.options.cancelLabel);

		this.onClickOk = this.ok.bindAsEventListener(this);
		this.onClickCancel = this.cancel.bindAsEventListener(this);
		Event.observe(this.okButton, 'click', this.onClickOk);
		Event.observe(this.cancelButton, 'click', this.onClickCancel);
		
		this.dialog = Builder.node('div', {id: this.options.id}, [
			Builder.node('h2', this.options.title), 
			Builder.node('div', [
				Builder.node('p', {className: this.options.messageClass }, this.options.message),
				Builder.node('p', {className: this.options.buttonsClass }, [
					this.okButton,
					this.cancelButton
				])
			])
		]);
		
		if (this.options.top > 0 || this.options.left > 0) {
			Element.setStyle(this.dialog, {
				top:  this.options.top + 'px',
				left: this.options.left + 'px'
			});
		}
	
		document.body.appendChild(this.dialog);
		
		this.okButton.focus();
	},
	
	destroy: function() {
		if (this.dialog) {
			Element.remove(this.dialog);	
			this.dialog = null;
		}

		Event.stopObserving(this.okButton, 'click', this.onClickOk);
		Event.stopObserving(this.cancelButton, 'click', this.onClickCancel);
	},
	
	ok: function() {
		this.destroy();	

		if (this.options.onOk) {
			this.options.onOk();	
		}
	},
	
	cancel: function() {
		this.destroy();

		if (this.options.onCancel) {
			this.options.onCancel();	
		}
	}
};

var Dashboard = Class.create();
Dashboard.prototype = {

	initialize: function() {
		this.deleteButton = $('dashboardDelete');
		this.createButton = $('dashboardCreate');
		this.moveButton = $('dashboardMove');
		this.pageButton = $('dashboardPage');
		this.languageButton = $('dashboardLanguage');
		
		if (this.moveButton) {
			this.onClickMove  = this.movePage.bindAsEventListener(this);
			Event.observe(this.moveButton, 'click', this.onClickMove);
		}
		
		if (this.createButton) {
			this.onClickCreate  = this.createPage.bindAsEventListener(this);
			Event.observe(this.createButton, 'click', this.onClickCreate);
		}
		
		if (this.deleteButton) {
			this.onClickDelete  = this.deletePage.bindAsEventListener(this);
			Event.observe(this.deleteButton, 'click', this.onClickDelete);
		}
		
		if (this.pageButton) {
			this.onClickPage	= this.showTree.bindAsEventListener(this);
			Event.observe(this.pageButton, 'click', this.onClickPage);
		}

		if (this.languageButton) {
			this.onClickLanguage = this.showLanguage.bindAsEventListener(this);
			Event.observe(this.languageButton, 'click', this.onClickLanguage);
		}

		this.dialog = null;
		this.overlay = null;
	},
	
	showTree: function(e) {
		this.overlay = new Overlay({
			animate: false,
			opacity: 0,
			onHide: function() { 
				this.overlay.destroy(); 
				if (this.dialog) { 
					this.dialog.destroy(); 
				}
			}.bind(this)
		});
		
		var position = Position.cumulativeOffset(this.pageButton);
		
		this.dialog = new DashboardTree ({
			url:			this.pageButton.href,
			title:			'Ga naar:',
			left: 			position[0],
			top: 			position[1] + 20
		});

		Event.stop(e);	
	},
	
	showLanguage: function(e) {
		this.overlay = new Overlay({
			animate: false,
			opacity: 0,
			onHide: function() { 
				this.overlay.destroy(); 
				if (this.dialog) { 
					this.dialog.destroy(); 
				}
			}.bind(this)
		});
		
		var position = Position.cumulativeOffset(this.languageButton);
		
		this.dialog = new DashboardLanguage ({
			url:			this.languageButton.href,
			title:			'Taal:',
			left: 			position[0],
			top: 			position[1] + 20
		});

		Event.stop(e);	
	},
	
	movePage: function(e) {
		this.overlay = new Overlay({
			animate: false,
			onHide: function() { 
				this.overlay.destroy(); 
				if (this.dialog) { 
					this.dialog.destroy(); 
				}
			}.bind(this)
		});
					
		var position = Position.cumulativeOffset(this.moveButton);

		this.dialog = new DashboardForm ({
			url:			this.moveButton.href + '/ajax',
			title:			this.moveButton.text ? this.moveButton.text : this.moveButton.innerText,
			left: 			position[0] - 8,
			top: 			position[1],
			wide:			true,
			onComplete:		function() {
				new DashboardSelector('parentSelector', 'parent', 'language', 'moveButton');
			}
		});
		
		Event.stop(e);	
	},
	
	createPage: function(e) {
		this.overlay = new Overlay({
			animate: false,
			onHide: function() { 
				this.overlay.destroy(); 
				if (this.dialog) { 
					this.dialog.destroy(); 
				}
			}.bind(this)
		});
					
		var position = Position.cumulativeOffset(this.createButton);

		this.dialog = new DashboardForm ({
			url:			this.createButton.href + '/ajax',
			title:			this.createButton.text ? this.createButton.text : this.createButton.innerText,
			left: 			position[0] - 8,
			top: 			position[1]
		});
		
		Event.stop(e);	
	},
	
	deletePage: function(e) {
		this.overlay = new Overlay({
			animate: false,
			onHide: function() { 
				this.overlay.destroy(); 
				if (this.dialog) { 
					this.dialog.destroy(); 
				}
			}.bind(this)
		});
					
		var position = Position.cumulativeOffset(this.deleteButton);
		
		this.dialog = new DashboardConfirm ({
			title:			this.deleteButton.text ? this.deleteButton.text : this.deleteButton.innerText,
			okLabel: 		'Ja',
			cancelLabel: 	'Nee',
			message: 		'Weet u zeker dat u deze pagina wilt verwijderen?',
			left: 			position[0] - 8,
			top: 			position[1],
			onOk: 			this.deletePageOk.bind(this),
			onCancel: 		this.deletePageCancel.bind(this)
		});

		Event.stop(e);	
	},
	
	deletePageOk: function() {
		window.location = this.deleteButton.href;
	},
	
	deletePageCancel: function() {
		if (this.overlay) {
			this.overlay.destroy();	
		}
	}
};


Event.onDOMReady(function (event) {
	if ($('dashboard')) {
		new Dashboard('dashboard');	
	}
});




var Tree = Class.create();
Tree.prototype = {
	
	initialize: function(element, options) {
		this.options = Object.extend({
			root: true
		}, options || {});
		
		this.element = $(element);

		if (this.options.root) {
			Element.addClassName(this.element, 'tree');
		}

		var listitem = null;

		for (var i = 0; i < this.element.childNodes.length; i++) 
		{
			if (this.element.childNodes[i].tagName && 
				this.element.childNodes[i].tagName.toLowerCase() == 'li') 
			{
				listitem = this.element.childNodes[i];
			
				var spanC = Builder.node('span', { className: 'c' });
				var spanB = Builder.node('span', { className: 'b' }, [ spanC ]);
				var spanA = Builder.node('span', { className: 'a' }, [ spanB ]);
				
				if (Element.hasClassName(this.element, 'closed')) {
					Element.setClassName(spanA, 'closed');
				}
			
				Event.observe(spanA, 'click', this.toggle.bindAsEventListener(this));

				// Find the UL within the LI, if it exists
				var stoppingPoint = listitem.childNodes.length;
				var startingPoint = 0;
				var childUL = null;

				for (var j = 0; j < listitem.childNodes.length; j++) {
					if (listitem.childNodes[j].tagName && listitem.childNodes[j].tagName.toLowerCase() == 'ul') {
						childUL = listitem.childNodes[j];
						stoppingPoint = j;
						break;					
					}
				}
				
				for (var j = startingPoint; j < stoppingPoint; j++) {
					spanC.appendChild(listitem.childNodes[startingPoint]);
				}
				
				// Insert the outermost extra span into the tree
				if (listitem.childNodes.length > startingPoint) {
					listitem.insertBefore(spanA, listitem.childNodes[startingPoint]);
				} else {
					listitem.appendChild(spanA);
				}
				
				// Process the children
				if(childUL != null) {
					new Tree(childUL, { root: false	});
					Element.addClassName(listitem, 'children');
					Element.addClassName(spanA, 'children');
				}
			}
		}

		if (listitem != null) {
			Element.addClassName(listitem, 'last');
			Element.addClassName(spanA, 'last');
		} 
	},
	
	
	toggle: function(e) {
		if (Event.findElement(e, 'span') != Event.element(e)) {
			return;	
		}

		Event.stop(e);

		var listitem = Event.findElement(e, 'li');

		// console.debug([Event.findElement(e, 'span'), Event.element(e)]);


		if (Element.hasClassName(listitem, 'children')) {
			if (Element.hasClassName(listitem, 'closed')) {
				Element.removeClassName(listitem, 'closed');
				Element.removeClassName(listitem.getElementsByTagName('li')[0], 'closed');
			} else {
				Element.addClassName(listitem, 'closed');
				Element.addClassName(listitem.getElementsByTagName('li')[0], 'closed');
			}
		}
	}
	
};