﻿// ========================================================================
// Author: 	Kevin Cherry	
// Date: 	June 05, 2007
// Purpose: To provide objects that extend functionality of pre-existing
// 			javascript objects.
// Usage: 	These objects are used in the same manner as the built-in
//			javascript objects except that the prefix "x" standing for
//			"Extended" is used. 
//			Example of usage: 
//				xMath.square(3) will return 9
//				xDocument.setCookie('username','Kevin') will set a JS cookie
//					with 'username' as key and 'Kevin' as value
// Note:	All functions inside closures have been manipulated to behave
//			like methods of a class as mentioned above. This means that
//			simply referencing a function without the object and dot 
//			operator will not work.
//			There are plenty of documentation before each closure
//			specifying how methods are to be used, however, when in doubt,
//			just call the method to see what it does. If any methods are
//			missing that you would like added, you can either try your hand 
//			at writing them yourself, or contact me and I will see what kind
//			of JS magic I can work.
// LICENSE:	You may use this code for any purpose, commercial or private, 
//			without any permission from the author. You may not remove this
//			LICENSE nor the Author, Date, Purpose, Usage, or Note from your 
//			final code. Please DO NOT link directly to this .js file from 
//			your site. Copy the file to your server and use it there. 
//			Thank you. (Note: Some wording	in this notice came from 
//			http://www.mattkruse.com/javascript/date/source.html
//			I just like his style with words :))
// ========================================================================

/* CLOSURE: xGlobal
 * PURPOSE: Holds all global functions used by other closures
 *
 *
 * FUNCTION: getObjFromStr
 * PURPOSE:	 if obj is not an object in the document, it is treated as an
 *			 id and an attempt is made to find an object with that id. If
 *			 that fails, an attempt is made to find an object with that name.
 *			 If that fails, it returns null.
 */
function XGlobal() {
	this.getObjFromStr = function(obj) {
		if (typeof(obj) != 'object') {
			str = obj
			obj = document.getElementById(str)
			if (obj == null) {
				nobjs = document.getElementsByName(str)
				if (nobjs.length == 0)
					return null
				else
					obj = nobjs[0]
			}
		}
		return obj
	}
	this.sortNum = function(a, b) {
		return a-b
	}
}var xGlobal = new XGlobal();


/* 
 * CLOSURE: XDate
 *
 *
 * FUNCTION: getShortYear
 * PURPOSE:  if no arguments given: returns last 2 digits of current year
 *			 if a date is given: returns last 2 digits of that date's year
 *			 else: returns null
 *			 note: only first argument is used. All others are ignored
 *
 * FUNCTION: getStrDay
 * PURPOSE:  if no arguments given: returns current day of week as a abbreviated name string
 *			 if a date is given: returns that date's day of week as a abbreviated name string
 *			 else: returns null
 *			 note: only first argument is used. All others are ignored
 *
 * FUNCTION: getFullStrDay
 * PURPOSE:  if no arguments given: returns current day of week as a full name string
 *			 if a date is given: returns that date's day of week as a full name string
 *			 else: returns null
 *			 note: only first argument is used. All others are ignored
 *
 * FUNCTION: getStrMonth
 * PURPOSE:  if no arguments given: returns current month as a abbreviated name string
 *			 if a date is given: returns that date's month as a abbreviated name string
 *			 else: returns null
 *			 note: only first argument is used. All others are ignored
 *
 * FUNCTION: getFullStrMonth
 * PURPOSE:  if no arguments given: returns current month as a full name string
 *			 if a date is given: returns that date's month as a full name string
 *			 else: returns null
 *			 note: only first argument is used. All others are ignored
 */
function XDate() {
	this.getShortYear = function () {
		if (!arguments.length) {
			var d = new Date()
			return (d.getFullYear().toString().substring(2,4))
		}
		else {
			if (arguments[0].constructor == Date)
				return (arguments[0].getFullYear().toString().substring(2,4))
		}
		return null
	}
	this.getStrDay = function () {
		var weekday=new Array('Sun','Mon','Tues','Wed','Thurs','Fri','Sat')
	
		if (!arguments.length) {
			var d = new Date()
			return weekday[d.getDay()]
		}
		else {
			if (arguments[0].constructor == Date)
				return weekday[arguments[0].getDay()]
		}
		return null
	}
	this.getFullStrDay = function () {
		var weekday=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')
	
		if (!arguments.length) {
			var d = new Date()
			return weekday[d.getDay()]
		}
		else {
			if (arguments[0].constructor == Date)
				return weekday[arguments[0].getDay()]
		}
		return null
	}
	this.getStrMonth = function () {
		var month=new Array('Jan','Feb','Mar','Apr','May','June','July','Aug','Sept','Oct','Nov','Dec')
	
		if (!arguments.length) {
			var d = new Date()
			return month[d.getMonth()]
		}
		else {
			if (arguments[0].constructor == Date)
				return month[arguments[0].getMonth()]
		}
		return null
	}
	this.getFullStrMonth = function () {
		var month=new Array('January','Febuary','March','April','May','June','July','August','September','October','November','December')
	
		if (!arguments.length) {
			var d = new Date()
			return month[d.getMonth()]
		}
		else {
			if (arguments[0].constructor == Date)
				return month[arguments[0].getMonth()]
		}
		return null
	}
}var xDate = new XDate();


/*
 * CLOSURE: XMath
 *
 *
 * FUNCTION: roundTo
 * PURPOSE:  rounds number to nearest value at given position. Position must be
 *				 given as a number with a 1 in the place to round to.
 *				 Ex: roundTo(857,100) will round 857 to nearest hundred (result=900)
 *				 roundTo(6.235, 0.01) will round 6.235 to nearest hundredth (result=6.24)
 *
 * FUNCTION: square
 * PURPOSE:  squares given number
 *
 * FUNCTION: cube
 * PURPOSE:  cubes given number
 *
 * FUNCTION: cbrt
 * PURPOSE:  returns the cube root of the given number
 *
 * FUNCTION: xrt
 * PURPOSE:  returns the xth root of the given number
 *
 * FUNCTION: sasLawOfSin
 * PURPOSE:  "side-angle-side" law of sines. Given 2 sides and 1 angle,
 *			 returns other angle. Returned angle is opposite last given side.
 *
 * FUNCTION: asaLawOfSin
 * PURPOSE:  "angle-side-angle" law of sines. Given 1 side and 2 angles,
 *			 returns other side. Returned side is opposite first given angle.
 *
 * FUNCTION: lawOfCos
 * PURPOSE:  uses law of cosines to return other side from given 2 sides
 *			 and an angle. Returned side is opposite given angle.
 *
 * FUNCTION: hypyth
 * PURPOSE:  returns hypothenuse of triangle using pythagoras theroem with 
 *			 given two sides
 *
 * FUNCTION: sdpyth
 * PURPOSE:  returns other side of triangle using pythagoras theroem with
 *			 given side and hypothenuse
 *
 * FUNCTION: rand
 * PURPOSE:  generates a random number between given min and max
 */
function XMath() {
	this.roundTo = function (num, pos) {
  		return Math.round(num/pos)*pos
	}
	this.square = function (num) { 
		return Math.pow(num,2) 
	}
	this.cube = function (num) { 
		return Math.pow(num,3) 
	}
	this.cbrt = function (num) {
		return Math.pow(num, 1/3)
	}
	this.xrt = function (num, root) {
		return Math.pow(num, 1/root)
	}
	this.dist = function (x1, y1, x2, y2) { 
		return Math.sqrt(this.square(x1-x2)+this.square(y1-y2)) 
	}
	this.sasLawOfSin = function (a, A, b) {
		return Math.asin((b*Math.sin(A))/a)
	}
	this.asaLawOfSin = function (A, b, B) {
		return (b*Math.sin(A))/Math.sin(B)
	}
	this.lawOfCos = function (a, b, C) {
		return Math.sqrt(this.square(a)+this.square(b)-(2*a*b*Math.cos(C)))
	}
	this.hypyth = function (a, b) {
		return Math.sqrt(this.square(a) + this.square(b))
	}
	this.sdpyth = function (a, c) {
		return Math.sqrt(this.square(c) - this.square(b))
	}
	this.rand = function (min, max) {
		return Math.floor(min+(Math.random()*(max-min+1)))
	}
	this.sum = function (list) {
		tsum = 0
		for (i in list)
			tsum += list[i]
		return tsum
	}
	this.avg = function(list) {
		return this.sum(list)/list.length
	}
	this.median = function(list) {
		return list.sort(xGlobal.sortNum)[Math.floor(list.length/2)]
	}
	this.mode = function(list) {
	}
	
	this.matadd = function() {
		
	}
	this.matmul = function() {
		
	}
}var xMath = new XMath();


function XArray() {
	this.add = function() {
		valid = true
		if (!arguments)
			return null
		else
			len = arguments[0].length
			
		for (i in arguments) {
			if (arguments[i].constructor != Array || arguments[i].length != len) {
				valid=false
				break
			}
		}
		vecsum = new Array()
		for(i = 0; i < len; i++) {
			vecsum[i] = 0
		}
		for(i in arguments) {
			for(j=0; j<len; j++) {
				vecsum[j] += arguments[i][j]
			}
		}
		return vecsum
	}
	this.mul = function() {
		valid = true
		if (!arguments)
			return null
		else
			len = arguments[0].length
			
		for (i in arguments) {
			if (arguments[i].constructor != Array || arguments[i].length != len) {
				valid=false
				break
			}
		}
		vecsum = new Array()
		for(i = 0; i < len; i++) {
			vecsum[i] = 0
		}
		for(i in arguments) {
			for(j=0; j<len; j++) {
				vecsum[j] *= arguments[i][j]
			}
		}
		return vecsum
	}
	this.fill = function(vector, value) {
		for (i in vector)
			vector[i] = value
	}
}var xArray = new XArray();

/*
 * CLOSURE: XString
 *
 *
 * FUNCTION: toCapitalCase
 * PURPOSE:  converts given string into initial caps
 *
 * FUNCTION: trimBack
 * PURPOSE:  removes trailing whitespace
 *
 * FUNCTION: trimFront
 * PURPOSE:  removes leading whitespace
 *
 * FUNCTION: trim
 * PURPOSE:  removes both leading and trailing whitespace
 */
function XString() {
	this.toCapitalCase = function (str) {
		if (!str) return null
		str = str.substring(0,1).toUpperCase() + str.substring(1,str.length)
		
		for(i = 0; i < str.length; i++) {
			if (str.substring(i,i+1) == ' ')
				str = str.substring(0,i+1) + str.substring(i+1,i+2).toUpperCase() + str.substring(i+2,str.length)
		}
		return str
	}
	this.trimBack = function(str) {
		tlen = str.length
		for (i = tlen; i > 0; i--) {
			len = str.length
			strback = str.substring(len-1, len)
			if (strback == ' ' || strback == '\t')
				str = str.substring(0,len-1)
			else
				break
		}
		return str
	}
	this.trimFront = function(str) {
		tlen = str.length
		for (i = 0; i < tlen; i++) {
			strfront = str.substring(0, 1)
			if (strfront == ' ' || strfront == '\t')
				str = str.substring(1,str.length)
			else
				break
		}
		return str
	}
	this.trim = function(str) {
		return this.trimBack(this.trimFront(str))
	}
}var xString = new XString();


/*
 * CLOSURE: XDocument
 *
 *
 * PROPERTY: activeElement
 * PURPOSE:  contains the element that currently has the focus. activeElementSetUp must be
 *			 called prior to using this value.
 *			 Note: function used for browsers other than Internet Explorer to simulate 
 *				   Internet Explorer's recognition of the document.activeElement property
 *
 * FUNCTION: activeElementSetUp
 * PURPOSE:  must be called before property activeElement can be referenced. Best if 
 *			 called using onload event of body element. 
 *			 Note: function used for browsers other than Internet Explorer to simulate 
 *				   Internet Explorer's recognition of the document.activeElement property.
 *				   Also, this function will not overwrite any onfocus or onblur events
 *				   already on any of the form elements. It will simply append to it.
 *
 * FUNCTION: setActiveElement
 * PURPOSE:  sets the property, activeElement, to the element that currently has the focus 
 *
 * FUNCTION: getSelOptText
 * PURPOSE:	 gets the text from the selected option in a list box
 *
 * FUNCTION: checkExistsInputType
 * PURPOSE:  checks if an input element with the given type exists in the document
 *
 * FUNCTION: checkCountInputType
 * PURPOSE:  returns count of all input elements with the given type existing in the document
 *
 * FUNCTION: checkExists
 * PURPOSE:  checks if a given tag element exists in the document
 *
 * FUNCTION: checkCount
 * PURPOSE:  returns count of all given tag elements that exists in the document
 *
 * FUNCTION: setFieldToCookie
 * PURPOSE:  sets the value of a text field to the cookie value cooresponding to the given key
 *
 * FUNCTION: setCookie
 * PURPOSE:  sets a cookie with the given key and value
 *
 * FUNCTION: rmCookie
 * PURPOSE:	 removes cookie with the given key by setting its value to undefined and its 
 *			 expiration to yesterday
 *
 * FUNCTION: getCookie
 * PURPOSE:  gets the cookie value of the given key
 */
function XDocument() {
	this.activeElement=null
	this.activeElementSetUp = function() {
	    for (i=0; i< document.forms[0].elements.length-1; i++) {
	        elem = document.forms[0].elements[i]

			elem.elemonfocus = 'xDocument.setActiveElement(this);'
			elem.elemonblur  = 'xDocument.setActiveElement(null);'

			if (elem.onfocus)	elem.elemonfocus += elem.onfocus.toString().split('{')[1].substring(0,elem.onfocus.toString().split('{')[1].length-1)
			if (elem.onblur)	elem.elemonblur += elem.onblur.toString().split('{')[1].substring(0,elem.onblur.toString().split('{')[1].length-1)				
				
			elem.onfocus = function() { eval(this.elemonfocus) }
        	elem.onblur  = function() { eval(this.elemonblur) }
	   	}
	}
	this.setActiveElement = function(obj) {
		this.activeElement = obj
	}
	this.getSelOptText = function(obj) {
		sel = xGlobal.getObjFromStr(obj)
		if (sel != null)
			return sel.options[sel.selectedIndex].text
		else
			return null
	}
	this.checkExistsInputType = function (type) {
		len = document.getElementsByTagName('input').length;
		for (i = 0; i < len; i++ )
			if (document.getElementsByTagName('input')[i].type == type)
				return true
		return false
	}
	this.checkCountInputType = function (type) {
		len = document.getElementsByTagName('input').length;
		count = 0
		for (i = 0; i < len; i++ )
			if (document.getElementsByTagName('input')[i].type == type)
				count++
		return count
	}
	this.checkExists = function (tag) {
		return document.getElementsByTagName(tag).length? true:false
	}
	this.checkCount = function (tag) {
		return document.getElementsByTagName(tag).length
	}
	this.setFieldToCookie = function (objraw, key) {
		obj = xGlobal.getObjFromStr(objraw)
		if (obj != null) {
			if (document.cookie.length>0) {
				allcookies = document.cookie.split(';') 
				for(i = 0; i <  allcookies.length; i++) {
					pieces = allcookies[i].split('=')
					if (xString.trimFront(pieces[0]) == key) {
						obj.value = pieces[1]
						break
					}
				}
			}
		}
	}
	this.setCookie = function (key, value){
		document.cookie = key + '=' + value;
	}
	this.rmCookie = function (key){
		document.cookie = key + '=' + 'undefined; expires=' + (Date()-1)
	}
	this.getCookie = function (key) {
		value = null;
		if (document.cookie.length>0) {
			allcookies = document.cookie.split(';') 
			for(i = 0; i <  allcookies.length; i++) {
				pieces = allcookies[i].split('=')
				if (pieces[0] == key) {
					value = pieces[1]
					break
				}
			}
		}
		return value
	}
	this.scrollText = function (obj, container, top, left, width, height, text) {
		var right	= left+width
		var bottom	= top+height
		var y = 140
		var t
		(function() {
			obj.style.position = 'absolute';
			obj.style.clip = 'rect(' + top + 'px,' + right + 'px,' + bottom + 'px,' + left + 'px)';
			t = window.setTimeout('scroll()',75)
			obj.onmousemove= 		function () { xDocument.stopScroll(container) }
			obj.onmouseout=			function () { xDocument.startScroll(container)}
			container.onmousemove=	function () { xDocument.stopScroll(container) }
			container.onmouseout=	function () { xDocument.startScroll(container)}
		})()
		function scroll() {
			if (y < -200) {
				y = 140
				top = -100
				bottom = 0
			}
			y--
			top++
			bottom++
			obj.style.clip = 'rect(' + top + 'px,' + right + 'px,' + bottom + 'px,' + left + 'px)';
			obj.style.top = y
			t = window.setTimeout('scroll()',40)
		}
		function stopScroll(container) {
			container.style.border = '2px groove red'
			//document.getElementById('pausemsg').innerHTML = 'news paused'
			window.clearTimeout(t)
		}
		function startScroll(container) {
			container.style.border = ''
			//document.getElementById('pausemsg').innerHTML = ''
			t = window.setTimeout('foo()',40)
		}
	}
}var xDocument = new XDocument();











