/* ----------------------------------------------------------
    simulates the .net string builder class. preferred way
    of constructing large strings instead of using concats.
    Always null out the obj after you're done with it.
    
    ex. var html = new StringBuilder();
        var test = html.append("<br />").toString();
        html = null; // prevents memory leaks in IE
---------------------------------------------------------- */
function StringBuilder() {
    this.strings = new Array();
    
    this.toString = function(){
        return this.strings.join('');
    };
    
    this.append = function(string){
        this.strings.push(string);
        return this;
    };
    
    this.length = function(){
        return this.strings.length;
    };
}

function strIsEmpty(str) {
    return typeof(str) != "string" || str.length == 0;
}

/* ----------------------------------------------------------
    trys to parse a string to int. returns 0 if operation failed.
    returns 0 if failed.
---------------------------------------------------------- */
function tryParseInt(string) {
	var numRegex = /^[\d]+$/i;
	return numRegex.test(string) ? parseInt(string) : -1;
}

/* ----------------------------------------------------------
	Begin jquery plugins, map to "base" namespace and
	wrap in closure. Within the closure we can safely map to
	the "$" token.
---------------------------------------------------------- */
(function($){
	
	// create base namespace
	$.base = $.base || {};

	/* = BEGIN LAYER -------------------------------------- */
	// css class used to denote a layer object
	$.base.layerClass = "ui-layer";

	/* -----------------------------------------------------
		Main layer plugin, searches out elements with the
		css class "layer" and gets their settings from
		custom attributes set on the element itself.
		
		ex. <div id="priv_notice" modal="true" drag="true"
				close="true">...content</div>
		
		ex. $("div.layer").layer();
	----------------------------------------------------- */
	$.fn.layer = function(params) {
		return this.each(function() {
			var element = $(this);
			
			// make sure we're dealing with a layer div and that it already hasn't been
			// turned into a new layer object
			if (!element.is("." + $.base.layerClass) && element.is(".layer"))
			{
				new $.base.layer(this, params);
			}
		});
	};
	
	$.fn.layerOpen = function() {
		return this.each(function() {
			if ($(this).is("." + $.base.layerClass)){
				$.base.layerOpen(this);
			}
		});
	};
	
	$.fn.layerClose = function() {
		return this.each(function() {
			if ($(this).is("." + $.base.layerClass)){
				$.base.layerClose(this);
			}
		});
	};

	/* -----------------------------------------------------
		layer helper function that manages visibilty and
		page settings.
		
		@zindex: z-index of the layer. default 4000
		@handle: drag handle, pass string or jquery obj
		@modal: true/false, to display page shield
		@drag: true/false, enable draggin on layer,
			must set handle.
		@center: auto center the layer, otherwise will default
			to layer's current position.
		@container: contain dragging to a specific element,
			can pass jquery obj. default is document
		@overlayID: id for the overlay/page shield used by
			layer.
		@shieldID: id for the IE selects shield used by
			the layer.
	----------------------------------------------------- */
	$.base.layer = function(el, params) {
		
		var options = $.extend({
			zindex: 501,
			handle: undefined,
			modal: false,
			drag: false,
			center: false,
			container: "document",
			overlayID: undefined,
			shieldID: undefined
		}, params);
		
		this.element = el;
		
		// do bindings
		$.data(this.element, $.base.layerClass, this);

		// add class to denote this element is now a layer object
		// make sure layer has default css styles
		var uiLayer = $(el).addClass($.base.layerClass)
			.css({position: "absolute", zIndex: options.zindex});
		
		var defaultBtn = uiLayer.attr("defaultbutton");
		
		// setup drag
		if (options.drag == true && options.handle){
			uiLayer.draggable({ opacity: .70,
					   cursor: "move",
					   handle: options.handle,
					   containment: options.container,
					   start: function(){
						// we need to temporarily hide shield for ie on drag
						showShield(false, uiLayer, options);
					   },
					   stop: function(){
						// re-enable shield for ie
						showShield(true, uiLayer, options);
					   }
			});
		}
        
		function prepBody(show, layer, options){
			if (options.modal){
				// get rid of scroll bars if its modal
				$("body, html").css({height: "100%", overflow: show ? "hidden" : ""});
				
				// hide selects for poor ie
				if ($.browser.msie)
				{
					var selects = uiLayer.find("select");
					$("select").not(selects).css("visibility", show ? "hidden" : "visible"); 
				}
			
				layer.overlay(show, {id: options.overlayID});
			}
			else{
				showShield(show, layer, options);
			}
		};
		
		function showShield(show, layer, options){
			if (!options.modal && $.browser.msie) {
				layer.shield(show, {id: options.shieldID});
			}
		};
		
		this.open = function(){
		    
			// if the layer has a default button then lets go ahead
			// and set it up
			if (defaultBtn){
			    $("#" + defaultBtn).focus();
			    $(document).defaultButton(defaultBtn);
			}
			
			/* NOTE: must follow this sequence!!!
			  - when you center a layer, css position settings
			    won't take effect till the layer/dom object
			    is visible, "display: block;". so it is important
			    to follow this sequence.
				1. center layer
				2. show layer
				3. prepare body
			*/
			if (options.center){
			    uiLayer.centerElm();
			}
			
			// show the layer so that these values take effect on the DOM
			uiLayer.show();
			
			// this must come after the layer is visible, overlay and shield
			// needs the element to be visible first to properly get dimensions
			// and position of object
			prepBody(true, uiLayer, options);
		};
	
		this.close = function() {
			prepBody(false, uiLayer, options);
			uiLayer.hide();
		};
	};

	$.base.layerOpen = function(el) {
		$.data(el, $.base.layerClass).open();
	};

	$.base.layerClose = function(el) {
		$.data(el, $.base.layerClass).close();
	};
	/* = END LAYER -------------------------------------------- */
	
	/* ----------------------------------------------------------
		creates a hovering tooltip.
		ex. $("a.tooltip").help();
	---------------------------------------------------------- */
	$.fn.help = function(){
		
		isIE = $.browser.msie && $.browser.version == '6.0';
		
		function getHelpCont(){
                        var contID = 'helpCont';
			var cont = $('#' + contID);
			if (cont.length == 0){
			    cont = $('<div id="' + contID + '"></div>').appendTo('body');
			}
	
			return cont;
		};
	    
		return this.hover(function(){
			
			var helpLink = $(this);
			
			// get the help div and set the text
			var text = helpLink.attr('helptext');
			var cont = getHelpCont().html(text);
	
			// get link position
			var position = helpLink.position();
	
			// get dimensions
			var contWidth = cont.width(), width = helpLink.width(), viewPort = $(window).width();
			
			// get position
			var left = width + position.left + 6, top = 0;
	
			// make sure help cont doesn't go past viewport
			left = (left + contWidth) > viewPort ? position.left - (contWidth + 10) : left;
			top = position.top < 0 ? 0 : position.top;
			
			// set pos and show help div
			cont.css({top: top, left: left}).show();
	
			// if its ie then we need to show the iframe shield
			if (isIE){
			    cont.shield(true);
			}
		
		}, function(){
			var cont = getHelpCont().hide();
			
			if (isIE){
			    cont.shield(false);
			}
		})
		.bind('click', function(){
		    return false;
		}).bind('unload', $.base.unBindElm);
	};
	
	/* ----------------------------------------------------------
		Centers an element on the page.
		
		ex. $("#layer").centerElm();
	---------------------------------------------------------- */
	$.fn.centerElm = function() {
	
		return this.each(function(){
			
			var element = $(this);
			var wnd = $(window), left = 0, top = 0;
			
			// get position
			top = (wnd.height() / 2) - (element.height() / 2);
			left = (wnd.width() / 2) - (element.width() / 2);
			
			// make sure we don't go past viewport
			left = left < 0 ? 0 : left;
			top = top < 0 ? 0 : top;
			
			element.css({position: "absolute", left: left, top: top});	
		});
	};
	
	/* -----------------------------------------------------
		Plugin that allows you to create a page shield or overlay
		that can be contained to the element's dimension or for the
		entire page. Please refer to base.css for css styles.
		
		@show: true/false to make the overlay visible
		@params: pass a array to set various options:
			- id: the id for the overlay be set or one can
				be generated from the elements id.
			- zindex: set the zindex for the overlay
			- contain: true/false, true to contain the dimensions
				to the element's. false to cover the whole page.
		
		// will display overlay and cover entire page
		ex. $("#layer").overlay(true, {id: "myoverlay"});
		
		// will create an overlay to the exact dimension of the
		// layer.
		// * must set a z-index otherwise it will display
		// overlay behind the layer by default.
		ex. $("#layer").overlay(true, {id: "myoverlay", contain: true});
	----------------------------------------------------- */
	$.fn.overlay = function(show, params){
		var options = $.extend({
			id: undefined,
			zindex: undefined,
			contain: false // set true if want to contain to element
		    }, params);
		
		return this.each(function(){
			
			var element = $(this);
			
			// assign id to overlay if one hasn't been provided
			var overlayID =  options.id || (!strIsEmpty(element[0].id) ? 'ol-' + element[0].id : '_overlay');
			
			// set default zindex
			var zindex = options.zindex || element.css('z-index');
			
			// create the overlay if it doesn't exist
			var overlay = $('#' + overlayID);
			if (overlay.length == 0){
				overlay = $('<div class="overlay" id="' + overlayID + '" />').css('z-index', zindex - 1).appendTo('body'); 
			}
		     
			// only set the dimension of overlay if you want to contain it to element
			var top = '', left = '', width = '', height = '';
			if (options.contain) {
				width = element.innerWidth();
				height = element.height();
				
				var position = element.position();
				top = position.top;
				left = position.left;
			}
			
			// set position and display settings
			overlay.css({position: 'absolute', width: width, height: height, top: top, left: left, display: show ? 'block' : 'none'});
		});
	};
	
	/* ----------------------------------------------------- 
		Plugin that creates an iframe shield for an element and matches its dimensions. 
		Should only be used for IE 5/6.
		
		@show: true/false to make the shield visible
		@params: pass a array to set various options:
			- id: the id for the shield be set or one can
				be generated from the elements id.
			- zindex: set the zindex for the shield
       ----------------------------------------------------- */
       $.fn.shield = function(show, params){
       
		var options = $.extend({
			id: undefined,
			zindex: 99
		}, params);
		
		return this.each(function(){		
			// create id
			var element = $(this);
		
			// assign id to overlay if one hasn't been provided
			var shieldID = options.id || (!strIsEmpty(element[0].id) ? 'shl-' + element[0].id : '_shield');
	
			// set default zindex
			var zindex = options.zindex || element.css('z-index');
	
			// get the shield
			var shl = $('#' + shieldID);
			if (shl.length == 0){
				// create it and append to body
				shl = $('<iframe style="display: none;" src="javascript:false;" id="' + shieldID + '" />')
					.css('z-index', zindex - 1).appendTo('body');
			}
		
			var top = '', left = '', width = '', height = '';
			if (show){
				width = element.width();
				height = element.height();
				
				var position = element.position();
				top = position.top;
				left = position.left;
			}
			
			// set position and display settings
			shl.css({position: 'absolute', width: width, height: height, top: top, left: left, display: show ? 'block' : 'none'});
		});
       };
       
	/* -----------------------------------------------------
		plugin used for ie 5/6 to handle css hover styling
		// ie 5/6 can't handle pseudo selectors like :hover
		// on elements, except for anchors <a>
		ex. $("table tr").hoverCss("blue-highlight");
	----------------------------------------------------- */
	$.fn.hoverCss = function(css){
		return this.each(function(){
			$(this)
			.unbind('mouseover', $.base.toggleCss)
			.unbind('mouseout', $.base.toggleCss)
			.bind('mouseover', {elm: this, cssClass: css}, $.base.toggleCss)
			.bind('mouseout', {elm: this, cssClass: css}, $.base.toggleCss)
			.bind('unload', $.base.unBindElm);
		
		});
	};
	
	/* -----------------------------------------------------
		plugin for ie 5/6 to handle css focus styling
		ex. $("input").focusCss("input-green");
	----------------------------------------------------- */
	$.fn.focusCss = function(css){
		return this.each(function(){
			$(this)
			.unbind('focus', $.base.toggleCss)
			.unbind('blur', $.base.toggleCss)
			.bind('focus', {elm: this, cssClass: css}, $.base.toggleCss)
			.bind('blur', {elm: this, cssClass: css}, $.base.toggleCss)
			.bind('unload', $.base.unBindElm);
		});
	};
	
	/* ----------------------------------------------------------
		On hover/focus toggle css styling for ie. refer to:
		$().focusCss()
		$().hoverCss()
	---------------------------------------------------------- */
	$.base.toggleCss = function (e){
		var elm = e.data.elm;
		var css = e.data.cssClass;
		
		if (elm && !strIsEmpty(css)){
		    $(elm).toggleClass(css);
		}
	};
        
        /* -----------------------------------------------------
		Plugin that allows you to convert a string bool value
		to a true javascript bool object. All attributes are
		strings until converted to right data type. Returns
		false if attribute is undefined.
		
		@attrName: name of the attribute on the dom to
			convert to boolean.
		
		// some attribute on element, can be custom
		ex. <div id="test" enabledrag="true" />
		
		// pass the name of the attribute to convert
		ex. var enable = $("#test").getBoolAttr("enabledrag");
	----------------------------------------------------- */
	$.fn.getBoolAttr = function(attrName){
	    var attr = this.attr(attrName);
	    return !strIsEmpty(attr) && attr.toLowerCase() == "true"; 
	};
        
        /* ----------------------------------------------------------
		Helper function to be used in jquery event bindings. Call
		this function on window unload to clear all wired events
		for that element. 
		ex. $(elm).bind("unload", $.base.unBindElm);
		*No need to pass any params/args. jquery automatically
		passes the event obj.
	---------------------------------------------------------- */
	$.base.unBindElm = function (e){
		if (e && e.target){
		    $(e.target).unbind();
		}
	};
	
	/* ----------------------------------------------------------
		Util method that gets the base URL
	---------------------------------------------------------- */
	$.getUrl = function() {
	    var location = window.location;
	    return  location.protocol + '//' + location.hostname + (strIsEmpty(location.port) ? '' : ':' + location.port);
	};
	
})(jQuery);
