Script = {
	
	loadedScripts: {},
	
	defaultScriptDirectory: '/_js',
	
	require: function( src ){
		/*
		if (!Script.loadedScripts[ src ]){
			if ( src.find('/') == -1 ) { src = Script.defaultScriptDirectory + src; }
			if ( src.find('.js') == -1 ) { src = src + '.js'; }
			*/
			document.write('<script type="text/javascript" src="'+src+'"></script>');
			/*
			Script.loadedScripts[ src ] = true;
		}
		*/
	}

}

// Sets a window.loaded variable so we can test to see if the page has loaded yet.
// This is used with Event.defer
if ( window.loaded == null ){
	Event.observe( window, 'load', function(){ window.loaded = true })
} else {
	window.loaded = false;
}

debug = function(){};
$D = function(){};
$DD = function(){};

ImageMethods = {
	
	encode: function(){
		return this.src + ',' + this.width + ',' + this.height;
	}
	
}

function $I(src,width,height){
	var image = new Image(width,height);
	image.src = src;
	Object.extend( image, ImageMethods );
	return image;
}

Element.CustomMethods = {

	// finds the nearest parent where executing method(parent) on the parent equals true
	findParent: function( element, method ){
		return $(element).ancestors().find( method );
	},
	
	position: function( element, left, top ){
		$(element).setStyle({ left: left+'px', top: top+'px' })
	},
	
  positionAt: function( element, target, hPos, vPos, hPad, vPad, pagePadding ) {
		var source = $(element);
		var destination = $(target);
		
		hPos = hPos || 'left';
		vPos = vPos || 'below';
		hPad = hPad || 0;
		vPad = vPad || 0;
		pagePadding = pagePadding || 0;
		
		var offset     = Position.cumulativeOffset( destination );
		var dSize      = Element.getDimensions( destination );
		var sSize      = Element.getDimensions( source );
		var pageWidth  = Position.getPageDimensions().width;
		var top, left;
		
		switch ( hPos ) {
			case 'left'   : left = offset[0] + hPad; break;
			case 'overright' : left = offset[0] + dSize.width; break;
			case 'center' : left = offset[0] + ( dSize.width - sSize.width ) / 2; break;
			case 'right'  : left = offset[0] + dSize.width - sSize.width - hPad; break;
		}
		switch ( vPos ) {
			case 'above'  : top = offset[1] - sSize.height - vPad; break;
			case 'top'    : top = offset[1] + vPad; break;
			case 'middle' : top = offset[1] + ( dSize.height - sSize.height ) / 2; break;
			case 'bottom' : top = offset[1] + dSize.height - sSize.height - vPad; break;
			case 'below'  : top = offset[1] + dSize.height + vPad; break;
		}
		
		if ( top < pagePadding )
			top = pagePadding;
		if ( left + sSize.width > pageWidth - pagePadding )
			left = pageWidth - pagePadding - sSize.width;
		if ( left < pagePadding )
			left = pagePadding
			
		source.position( left, top )
  },
  
  setBackgroundImage: function( element, src ){
		var ext = src.split('.').pop();
		if ( ext.toLowerCase() == 'png' && Browser.ie5_5up() ) {
			element.style.filter =
				"progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + src + "');"
		} else {
			element.style.backgroundImage = 'url(' + src + ')';
		}
  },
  
  setImage: function( element, image, options ){
		if ( image && image.src ) {
	  	element = $( element );
			var options = Object.extend( { src: true, width: true, height: true }, options );
			var style = {}
			if ( options.src ) {
				if ( element.tagName == 'IMG' ) {
					element.src = image.src;
				} else {
					element.setBackgroundImage( image.src );
				}
			}
			if ( options.width ) style.width = image.width + 'px'
			if ( options.height ) style.height = image.height + 'px'
			element.setStyle( style );
		}
	},
	
	setValue: function( element, value, options ){
  	// option to allow loose matching on select boxes
  	options = Object.extend( { loose: false }, options )
		element = $( element );
		switch ( element.tagName.toLowerCase() ) {
			case "input" :
			case "textarea" :
				switch ( element.type ){
					// TODO: check the checked code
					// TODO: Consider changing this code. It is not consistent with $F()
					// from the prototype library.
					case "checkbox" : element.checked = value ? true : false; break;
					default         : element.value = value; break;
				}
				break;
			case "select" :
				// loose matching only cares about first word and doesn't check case
				if (options.loose) { value = value.split(', ')[0].toLowerCase(); }
				for (var i=0;i<element.length;i++) {
					var option = element.options[i].value;
					if (options.loose) option = option.split(', ')[0].toLowerCase();
					if (option==value) {
						element.options[i].selected = true;
						break;
					}
				}
				break;
		}
	}
  
}

Element.addMethods( Element.CustomMethods );
//Object.extend( Element.Methods, Element.CustomMethods );

/*
	initialize: function( element, event, options ){
		this.html = ''; // response html goes here
		this.element = element;
		this.event = event;
		this.options = Object.extend( {
			url: location.href.match(/([^#])+/)[0], // defaults to current page w/o hash
			parameters: {},
			onRequest: function(){}, // when request gets initiated
			onCancel: function(){} // if request is interrupted
		}, options)
		Event.observe( element, event, this.onEvent.bindAsEventListener(this) )
	},
	
	onEvent: function(e){
		Event.stop( e );
		this.ajax = new Ajax.Request( this.options.url, {
			method: 'post',
			parameters: $H( this.options.parameters ).toQueryString(),
			onComplete: this.onComplete.bind( this )
		})
	},
	
	onComplete: function( result ){
		Ajax.evalScriptsWithHTML( result.responseText );
	}
*/

// Makes a request to the server.
// Renders the resulting responseText without the scripts into a variable called "html".
// Executes the scripts in the responseText.
// Scripts have access to the "html" variable.
// Displays an indicator as it retrieves.

Ajax.showActivity = function( container ){}

Ajax.Activity = Class.create();
Ajax.Activity.prototype = {
	
	getImage: function(){
		return $I( '/s/ajax/activity.gif', 16, 16);
	},
	
	initialize: function( container ){
		if (!this.image) { this.image = $( this.getImage() ); }
		this.image.show();
		container = $(container);
		container.parentNode.insertBefore( this.image, container.nextSibling );
	},
	
	close: function(){
		this.image.hide();
	}
	
}

//
// new SimpleRequest({ parameters: { blockType: 'text' } })
Ajax.SimpleRequest = Class.create();
Ajax.SimpleRequest.prototype = {
	
	initialize: function( options ){
		this.options = Object.extend( {
			url: location.href.match(/([^#])+/)[0], // defaults to current page w/o hash
			parameters: {},
			indicatorElement: '' // where should we display the indicator element?
		}, options)
	}
	
}

// converts a framework style encoded image to a JavaScript image
String.prototype.toImage = function(code){
	var imageParts = this.split(',');
	// TODO: test below and if it works, use it
	// return ( imageParts.length >= 3 ) ? $I( imageParts[0], imageParts[1], imageParts[2] ) : null;
	if ( imageParts.length >= 3 ) {
		return $I( imageParts[0], imageParts[1], imageParts[2] )
	} else {
		return null;
	}
}

/*	Identifiers based on this link but code is all new
		http://www.webreference.com/tools/browser/javascript.html
		*/
Browser = {
	agent: function(){ return window.navigator.userAgent; },
	agentContains: function(s){ return Browser.agent().indexOf(s) != -1; },
	ie: function(){ return Browser.agentContains('MSIE') },
	gecko: function(){ return Browser.agentContains('Gecko')},
	firefox: function(){ throw 'Use Browser.gecko() instead'; },
	version: function(){
		var agent = Browser.agent();
		if(Browser.ie()){
			return parseFloat(agent.split('MSIE')[1])
		}else{
			return parseFloat(agent.split('/')[1])
		}
	},
	ie5_up: function(){ return Browser.ie() && (Browser.version() >= 5.0) },
	ie5_5up: function(){ return Browser.ie() && (Browser.version() >= 5.5) }
}


// Same as extend but throws an error if the key doesn't exist
// in the destination. Stricter checking = better code.
Object.extend( Object,{
	
	restrict: function(destination, source){
		for (property in source) {
			if ( destination[property] === undefined ){
				throw "The key "+property+" could not be found in the destination object.";
			}
		}
		return Object.extend(destination, source);
	}

})
// consider adding a "require" method to object


Object.extend( Event, {
	
	KEY_PGUP: 33,
	KEY_PGDN: 34,
	
	// DEPRECATED: Use Event.defer instead
	observeWindowLoad: function(func){
		Event.observe(window,'load',func)
	},
	
	// Event.defer is the preferred way of waiting for the window to
	// load before executing JavaScript. This supports the use of
	// deferring function execution at window.load time while still
	// allowing the function to execute if it is called as a response
	// to an AJAX call. This is because an AJAX call that executes
	// code rendered at window.load time will not execute because the
	// window.onload event has already fired and won't fire again.
	defer: function(func){
		window.loaded ? func() : Event.observe( window, 'load', func);
	},
	
	// TODO: Not sure if this is necessary. Writing it out doesn't seem to be
	// that bad and reduces the extensions code.
	observeAll: function(elements, name, observer){
		var elements = $A(elements);
		elements.each(function(element){
			Event.observe(element, name, observer)
		})
	},
	
	cancel: function(event){
		// TEST: TODO: Test then switch to the code below. 
		// event.stopPropogation ? event.stopPropogation() : event.cancelBubble = true;
		if (event.stopPropogation) {
			event.stopPropagation();
		} else {
			event.cancelBubble = true;
		}
	}
	
})

Object.extend(Element,{
	
  findElement: function(element, tagName) {
    while (element.parentNode && (!element.tagName ||
        (element.tagName.toUpperCase() != tagName.toUpperCase())))
      element = element.parentNode;
    return element;
  },
  
  styleAll: function(elements, style) {
  	var elements = $A(elements);
  	elements.each(function(element){
  		Element.setStyle(element,style);
  	})
  },
  
  // DEPRECATED: Use $(element).setValue instead
  setValue: function(element, value, options){
  	// option to allow loose matching on select boxes
  	options = Object.extend({loose: false},options)
		element = $(element);
		switch (element.tagName.toLowerCase()) {
			case "input" :
			case "textarea" :
				switch (element.type){
					case "checkbox" :
						element.checked = value ? true : false;
						break;
					default :
						element.value = value;
						break;
				}
				break;
			case "select" :
				// loose matching only cares about first word and doesn't check case
				if (options.loose) { value = value.split(', ')[0].toLowerCase(); }
				for (var i=0;i<element.length;i++) {
					var option = element.options[i].value;
					if (options.loose) {
						option = option.split(', ')[0].toLowerCase();
					}
					if (option==value) {
						//  | (parseInt(value)>0 & parseInt(option)==parseInt(value))
						element.options[i].selected = true;
						break;
					}
				}
				break;
		}
  },
  
  // DEPRECATED: Use $(element).setImage instead
	// displays the image in the element.
	// different code for IMG and other tags like DIV.
	// options to set src, width, height only
  setImage: function(element, image, options){
		var options = Object.extend({
			src: true,
			width: true,
			height: true
		},options);
		if (image) {
			// image src/background
			if (options.src) {
				var element = $(element);
				if (element.tagName == 'IMG') {
					element.src = image.src;
				} else {
					var ext = image.src.split('.').pop();
					if (ext.toLowerCase() == 'png' && Browser.ie5_5up()) {
						element.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + image.src + "');"
					} else {
						element.style.backgroundImage = 'url(' + image.src + ')';
					}
				}
			}
			// width / height
			if (options.width) { element.style.width = image.width }
			if (options.height) { element.style.height = image.height }
		}
	}
  
})

// String manipulation
Object.extend(String.prototype,{
	
	// trims whitespace. can't believe it's not part of prototype.
	trim: function() {
		return this.replace(/^\s+|\s+$/g, '');
	},
	
	// converts camel case (backgroundColor) into a normal style (background-color)
	decamelize: function(){
		var s = this;
		var regex = /[A-Z]/;
		for (var i=0; i<100; i++){
			var pos = s.search(regex);
			if(pos==-1) break;
			s = s.slice(0,pos) + '-' + s.substr(pos,1).toLowerCase() + s.slice(pos+1,s.length);
		}
		// TODO: there is a bit of ugliness here. Why does it need to be trimmed?
		// see if we can clean this up later.
		s = s.trim();
		return s;
	},
	
	capitalize: function(){
		return this.charAt(0).toUpperCase() + this.substr(1);
	}

})



Style = new Object();
Object.extend(Style,{
	
	encode: function(obj){
		var s = '';
		for (name in obj){
			s += name.decamelize() + ": " + obj[name] + "; ";
		}
		return s;
	},
	
	decode: function(style){
		var obj = new Object();
		var array = $A(style.trim().split(';'));
		array.each(function(declaration){
			if(declaration.length>0){
				var split = declaration.trim().split(':');
				var property = split[0].trim().camelize();
				var value = split[1].trim();
				obj[property] = value;
			}
		})
		return obj;
	}

})

// Positioning helpers. Extends Position in prototype.js and util.js
Object.extend(Position,{

	// DEPRECATED: Use $(element).positionAt instead
	// Preferred method to position an object in relation to another object
	place: function(source,destination,options){
		var source = $(source);
		var destination = $(destination);
		var options = Object.extend({
			verticalPosition: 'top', // above, top, middle, bottom, below
			verticalPadding: 0,
			horizontalPosition: 'left', // left, center, right
			horizontalPadding: 0,
			pagePadding: 2
		},options)
		var v = options.verticalPadding;
		var h = options.horizontalPadding;
		var offset = Position.cumulativeOffset(destination);
		var destSize = Element.getDimensions(destination);
		var sourceSize = Element.getDimensions(source);
		var top, left;
		switch (options.verticalPosition) {
			case 'above' :
				top = offset[1] - sourceSize.height - v;
				break;
			case 'top' :
				top = offset[1] + v;
				break;
			case 'middle' :
				top = offset[1] + (destSize.height - sourceSize.height)/2;
				break;
			case 'bottom' :
				top = offset[1] + destSize.height - sourceSize.height - v;
				break;
			case 'below' :
				top = offset[1] + destSize.height + v;
				break;
		}
		if (top<0) top = 0;
		switch (options.horizontalPosition) {
			case 'left' :
				left = offset[0] + h;
				break;
			case 'center' :
				left = offset[0] + (destSize.width - sourceSize.width)/2;
				break;
			case 'right' :
				left = offset[0] + destSize.width - sourceSize.width - v;
				break;
		}
		
		var pageWidth = Position.getPageDimensions().width;
		
		if ( left + sourceSize.width > pageWidth-options.pagePadding ) {
			left = pageWidth - options.pagePadding - sourceSize.width;
		}

		Element.setStyle(source,{
			top: top,
			left: left
		})
	},
			
	// deprecated
	getPageWidth: function(){
		return document.body.clientWidth;
	},
	
	// deprecated
	getPageHeight:  function(){
		return document.body.clientHeight;
	},
	
	getPageDimensions: function(){
		return {
			width: document.body.clientWidth,
			height: document.body.clientHeight
		}
	},
	
	getRect: function(element){
		var pos = Position.positionedOffset(element);
		var width = element.offsetWidth;
		var height = element.offsetHeight;
		return {
			left: pos[0],
			top: pos[1],
			width: width,
			height: height,
			right: pos[0]+width,
			bottom: pos[1]+height
		};
	},
	
	// helper for positionedRect and cumulativeRect
	_rect: function(element,left,top){
		var width = element.offsetWidth;
		var height = element.offsetHeight;
		return {
			left: left,
			top: top,
			width: width,
			height: height,
			right: left+width,
			bottom: top+height
		}
	},
	
	positionedRect: function(element){
		var pos = Position.positionedOffset(element);
		return Position._rect(element,pos[0],pos[1]);
	},
	
	cumulativeRect: function(element){
		var pos = Position.cumulativeOffset(element);
		return Position._rect(element,pos[0],pos[1]);
	},
	
	
	// DEPRECATED:
	// deprecated I think. Can't think of where I'd use this now
	// that the Panel2 has been created.
	positionAround: function(button,element,padding){
		// sets default padding to 2 pixels
		var padding = padding?padding:2;
		var buttonRect = Position.getRect(button);
		var elementRect = Position.getRect(element);
		var pageWidth = Position.getPageWidth();
		var left = 0;
		if(buttonRect.left+elementRect.width <= pageWidth-padding){
			left = buttonRect.left;
		}else{
			left = pageWidth-elementRect.width-padding;
			if(left<padding){left = padding}
		}
		element.style.left = left;
		element.style.top = buttonRect.bottom+padding;
	},
	
	// DEPRECATED: Use Position.place instead.
	// A version of position around that doesn't care about position: relative.
	// Important for positioning elements that are added to document.body
	// instead of inside of a position: relative div
	positionAround2: function(button,element,padding){
		var padding = padding ? padding: 2;
		var pageWidth = Position.getPageWidth();
		var buttonSize = Element.getDimensions(button);
		var buttonPos = Position.cumulativeOffset(button);
		var elementSize = Element.getDimensions(element);
		var left = buttonPos[0];
		var topPos = buttonPos[1] + buttonSize.height + padding;
		
		if ((elementSize.width + left) > pageWidth){
			left = pageWidth - elementSize.width - padding;
		}
		Element.setStyle(element,{
			left: left,
			top: topPos
		})
	},
	
	// DEPRECATED: Use Position.place instead
	positionCentered: function(element){
		var rect = Position.getRect(element);
		var left = (Position.getPageWidth() - rect.width) / 2;
		var top = (Position.getPageHeight() - rect.height) / 2;
		Element.setStyle(element,{
			left: parseInt(left) + 'px',
			top: parseInt(top) + 'px'
		})
	},
	
	getScrollTop: function(){
		Position.prepare();
		return this.deltaY;
	}
	
})
