


Event.observe(window, 'load', function() {
	prepMenus();	
});

function prepMenus(){
	closeAllMenus();

	$$(".subMenu li a, .mainMenu li a").each(function(linkitem){
		linkitem.observe("mouseover", linkMouseOver);
		linkitem.observe("mouseout", linkMouseOut);
	});

}
var actionDelay;
var openMenu;
var direction=1;

function linkMouseOver(e){
	var submenu = Event.element(e).up().down("ul");
	if(!submenu){
		closeAllMenus( Event.element(e));
	}
	if(submenu && submenu.style.display=="none"){
		openMenu = submenu;
		closeAllMenus(submenu);
		submenu.style.position="absolute";
		var anchor = submenu.up().positionedOffset();
		var anchorAbs = submenu.up().cumulativeOffset();
		if(submenu.up().up().className=="subMenu"){
			//Submenus drop down to the left by default
			if(anchorAbs.left + ((submenu.getWidth()*direction) *2) > document.viewport.getWidth() || anchorAbs.left + ((submenu.getWidth()*direction) *2) < 0) direction *= -1;
			submenu.style.top = anchor.top-10 + "px";
			submenu.style.left = anchor.left + ((submenu.getWidth()-10)*direction) + "px";
		} else {
			//This is a top level item - work out if we are vertical or horizontal
			if(submenu.up(".verticalMenu")){
				//Vertical menus drop to the left
				submenu.style.top = anchor.top + "px";
				submenu.style.left = anchor.left + submenu.up().getWidth() + "px";
			} else {
				//Main menus drop down to the bottom
				submenu.style.top = anchor.top + submenu.up().getHeight() + "px";
				submenu.style.left = anchor.left + "px";
			}
		}
		Ext.get(submenu).slideIn('t', {
		    easing: 'easeOut',
		    duration: .5
		});
	}
	clearTimeout(actionDelay);
}

function linkMouseOut(e){
	actionDelay = hideSubMenu.delay(1,Event.element(e).up().down("ul"));
}

function hideSubMenu(submenu){
	//if(submenu){
		//submenu.style.display="none";
		//closeMenu();
		closeAllMenus();
	//}
}

function closeAllMenus(exceptTree){
	var submenus = $$(".subMenu");
	for(var i=0, l=submenus.length;i<l;i++){
		if(exceptTree){
			if(submenus[i].descendants().indexOf(exceptTree)==-1)submenus[i].hide();
		} else {
			submenus[i].hide();
		}
	}
}

function closeMenu(){
	//Nicely folds up all open menus
	var menu=openMenu;
	if(!menu || menu.className!="subMenu")return;
	//showToast("Closing Menu!",menu.tagName);
	Ext.get(menu).ghost('t', {
	    duration: .3,
	    useDisplay:true,
	    callback:closeMenu
	});
	openMenu=menu.up("ul");
	//openMenu="";
}

/*
function wiggleMe(){
	var submenus = $$(".subMenu");
	new Effect.Move(submenus[Math.floor(Math.random()*submenus.length)], { x:0, y: Math.floor(Math.random()*2000-1000), mode: 'relative' });
	setTimeout("wiggleMe()",1000);
}
setTimeout("wiggleMe()",5000);
*/



var XerxesSmoothScroll = function(config){
	Ext.apply(this, config);
	Ext.onReady(this.init.createDelegate(this));
}

XerxesSmoothScroll.prototype = {
	scrollTimer: null,
	increment: 4, //Increments that the scroller jumps by
	interval: 60, //ms delay between increments
	scrollTarget: 0, // Target top position on the page we are scrolling to
	callback:null,
	init:function(){
		//If we have a small window, scroll it to the content
		/*if (this.getWindowHeight() < 600 && this.getScrollTop() == 0) {
			var pContent = Ext.select(".mainMenu");
			if (!pContent) return;
			pContent = pContent.first(); //Grab the first instance
			if (!pContent) return;
			this.scrollTo(pContent);
		}*/
		

	},
	getScrollTop: function(){
		body = document.body
		d = document.documentElement
		if (body && body.scrollTop) return body.scrollTop
		if (d && d.scrollTop) return d.scrollTop
		if (window.pageYOffset) return window.pageYOffset
		return 0
	},
	getWindowHeight:function(){
		return window.innerHeight || document.documentElement.clientHeight;
	},
	scrollTo:function(el,callback,offset){
		if(callback)this.callback = callback;
		this.scrollTarget = Ext.get(el).getTop();
		if(offset)this.scrollTarget += offset;
		this.scrollAnim(); //Start animating
	},
	scrollToPoint:function(point,callback){
		if(callback)this.callback = callback;
		this.scrollTarget = point;
		this.scrollAnim(); //Start animating
	},
	stopScroll:function(){
		clearTimeout(this.scrollTimer);
		if(this.callback)Ext.callback(this.callback); //Call any specified callback
		this.callback = null;
		this.scrollTarget = 0;
	},
	scrollAnim: function(){
		clearTimeout(this.scrollTimer);
		i = this.getWindowHeight();
		h = document.body.scrollHeight;
		a = this.getScrollTop()
		if (this.scrollTarget > a) {
			if (h - this.scrollTarget > i) {
				a += Math.ceil((this.scrollTarget - a) / this.increment)
			} else {
				a += Math.ceil((this.scrollTarget - a - (h - this.scrollTarget)) / this.increment)
			}
			
		} else {
			a = a + (this.scrollTarget - a) / this.increment;
		}
		window.scrollTo(0, a)
		if (a != this.scrollTarget) {
			this.scrollAnim.defer(this.interval, this)
		} else {
			this.stopScroll();
		}
	}
}

var XScroll = new XerxesSmoothScroll();




		Ext.Updater.defaults.loadScripts=true;
		var msgCt;
		function showToast(title, text){
            if(!msgCt){
                msgCt = Ext.DomHelper.insertFirst(document.body, {id:'msg-div'}, true);
            }
            msgCt.anchorTo(document, 't-t');
            var m = Ext.DomHelper.append(msgCt, {html:createBox(title, text)}, true);
            m.on("click",toastClickCallback,m);
            m.slideIn('t').pause(5).ghost("t", {remove:true});
        }
        function showStickyToast(title, text){
            if(!msgCt){
                msgCt = Ext.DomHelper.insertFirst(document.body, {id:'msg-div'}, true);
            }
            msgCt.anchorTo(document, 't-t');
            var m = Ext.DomHelper.append(msgCt, {html:createBox(title, text)}, true);
            m.on("click",toastClickCallback,m);
            m.slideIn('t');//.pause(5).ghost("t", {remove:true});
        }
        function setMask(maskText){
			clearMask();
			var mask = document.createElement("div");
			mask.className = "ext-el-mask";
			mask.id = "ScriptManagerMask";
			mask.setAttribute("style", "text-align:center;background:#000000;opacity:0.9;");
			mask.innerHTML = "&nbsp;";
			document.body.appendChild(mask);
			var maskMessage = document.createElement("div");
			maskMessage.className = "ext-el-mask-msg x-mask-loading";
			maskMessage.setAttribute("style", "position:absolute;top:-500px;z-index:2000000;")
			maskMessage.innerHTML = "<div>" + maskText + "<br /></div><p style=\"text-align:center;font-style:italic;font-size:10pt;\">You will be redirected shortly.</p>";
			maskMessage.id = "ScriptManagerMaskMessage";
			document.body.appendChild(maskMessage);
			//Fix by cboden for IE masking
			var winWidth = (window.innerWidth || document.getElementsByTagName('body')[0].clientWidth);
			var winHeight = (window.innerHeight || document.getElementsByTagName('body')[0].clientHeight);
			maskMessage.style.left = ((winWidth / 2) - (maskMessage.offsetWidth / 2)) + "px";
			maskMessage.style.top = ((winHeight / 2) - (maskMessage.offsetHeight / 2)) + "px";
		}
		function clearMask(){
			var mask = document.getElementById("ScriptManagerMask");
			var maskMessage = document.getElementById("ScriptManagerMaskMessage");
			if (mask) 
				document.body.removeChild(mask);
			if (maskMessage) 
				document.body.removeChild(maskMessage);
		}
        function toastClickCallback(evt,el){
        	this.ghost("t", {remove:true}) 
        }
        function showWindow(title,url,width,height,modal,draggable,resizable){
        	var win = new Ext.Window({
                title		: title,
                renderTo	: document.body,
                autoLoad	: url,
                layout      : 'fit',
                width       : width,
                autoScroll	: true,
                bodyStyle	:"padding:10px;",
                height      : height,
                modal		: modal,
                draggable	: draggable,
                buttons		: [	{
						   		text: 'Cancel',
						   		handler:closeWin
						    }],
                resizable	: resizable
            });
	        win.show();
	        function closeWin(){
        		win.close();
				document.location.href = document.location.href;
        	}
        }
        
       function showTipWindow(title,contentElement,width,height,modal,draggable,resizable){
        	var win = new Ext.Window({
                title		: title,
                renderTo	: document.body,
                contentEl	: contentElement,
                layout      : 'fit',
                width       : width,
                autoScroll	: true,
                autoShow	: true,
                bodyStyle	:"padding:10px;",
                height      : height,
                modal		: modal,
                draggable	: draggable,
                closeAction	: 'hide',
                buttons		: [	{
						   		text: 'Cancel',
						   		handler:closeWin
						    }],                
                resizable	: resizable
            });
	        win.show();
	        function closeWin(){
        		win.hide()
        	}
        }
        
        function openWindowUrl(url){
        	showWindow(url,url,600,500,true,true,true);
        }
        function setUrl(url){
			document.location.href=url;
		}
        
        function createBox(t, s){
        		return ['<div class="msg">',
                '<div class="x-box-tl"><div class="x-box-tr"><div class="x-box-tc"></div></div></div>',
                '<div class="x-box-ml"><div class="x-box-mr"><div class="x-box-mc"><h3>', t, '</h3>', s, '</div></div></div>',
                '<div class="x-box-bl"><div class="x-box-br"><div class="x-box-bc"></div></div></div>',
                '</div>'].join('');
    	}
    	
 //Scroller
 function createScroller(zoneId,vertical,slideDuration,jumpDelay,direction){
	if(direction === undefined)direction=true;
	if(vertical === undefined)vertical=true;
	if(slideDuration === undefined)slideDuration=1;
	if(jumpDelay === undefined)jumpDelay=1;
	var zone = Ext.get(zoneId);
	if(zone){
		if(direction){
			if(vertical){
				direction = zone.scroll("b",zone.getHeight(),{duration:slideDuration});
			} else {
				direction = zone.scroll("l",zone.getWidth(),{duration:slideDuration});
			}
		} else{
			if(vertical){
				zone.scrollTo("top",0,{duration:slideDuration});
			} else {
				zone.scrollTo("left",0,{duration:slideDuration});
			}
			direction = true;
		}
		createScroller.defer((slideDuration * 1000) + (jumpDelay*1000),null,[zoneId,vertical,slideDuration,jumpDelay,direction]);
	}
}  
    	
    	var cookiePath = '/';

// Cookie functions -------------------------------------------------------------
// Thanx a lot to Jerry Aman, Optima System
// and Bill Dortch, hIdaho Design for the free use of their code.
// Found on http://www.cookiecentral.com/js_cookie8.htm

function getCookieVal( offset )
{
  var endstr = document.cookie.indexOf ( ";", offset );

  if ( endstr == -1 )
  {
    endstr = document.cookie.length;
  }
  return unescape( document.cookie.substring( offset, endstr ) );
}

function getCookie( name )
{
  var arg = name + "=";
  var alen = arg.length;
  var clen = document.cookie.length;
  var i = 0;

  while ( i < clen )
  {
    var j = i + alen;

    if ( document.cookie.substring( i, j ) == arg )
    {
      return getCookieVal ( j );
    }

    i = document.cookie.indexOf( " ", i ) + 1;

    if ( i == 0 )
    {
      break;
    }
  }
  return null;
}

function setCookie( name, value )
{
  var argv = setCookie.arguments;
  var argc = setCookie.arguments.length;
  var expires = (argc > 2) ? argv[2] : null;
  var path = (argc > 3) ? argv[3] : null;
  var domain = (argc > 4) ? argv[4] : null;
  var secure = (argc > 5) ? argv[5] : false;

  document.cookie = name + "=" + escape (value) +
    ( ( expires == null ) ? "" : ( "; expires=" + expires.toGMTString() ) ) +
    ( ( path == null ) ? "" : ( "; path=" + path ) ) +
    ( ( domain == null ) ? "" : ( "; domain=" + domain ) ) +
    ( ( secure == true ) ? "; secure" : "" );
}

function deleteCookie ( name )
{
  var exp = new Date();
  exp.setTime ( exp.getTime() - 1 );  // This cookie is history
  setCookie( name, "", exp, cookiePath );
}


//-------------------------------------------------------------------------------
//This function tests if the cookies are enabled.

function testCookie()
{
  var expDate = new Date();
  //valid one minute
  expDate.setTime( expDate.getTime() + ( 60 * 1000 ) );
  setCookie( "testCookie", "OK", expDate );
  testing = getCookie( "testCookie" );

  if ( testing == "OK" )
  {
    return true;
  }
  else
  {
    return false;
  }
}

// End of Cookie functions ------------------------------------------------------
    	
function xerxesCompatibilityTests(){
	if(!testCookie() && !Ext.isSafari){
		showStickyToast("Cookies Are Disabled", "We have detected that you have cookies disabled on your browser. Please note that to be able to use this site correctly you must enable cookies. A guide to enable cookies for your browser can be <a href='http://www.google.com/cookies.html' target='_BLANK'>found here</a>.")
	}
	if(Ext.isIE6){
		showStickyToast("Internet Explorer 6", "We have detected that you are using Internet Explorer 6. This browser is now eight years old and has difficulty working with modern websites such as this one. Please upgrade your browser by using one of the following links: <br /><br /><a href='http://www.mozilla-europe.org/en/firefox/' target='_blank'>Latest Firefox</a><br /><a href='http://www.microsoft.com/windows/internet-explorer/default.aspx' target='_BLANK'>Latest Internet Explorer</a>. <br /><br /> Click to dismiss this message, however please be aware that interactive features such as online ticketing and bookings may not work as intended.")
	}
	
}    	

Ext.onReady(xerxesCompatibilityTests);
    	

    	


function showShop(shopName,shopURL){
		var win = new Ext.Window({
                title		: shopName,
                renderTo	: document.body,
                layout      : 'fit',
                //modal		:	true,
                width       : 870,
                height      : 600,
                html		: "Loading..",
                autoScroll	: true,
                bodyStyle	: "background-color:#ffffff",
                modal		: true,
                header		: false,
                draggable	: true,
                resizable	: false
            });
        win.show();
        win.load({
        			url:""+shopURL,
        			scripts:true
        		
        		});
}

function showItem(itemName, itemURL){
		var win = new Ext.Window({
                title		: itemName,
                renderTo	: document.body,
                layout      : 'fit',
                //modal		:	true,
                width       : 870,
                height      : 600,
                html		: "Loading..",
                autoScroll	: true,
                bodyStyle	: "background-color:#ffffff",
                modal		: true,
                header		: false,
                draggable	: true,
                resizable	: false
            });
        win.show();
        win.load({
        			url:""+itemURL,
        			scripts:true
        		});
}

function addItemToCart(itemUrl){
	Ext.Ajax.request({
		method: 'GET',
		url: ''+itemUrl,
		success: updateCartSuccess,
		failure: updateCartFailure
	});
}

function updateCartSuccess(response, options){
	showToast("Shopping Cart",response.responseText);
}

function updateCartFailure(response, options){
	showToast("Shopping Cart","The Item was not added to your shopping cart, please try to add it again.");
}

function openItem(itemUrl){
	//var updater = Ext.get($("shop{{{$shopInfo.id}}}").up()).getUpdater();
	//updater.update({ url: ""+itemUrl });
	
	document.location.href = itemUrl;
}

function changeCat(catId){
	//var updater = Ext.get($("shop{{{$shopInfo.id}}}").up()).getUpdater();
	//updater.update({ url: "{{{$showurl}}}app/shopping/viewShop/{{{$shopInfo.wiki_title}}}/&catId="+catId });
	
	document.location.href = "{{{$showurl}}}app/shopping/viewShop/{{{$shopInfo.wiki_title}}}/&catId="+catId;
}

function backToShop(){
	//var updater = Ext.get($("item{{{$itemInfo.id}}}").up()).getUpdater();
	//updater.update({ url: "{{{$showurl}}}app/shopping/viewShop/{{{$shopInfo.wiki_title}}}/" });
	
	//document.location.href = "{{{$showurl}}}app/shopping/viewShop/{{{$shopInfo.wiki_title}}}/";
}

function showItemPicture(imgTitle, imgUrl){
        window.open(imgUrl);
        /*
        var pwin = new Ext.Window({
               title		: imgTitle,
               renderTo		: document.body,
               html			: '<img src="'+imgUrl+'" id="shopBigImage" />',
               layout      	: 'fit',
               autoWidth	: true,
               autoScroll	: true,
               bodyStyle	:"padding:2px;",
               autoHeight	: true,
               modal		: true,
               draggable	: true,
               resizable	: false
           });
        pwin.show();
        var mask = pwin.container.select('div.ext-el-mask')
        mask.on("click",function(){this.close()},pwin);
        */
}


/**
 * @class Ext.grid.TableGrid
 * @extends Ext.grid.Grid
 * A Grid which creates itself from an existing HTML table element.
 * @constructor
 * @param {String/HTMLElement/Ext.Element} table The table element from which this grid will be created - 
 * The table MUST have some type of size defined for the grid to fill. The container will be 
 * automatically set to position relative if it isn't already.
 * @param {Object} config A config object that sets properties on this grid and has two additional (optional)
 * properties: fields and columns which allow for customizing data fields and columns for this grid.
 * @history
 * 2007-03-01 Original version by Nige "Animal" White
 * 2007-03-10 jvs Slightly refactored to reuse existing classes
 */
Ext.grid.TableGrid = function(table, config) {
  config = config || {};
  Ext.apply(this, config);
  var cf = config.fields || [], ch = config.columns || [];
  table = Ext.get(table);

  var ct = table.insertSibling();

  var fields = [], cols = [];
  var headers = table.query("thead th");
  for (var i = 0, h; h = headers[i]; i++) {
    var text = h.innerHTML;
    var name = 'tcol-'+i;

    fields.push(Ext.applyIf(cf[i] || {}, {
      name: name,
      mapping: 'td:nth('+(i+1)+')/@innerHTML'
    }));

    cols.push(Ext.applyIf(ch[i] || {}, {
      'header': text,
      'dataIndex': name,
      'width': h.offsetWidth,
      'tooltip': h.title,
      'sortable': true
    }));
  }

  var ds  = new Ext.data.Store({
    reader: new Ext.data.XmlReader({
      record:'tbody tr'
    }, fields)
  });

  ds.loadData(table.dom);

  var cm = new Ext.grid.ColumnModel(cols);

  if (config.width || config.height) {
    ct.setSize(config.width || 'auto', config.height || 'auto');
  } else {
    ct.setWidth(table.getWidth());
  }

  if (config.remove !== false) {
    table.remove();
  }

  Ext.applyIf(this, {
    'ds': ds,
    'cm': cm,
    'sm': new Ext.grid.RowSelectionModel(),
    autoHeight: true,
    autoWidth: false
  });
  Ext.grid.TableGrid.superclass.constructor.call(this, ct, {});
};

Ext.extend(Ext.grid.TableGrid, Ext.grid.GridPanel);


/*
 * Ext Core Library Examples 3.0
 * http://extjs.com/
 * Copyright(c) 2006-2009, Ext JS, LLC.
 *
 * The MIT License
 *
 * 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.
 *
 */
Ext.ns('Ext.ux');

Ext.ux.Lightbox = (function(){
	var els = {}, images = [], activeImage, initialized = false, selectors = [];
	
	return {
		overlayOpacity: 0.85,
		animate: true,
		resizeSpeed: 8,
		borderSize: 10,
		labelImage: "Image",
		labelOf: "of",
		
		init: function(){
			this.resizeDuration = this.animate ? ((11 - this.resizeSpeed) * 0.15) : 0;
			this.overlayDuration = this.animate ? 0.2 : 0;
			
			if (!initialized) {
				Ext.apply(this, Ext.util.Observable.prototype);
				Ext.util.Observable.constructor.call(this);
				this.addEvents('open', 'close');
				this.initMarkup();
				this.initEvents();
				initialized = true;
			}
		},
		
		initMarkup: function(){
			els.shim = Ext.DomHelper.append(document.body, {
				tag: 'iframe',
				id: 'ux-lightbox-shim'
			}, true);
			els.overlay = Ext.DomHelper.append(document.body, {
				id: 'ux-lightbox-overlay'
			}, true);
			
			var lightboxTpl = new Ext.Template(this.getTemplate());
			els.lightbox = lightboxTpl.append(document.body, {}, true);
			
			var ids = 'outerImageContainer imageContainer image hoverNav navPrev navNext loading loadingLink ' +
			'outerDataContainer dataContainer data details caption description bottomNav navClose';
			
			Ext.each(ids.split(' '), function(id){
				els[id] = Ext.get('ux-lightbox-' + id);
				els[id].setVisibilityMode(Ext.Element.DISPLAY);
			});
			
			els.overlay.visibilityMode = els.lightbox.visibilityMode = els.shim.visibilityMode = Ext.Element.DISPLAY;
			Ext.get("ux-lightbox").setVisibilityMode(Ext.Element.DISPLAY);
			els.overlay.hide();
			els.shim.hide();
			els.lightbox.hide();
			
			var size = (this.animate ? 250 : 1) + 'px';
			els.outerImageContainer.setStyle({
				width: size,
				height: size
			});
		},
		
		getTemplate: function(){
			return ['<div id="ux-lightbox">', '<div id="ux-lightbox-outerImageContainer">', '<div id="ux-lightbox-imageContainer">', '<img id="ux-lightbox-image" src="">', '<div id="ux-lightbox-hoverNav">', '<a href="#" id="ux-lightbox-navPrev"></a>', '<a href="#" id="ux-lightbox-navNext"></a>', '</div>', '<div id="ux-lightbox-loading">', '<a id="ux-lightbox-loadingLink"></a>', '</div>', '</div>', '</div>', '<div id="ux-lightbox-outerDataContainer">', '<div id="ux-lightbox-dataContainer">', '<div id="ux-lightbox-data">', '<div id="ux-lightbox-details">', '<span id="ux-lightbox-caption"></span>', '<span id="ux-lightbox-description"></span>', '</div>', '<div id="ux-lightbox-bottomNav">', '<a href="#" id="ux-lightbox-navClose"></a>', '</div>', '</div>', '</div>', '</div>', '</div>'];
		},
		
		initEvents: function(){
			var close = function(ev){
				ev.preventDefault();
				this.close();
			};
			
			els.overlay.on('click', close, this);
			els.loadingLink.on('click', close, this);
			els.navClose.on('click', close, this);
			
			els.lightbox.on('click', function(ev){
				if (ev.getTarget().id == 'ux-lightbox') {
					this.close();
				}
			}, this);
			
			els.navPrev.on('click', function(ev){
				ev.preventDefault();
				this.setImage(activeImage - 1);
			}, this);
			
			els.navNext.on('click', function(ev){
				ev.preventDefault();
				this.setImage(activeImage + 1);
			}, this);
		},
		
		register: function(sel, group){
			if (selectors.indexOf(sel) === -1) {
				selectors.push(sel);
				
				Ext.fly(document).on('click', function(ev){
					var target = ev.getTarget(sel);
					
					if (target) {
						ev.preventDefault();
						this.open(target, sel, group);
					}
				}, this);
			}
		},
		
		open: function(image, sel, group){
			group = group || false;
			
			var viewSize = this.getViewSize();
			els.overlay.setStyle({
				width: viewSize[0] + 'px',
				height: viewSize[1] + 'px'
			});
			els.shim.setStyle({
				width: viewSize[0] + 'px',
				height: viewSize[1] + 'px'
			}).show();
			
			els.overlay.fadeIn({
				duration: this.overlayDuration,
				endOpacity: this.overlayOpacity,
				callback: function(){
					images = [];
					
					var index = 0;
					if (!group) {
						images.push([image.href, image.title,image.down("img").alt]);
					}
					else {
						var setItems = Ext.query(sel);
						Ext.each(setItems, function(item){
							if (item.href) {
								images.push([item.href, item.title,image.down("img").alt]);
							}
						});
						
						while (images[index][0] != image.href) {
							index++;
						}
					}
					
					// calculate top and left offset for the lightbox
					var pageScroll = Ext.fly(document).getScroll();
					
					var lightboxTop = pageScroll.top + (Ext.lib.Dom.getViewportHeight() / 10);
					var lightboxLeft = pageScroll.left;
					els.lightbox.setStyle({
						top: lightboxTop + 'px',
						left: lightboxLeft + 'px'
					}).show();
					
					this.setImage(index);
					
					this.fireEvent('open', images[index]);
				},
				scope: this
			});
		},
		
		setImage: function(index){
			activeImage = index;
			
			this.disableKeyNav();
			if (this.animate) {
				els.loading.show();
			}
			
			els.image.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.dataContainer.setOpacity(0.0001);
			els.description.hide();
			
			var preload = new Image();
			preload.onload = (function(){
				els.image.dom.src = images[activeImage][0];
				this.resizeImage(preload.width, preload.height);
			}).createDelegate(this);
			preload.src = images[activeImage][0];
		},
		
		resizeImage: function(w, h){
			var wCur = els.outerImageContainer.getWidth();
			var hCur = els.outerImageContainer.getHeight();
			
			var wNew = (w + this.borderSize * 2);
			var hNew = (h + this.borderSize * 2);
			
			var wDiff = wCur - wNew;
			var hDiff = hCur - hNew;
			
			var queueLength = 0;
			
			if (hDiff != 0 || wDiff != 0) {
				els.outerImageContainer.syncFx().shift({
					height: hNew,
					duration: this.resizeDuration
				}).shift({
					width: wNew,
					duration: this.resizeDuration
				});
				queueLength++;
			}
			
			var timeout = 0;
			if ((hDiff == 0) && (wDiff == 0)) {
				timeout = (Ext.isIE) ? 250 : 100;
			}
			
			(function(){
				els.hoverNav.setWidth(els.imageContainer.getWidth() + 'px');
				
				els.navPrev.setHeight(h + 'px');
				els.navNext.setHeight(h + 'px');
				
				els.outerDataContainer.setWidth(wNew + 'px');
				
				this.showImage();
			}).createDelegate(this).defer((this.resizeDuration * 1000) + timeout);
		},
		
		showImage: function(){
			els.loading.hide();
			els.image.fadeIn({
				duration: this.resizeDuration,
				scope: this,
				callback: function(){
					this.updateDetails();
				}
			});
			this.preloadImages();
		},
		
		updateDetails: function(){
			els.details.setWidth((els.data.getWidth(true) - els.navClose.getWidth() - 10) + 'px');
			
			els.caption.update(images[activeImage][1]);
			
			els.caption.show();
			if (images[activeImage][2]) {
				els.description.update("<br />"+images[activeImage][2]);
				els.description.show();
			}
			
			els.dataContainer.syncFx().slideIn('t', {
				duration: this.resizeDuration / 2
			}).fadeIn({
				duration: this.resizeDuration / 2,
				scope: this,
				callback: function(){
					var viewSize = this.getViewSize();
					els.overlay.setHeight(viewSize[1] + 'px');
					this.updateNav();
				}
			})
		},
		
		updateNav: function(){
			this.enableKeyNav();
			
			els.hoverNav.show();
			
			// if not first image in set, display prev image button
			if (activeImage > 0) 
				els.navPrev.show();
			
			// if not last image in set, display next image button
			if (activeImage < (images.length - 1)) 
				els.navNext.show();
		},
		
		enableKeyNav: function(){
			Ext.fly(document).on('keydown', this.keyNavAction, this);
		},
		
		disableKeyNav: function(){
			Ext.fly(document).un('keydown', this.keyNavAction, this);
		},
		
		keyNavAction: function(ev){
			var keyCode = ev.getKey();
			
			if (keyCode == 88 || // x
			keyCode == 67 || // c
			keyCode == 27) {
				this.close();
			}
			else 
				if (keyCode == 80 || keyCode == 37) { // display previous image
					if (activeImage != 0) {
						this.setImage(activeImage - 1);
					}
				}
				else 
					if (keyCode == 78 || keyCode == 39) { // display next image
						if (activeImage != (images.length - 1)) {
							this.setImage(activeImage + 1);
						}
					}
		},
		
		preloadImages: function(){
			var next, prev;
			if (images.length > activeImage + 1) {
				next = new Image();
				next.src = images[activeImage + 1][0];
			}
			if (activeImage > 0) {
				prev = new Image();
				prev.src = images[activeImage - 1][0];
			}
		},
		
		close: function(){
			this.disableKeyNav();
			els.lightbox.hide();
			els.overlay.fadeOut({
				duration: this.overlayDuration
			});
			els.shim.hide();
			els.image.hide();
			els.hoverNav.hide();
			els.navPrev.hide();
			els.navNext.hide();
			els.dataContainer.hide();
			els.description.hide();
			this.fireEvent('close', activeImage);
		},
		
		getViewSize: function(){
			return [Ext.lib.Dom.getViewWidth(true), Ext.lib.Dom.getViewHeight(true)];
		}
	}
})();

Ext.onReady(Ext.ux.Lightbox.init, Ext.ux.Lightbox);
