var box = Class.create({
	
	folder:'large',
	speed:0.45,
	controlDelay:0.5,
	
	messages: 
	{
		hideControls:	  'hide controls',
		keyboardIntructs: 'use the arrow keys to move through the items and the esc key to exit',
		dragNavIntructs:  'click and drag to move around the [type]',
		showControls:	  'show controls',
		showMoreInfo:	  'show more information about this item',
		hideMoreInfo:	  'hide the extra information'
	},

	initialize:function(){
		this.build();
		
		this.observe();
		},
	
	observe:function(element){
			
		$$('body')[0].observe('click',(function(event){
			this.element = event.findElement('.box');
			
			if(!this.element) return false;
			
			this.tagName = this.element.tagName;
			this.event = event;
			
			if(this.element.hasClassName('box'))
			{
				this.begin();
			}
			
			}).bind(this));
			
		$('boxContainer').observe('click', (function(event){
				this.boxElement = Event.element(event);
				var id = this.boxElement.id;
				
				if(id == 'boxClose' || id == 'boxOverlay')
					return this.close();
				if(id == 'boxPrev')
					return this.shiftUp();
				if(id == 'boxNext')
					return this.shiftDown();
				if(Event.findElement(event, '#boxMoreInfoButton'))
					return this.moreInfo();
				if(Event.findElement(event, '#boxHideButton'))
					return this.hideBar();
			
			}).bind(this));
			
		$('boxHideButton').observe('mouseenter', (function(event){
				arrow = $('boxHideButton').down('.boxNav');
				this.setMessage(arrow.hasClassName('boxNavBottom') ? this.messages.hideControls : this.messages.showControls);
			}).bind(this));
			
		$('boxHideButton').observe('mouseleave', (function(event){
				this.hideMessage.bind(this).delay(3);
			}).bind(this));
			
		$('boxMoreInfoButton').observe('mouseenter', (function(event){
				arrow = $('boxMoreInfoButton').down('.boxNav');
				this.setMessage(arrow.hasClassName('boxNavTop') ? this.messages.showMoreInfo : this.messages.hideMoreInfo);
			}).bind(this));
			
		$('boxMoreInfoButton').observe('mouseleave', (function(event){
				this.hideMessage();
			}).bind(this));
			
		$('boxNavArrowHold').observe('mousedown', (function(event){
		
				var element = Event.findElement(event, '.boxNav');
				
				if(element)
				{
					this.drag.setReferences();
					if(element.hasClassName('boxNavTop'))
					this.drag.setPositionAtOffset(0, -50);
						
					else if(element.hasClassName('boxNavBottom'))
						this.drag.setPositionAtOffset(0, 50);
						
					else if(element.hasClassName('boxNavRight'))
						this.drag.setPositionAtOffset(50, 0);
						
					else if(element.hasClassName('boxNavLeft'))
						this.drag.setPositionAtOffset(-50, 0);
				}
			}).bind(this));
			
		Event.observe(document.onresize ? document : window, 'resize', (function(){
			if($('boxContainer').visible())
				this.handleResize()
			}).bind(this) );
		},
		
	build:function(){
		if(!$('boxContainer'))
			$$('body')[0].insert({bottom:
				'<div id="boxContainer" style="display:none">\
						<div id="boxOverlay"></div>\
						<div id="box" class="whiteBack">\
							<div id="boxLoading" class="loading"></div>\
							<div id="boxContent">\
								<div id="boxMessageHold" class="whiteBack" style="display:none">\
									<div id="boxMessage" class="blackBack1">Message</div>\
								</div>\
								<div id="boxMainContent">\
									<div id="boxMainContentOverlay"></div>\
								</div>\
								<div id="boxNavArrowHold" style="display:none">\
										<div class="boxNav boxNavTop"></div>\
										<div class="boxNav boxNavRight"></div>\
										<div class="boxNav boxNavLeft"></div>\
										<div class="boxNav boxNavBottom"></div>\
									</div>\
								<div id="boxControls">\
									<div id="boxMoreInfoWrap">\
										<div id="boxMoreInfoButton" class="boxTab" style="float:left;display:inline;">\
											<div class="boxTabLeft"></div>\
											<div class="boxTabMiddle">More Info<div class="boxNav boxNavTop"></div></div>\
											<div class="boxTabRight"></div>\
										</div>\
										<div id="boxHideButton" class="boxTab">\
											<div class="boxTabLeft"></div>\
											<div class="boxTabMiddle"><div class="boxNav boxNavBottom"></div></div>\
											<div class="boxTabRight"></div>\
										</div>\
										<div id="boxMoreInfoContent" class="blackBack" style="display:none"></div>\
									</div>\
									<div id="boxControlsBasic" class="blackBack">\
										<div id="boxCaption">caption</div>\
										<div id="boxNav">\
											<div id="boxClose" class="close"></div>\
											<div id="boxNext" class="rightArrow"></div>\
											<div id="boxPrev" class="leftArrow"></div>\
										</div>\
										<div id="boxInfo">total</div>\
									</div>\
								</div>\
							</div>\
						</div>\
					</div>'
				})
		},
		
	begin:function(){
		this.tagArray.each((function(tag,number){
			if(tag == this.tagName){				
				this.functionArray[number]()
				}
			}).bind(this));
		},
		
	tagArray:[],
	functionArray:[],	
		
	plugin:function(tag,func){
		this.tagArray.push(tag);
		this.functionArray.push(func);
		},
		
	arrayitize:function(defaultSrc, titleAttr, optAttr, processSrc, defaults){
		if(this.array) return false;
		optAttr = optAttr || 'alt';
		this.optAttr = this.element.readAttribute(optAttr) || 'Anonymous'+new Date().getTime();
		this.optAttr = this.optAttr.sub(']','').split('[');
		this.gallery = this.optAttr[0];
		this.galleryElements = $$('body')[0].select('*['+(optAttr || 'alt')+'^='+this.gallery+']');
		if(this.galleryElements.size() == 0) this.galleryElements = [this.element];
		this.array = new Array();
		
		for(var num = 0;num < this.galleryElements.size();num++){
			 this.currentSrc = this.galleryElements[num].readAttribute(defaultSrc) != null ? this.galleryElements[num].readAttribute(defaultSrc) : this.galleryElements[num].readAttribute('href');
			 
			 this.optAttr = this.galleryElements[num].readAttribute(optAttr) != null ? this.galleryElements[num].readAttribute(optAttr).sub(this.gallery, '').sub(/^\[/, '').sub(/]$/,'') : defaults;
			 
			 var title = this.galleryElements[num].readAttribute(titleAttr) || '';
			 var opt = this.optAttr.split(',', 3);
			 
			 var type 	= opt[0];
			 var resize = opt[1];
			 
			 var info 	= opt == this.optAttr.split(',', 4) ? false : this.optAttr.sub(/\w+,/,'',3);
			 
			 var src;
			 	if(opt[2] != 'null' && opt[2] != undefined) src = opt[2];
			 	else if(processSrc) src = processSrc;
			 	else src = this.srcParser(this.currentSrc);
			 
			 var optionsArray = [title, type, resize, src, info];
			 
			 if(this.element == this.galleryElements[num]) this.number = num;
			 
			 this.array.push(optionsArray)
			}
		},
		
	handleResize:function(){
	if(typeof this.boxOutWidth == 'undefined') this.boxOutWidth=$('box').offsetHeight - parseInt( $('box').getStyle('height') );
		switch(this.resize){
		 case 'fixed':
		 	this.fixedResize();
		 	break;
		 case 'fill':
		 	this.fillResize();
		 	break;
		 default:
		 	this.aspectResize();
		 }
		},
		
	aspectResize:function(){
		//{width: [0], height: [1]}
		var boxWidth  = this.resizeMax[0];
		var boxHeight = this.resizeMax[1];
		
		var windowHeight = document.body.offsetHeight;
		var windowWidth  = document.body.offsetWidth;
		
		var boxHeightViewDif = windowHeight - boxHeight - this.boxOutWidth;
		var boxWidthViewDif  = windowWidth  - boxWidth  - this.boxOutWidth;
		
		if(boxHeightViewDif < 0 || boxWidthViewDif  < 0){
		
			boxHeightAbsoluteDif = boxHeightViewDif - boxWidthViewDif - boxWidth;
			boxWidthAbsoluteDif = boxWidthViewDif - boxHeightViewDif - boxHeight;
			
			if(boxHeightAbsoluteDif < boxWidthAbsoluteDif){
				boxHeight = windowHeight - this.boxOutWidth;
				boxWidth  = boxWidth * (boxHeight/this.resizeMax[1]);
			    }
			else{
			    boxWidth  = windowWidth - this.boxOutWidth;
			    boxHeight = boxHeight * (boxWidth/this.resizeMax[0]);
			    };
			};			
		var marginTop  = -boxHeight/2 + Math.max(document.body.scrollTop,document.documentElement.scrollTop)  - this.boxOutWidth/2;
		var marginLeft = -boxWidth/2  + document.body.scrollLeft - this.boxOutWidth/2;
		
		styleObject={
			height: 	boxHeight  + 'px',
		    width:		boxWidth   + 'px',
		    marginTop:  marginTop  + 'px',
		    marginLeft: marginLeft + 'px'
		    };
		    
		if(!this.resizeAnimate) return $('box').setStyle(styleObject);
		
		if(this.resizeEffect) this.resizeEffect.cancel();
		
		this.resizeEffect = new Effect.Morph('box', {
		    style:styleObject,
			queue: this.q.front,
		    duration:this.speed,
		    afterFinish:(function(){this.resizeAnimate = false}).bind(this)
		    });
		},
		
	fillResize:function(){
		var padding = 25;
		var boxWidth  = this.resizeMax[0];
		var boxHeight = this.resizeMax[1];
		
		var windowHeight = document.body.offsetHeight;
		var windowWidth  = document.body.offsetWidth;
		
		var boxHeightViewDif = windowHeight - boxHeight - this.boxOutWidth;
		var boxWidthViewDif  = windowWidth  - boxWidth  - this.boxOutWidth;
		
		if(boxWidth  + this.boxOutWidth >= windowWidth)   boxWidth  = windowWidth  - this.boxOutWidth - padding;
		if(boxHeight + this.boxOutWidth >= windowHeight) boxHeight = windowHeight - this.boxOutWidth - padding;
		
		//top for ie7 marginTop bug
		var marginTop  = -boxHeight/2 + Math.max(document.body.scrollTop,document.documentElement.scrollTop)  - this.boxOutWidth/2;
		var marginLeft = -boxWidth/2  + document.body.scrollLeft - this.boxOutWidth/2;
		
		styleObject={
			height: 	boxHeight  + 'px',
		    width:		boxWidth   + 'px',
		    marginTop:  marginTop  + 'px',
		    marginLeft: marginLeft + 'px'
		    };
		    
		if(!this.resizeAnimate) return $('box').setStyle(styleObject);
		
		if(this.resizeEffect) this.resizeEffect.cancel();
		
		this.resizeEffect = new Effect.Morph('box', {
		    style:styleObject,
			queue: this.q.front,
		    duration:this.speed,
		    afterFinish:(function(){this.resizeAnimate = false}).bind(this)
		    });

		},
		
	fixedResize:function(){
		
		},
		
	shiftUp:function(){
		this.number--;
		this.tagName = this.galleryElements[this.number].tagName;		this.element = this.galleryElements[this.number];
		this.begin();
		},
		
	shiftDown:function(){
		this.number++;
		this.tagName = this.galleryElements[this.number].tagName;		this.element = this.galleryElements[this.number];
		this.begin();
		},
		
	srcParser:function(source){		return source;
		var fileName = source.split('/').last();
		var fileNameBase = fileName.split('.')[0];
		
		var newSource = source.sub(fileName,fileName.sub(fileNameBase, this.folder));
		return newSource;
		},
		
	infoParser:function(info)
	{
		if(info == false || !info.isJSON())
		{
			$('boxMoreInfoButton').hide();
			$('boxMoreInfoContent').hide();
			return false;
		}
		if($('boxControlsBasic').visible()) $('boxMoreInfoButton').show();
		
		if($('boxMoreInfoContent').visible()) $('boxMoreInfoContent').show();
		 
		var metadata = info.evalJSON();
		
		var html = '';
		
		for(data in metadata)
		{
			html = html + (metadata[data].empty() ? '' : '<dt>' + data + ':&emsp;</dt>' + '<dd>' + metadata[data] + '</dd>');
		};
		
		html = '<dl>' + html + '</dl>';
		
		$('boxMoreInfoContent').update(html);
		
	},
	
	fixMoreInfoContentHieght:function()
	{
		$('boxMoreInfoContent').style.height = 'auto';
		
		var hide = $('boxMoreInfoContent').visible() ? false : true;
		var height = $('boxMoreInfoContent').show().getHeight();
		
		if(hide) $('boxMoreInfoContent').hide();
		
		$('boxMoreInfoContent').style.height = height + 'px';
	},
	
	moreInfo:function()
	{	
		this.hideMessage();
		var arrow = $('boxMoreInfoButton').down('.boxNav');
	
		this.fixMoreInfoContentHieght();
		
		Effect.toggle('boxMoreInfoContent', 'blind', 
		{
			duration: this.speed,
			beforeSetup:function(){arrow.toggleClassName('boxNavTop');arrow.toggleClassName('boxNavBottom');}
		});
	},
	
	hideBar:function()
	{
		this.hideMessage();
		var arrow = $('boxHideButton').down('.boxNav');

		var effects = [];
		
		if(arrow.hasClassName('boxNavBottom') && !this.hideControlsMessageBoolean)
		{
			this.tempMessage(this.messages.keyboardIntructs, 5);
			this.hideControlsMessageBoolean = true;
		}
		
		effects.push(Effect.toggle('boxControlsBasic', 'blind', {sync:true}))
		if(this.array[this.number][4])effects.push(Effect.toggle('boxMoreInfoButton', 'appear', {sync:true}))
		
		if($('boxMoreInfoContent').visible()) 
			effects.push(Effect.toggle('boxMoreInfoContent', 'blind', 
						{
							sync:true,
							beforeStart: (function(){this.fixMoreInfoContentHieght();}).bind(this),
							beforeSetup:function()
							{
								var arrow1 = $('boxMoreInfoButton').down('.boxNav');
								arrow1.toggleClassName('boxNavTop');
								arrow1.toggleClassName('boxNavBottom');
							}}
						));
		
		this.hideBar.Effect = new Effect.Parallel(effects,
		{
			duration: this.speed,
			afterSetup:function(){arrow.toggleClassName('boxNavTop');arrow.toggleClassName('boxNavBottom');},
			queue: this.q.end
		});
		
	},
		
	info:function(){
		var instructions = this.messages.dragNavIntructs.sub('[type]', this.type);
		
		if(this.resize == "fill")
		{
			this.tempMessage(instructions, 4);
		}
		
		$('boxInfo').update(this.number + 1 + '/' + this.array.size());
		$('boxCaption').update(this.title);
		this.nav();
		},
		
	nav:function(){
		var prev = $('boxPrev');
		var next = $('boxNext');
		var size = this.array.size();
		var hide = []; var show = [];
		if(size < 2)
			hide.push(prev,next)
		else if(this.number == 0){
			hide.push(prev);
			show.push(next);
			}
		else if(this.number+1 == size){
			hide.push(next);
			show.push(prev);
			}
		else
			show.push(prev,next);
		hide.invoke('hide');
		show.invoke('show');
		},
		
	loading:function(){
		this.hideEffect = new Effect.Parallel([
			Effect.Appear('boxLoading', {sync:true}),
			Effect.Fade('boxContent', {sync:true}),
			Effect.BlindUp('boxControls', {sync:true})
		],{
			queue: this.q.end,
			duration:this.speed
			});
		},
		
	loaded:function(){
		if(this.showEffect) this.showEffect.cancel();
		this.showEffect = Effect.Fade('boxLoading', {
			queue: this.q.end,
			duration:this.speed,
			afterSetup:this.onLoaded 	 || Prototype.emptyFunction,
			afterFinish:this.afterLoaded || Prototype.emptyFunction
			});
			
		$('boxContent').appear({to:1,from:0, queue:this.q.end, duration:this.speed, afterFinish: this.showControls.bind(this)});
		},
		
	setContent:function()
	{
		$('boxMainContentOverlay').nextSiblings().invoke('remove');
		$('boxMainContent').insert(this.contentHTML);
		if(this.contentProtected) $('boxMainContentOverlay').show();
		else $('boxMainContentOverlay').hide();
		if(this.resize == 'aspect')
		{
			$('boxMainContentOverlay').next().addClassName('boxAspectContent');
			$('boxNavArrowHold').hide();
		}
		else if(this.resize == 'fill')
		{
			this.startDrag();
			$('boxNavArrowHold').show();
		}
	},
		
	showControls:function(){
		if(this.onShowControls)this.onShowControls();
		Effect.BlindDown('boxControls', {delay:this.controlDelay, duration:this.speed, afterUpdate: (function(){this.fixMoreInfoContentHieght();}).bind(this)} );
		},
		
	open:function(){
		if(this.opened) return false;
		this.keyboardStart();
		this.opened = true;
		$('boxLoading').show();
		$('boxContent').hide();
		this.openEffect = $('boxContainer').appear({queue: this.q.end, duration:this.speed});
		},
	
	close:function(){
		this.opened = false;
		this.keyboardStop();
		this.array = false;
		this.closeEffect = $('boxContainer').fade({queue: this.q.end, duration:this.speed});
		},
		
	setMessage:function(message)
	{
		$('boxMessageHold').show();
		$('boxMessageHold').setOpacity(0);
		$('boxMessage').update(message);
		$('boxMessageHold').style.width = 'auto';
		
		var center = 
		{
			top:   ($('boxMainContent').getHeight() / 2) - $('boxMessageHold').getHeight() / 2 + 'px',
			left:  ($('boxMainContent').getWidth()  / 2) - $('boxMessageHold').getWidth()  / 2 + 'px',
			width: $('boxMessage').getWidth() + 'px'
		};
		
		$('boxMessageHold').setStyle(center);
		
		if(this.messageEffect) this.messageEffect.cancel();
		
		this.messageEffect = Effect.Appear('boxMessageHold', {duration: this.speed * 0.5,  queue:this.q.end});
	},	
	
	hideMessage:function()
	{
		if(this.messageEffect) this.messageEffect.cancel();
		
		this.messageEffect = Effect.Fade('boxMessageHold', {duration: this.speed * 0.5,  queue:this.q.end});
	},
	
	tempMessage:function(message, time)
	{
		this.setMessage(message);
		
		(function(){this.hideMessage}).bind(this).delay(time || 3)
	},
	
	keyboardStart:function()
	{
		this.keyboardActionWrap = this.keyboardAction.bindAsEventListener(this);
		document.observe('keydown', this.keyboardActionWrap);
	},
	
	keyboardStop:function(){document.stopObserving('keydown', this.keyboardActionWrap)},
		
	keyboardAction:function(event)
	{
		var code = event.keyCode;

        var escape = event.DOM_VK_ESCAPE || 27;

        var key = String.fromCharCode(code).toLowerCase();
        
        if (key.match(/x|o|c/) || (code == escape))    this.close();
         
        else if (code == 37 && $('boxPrev').visible()) this.shiftUp()
        
        else if (code == 39 && $('boxNext').visible()) this.shiftDown();

	},
		
	startDrag:function(){
		if(this.drag) this.drag.cancel();
		this.drag = new Control.DragNav('boxMainContent', $('boxMainContent').down('img'), {
			rangeX:(function(){return [0, this.image.width - $('boxMainContent').offsetWidth] }).bind(this),
			rangeY:(function(){return [0, this.image.height - $('boxMainContent').offsetHeight] }).bind(this),
			increment:2
			})
	},
	
	dragButtonNav:function(incrementX, incrementY)
	{
		this.drag.setValues(this.drag.x + (incrementX || 0), this.drag.y + (incrementY || 0));
	},
	
	q: {
 		front:{position:'front', scope:'box'},
 		end:{position:'end', scope:'box'},
 		withLast:{position:'with-last', scope:'box'}
	}

});
document.observe('dom:loaded', function(){ boxObject = new box(); })
