// $Id: main.js 12949 2008-06-30 08:23:11Z kbailey $
// +----------------------------------------------------------------------+
// | ModernBill [TM] .:. Client Billing System                            |
// +----------------------------------------------------------------------+
// | Copyright (c) 2001-2002 ModernGigabyte, LLC                          |
// +----------------------------------------------------------------------+
// | This source file is subject to the ModernBill End User License       |
// | Agreement (EULA), that is bundled with this package in the file      |
// | LICENSE, and is available at through the world-wide-web at           |
// | http://www.modernbill.com/extranet/LICENSE.txt                       |
// | If you did not receive a copy of the ModernBill license and are      |
// | unable to obtain it through the world-wide-web, please send a note   |
// | to license@modernbill.com so we can email you a copy immediately.    |
// +----------------------------------------------------------------------+
// | Authors: ModernGigabyte, LLC <info@moderngigabyte.com>               |
// | Support: http://www.modernsupport.com/modernbill/                    |
// +----------------------------------------------------------------------+
// | ModernGigabyte and ModernBill are trademarks of ModernGigabyte, LLC. |
// +----------------------------------------------------------------------+


var XKsliderTargets = new Array();
var XKsliders = new Array();
var XKselectedSlider = false;
var XKmouseDown = false;
var XKmouseXOffset = 0;
var XKmouseYOffset = 0;
var XKeditingField = '';
var ns6=document.getElementById && !document.all;
var XKpixelCorrection = 0.01;

	
function XKregisterSliderTarget(slidingobj, targettype, targetobj){
    dbg('registering slider target'+targettype);
    var tar = new Array();
    tar['slidingobj'] = slidingobj;
    tar['targettype'] = targettype;
    tar['targetobj'] = targetobj;
    XKsliderTargets[XKsliderTargets.length] = tar;
    dbg('registration successful.');
}

function XKsetSliderTargetValues(value){
    for (sst=0; sst<XKsliderTargets.length; sst++){
        if (XKsliderTargets[sst]['slidingobj']==XKselectedSlider['slidingobj']){
            if (XKsliderTargets[sst]['targetobj']!=XKeditingField){
                if (XKsliderTargets[sst]['targettype']=='div'){
                    XKsliderTargets[sst]['targetobj'].innerHTML = value;
                }
                if (XKsliderTargets[sst]['targettype']=='formtext'){
                    XKsliderTargets[sst]['targetobj'].value = value;
                }
            }
        }
    }
}

function XKregisterSlider(parentobj, slidingobj, orientation, min, max, setvalue){
    if (orientation=='vertical'){
        var usex = false;
        var usey = true;
    } else {
        var usex = true;
        var usey = false;
    }
    var tar = new Array();

    if (typeof parentobj=='undefined'){
        dbg('parent object not found');
    }

    tar['slidingobj'] = slidingobj;
    tar['parentobj'] = parentobj;
    tar['orientation'] = orientation;
    tar['usex'] = usex;
    tar['usey'] = usey;
    tar['min'] = min;
    tar['max'] = max;

    XKremoveSlider(slidingobj);
    XKaddSlider(tar);
    XKselectedSlider = tar;
    XKsliderSetValue(setvalue);

}

function XKsliderSetValue(value){

    dbg("value: "+value);
    value = parseFloat(value)+XKpixelCorrection;

    var sliderinfo = XKselectedSlider;

    if (value<sliderinfo['min'])return;

    dbg("min: "+sliderinfo['min']);
    dbg("max: "+sliderinfo['max']);
    dbg("beforeval: "+value);

    if (value>sliderinfo['max']){
        value = sliderinfo['max'];
    }
    if (value<sliderinfo['min']){
        value = sliderinfo['min'];
    }

    dbg("afterval: "+value);

    value -= sliderinfo['min'];
    dbg("afterval: "+value);

    var range = sliderinfo['max']-sliderinfo['min'];
    var ratio = value/range;

    var minx = findPosX(XKselectedSlider['parentobj'])+1;
    var maxx = findPosX(XKselectedSlider['parentobj'])+parseInt(XKselectedSlider['parentobj'].style.width)-(parseInt(XKselectedSlider['slidingobj'].style.width)/1)-1;
    var miny = findPosY(XKselectedSlider['parentobj'])+1;
    var maxy = findPosY(XKselectedSlider['parentobj'])+parseInt(XKselectedSlider['parentobj'].style.height)-(parseInt(XKselectedSlider['slidingobj'].style.height)/1)-1;

    var xrange = maxx-minx;
    dbg("xrange: "+xrange);
    var xpos = (xrange*ratio)+minx;

    var yrange = maxy-miny;
    var ypos = (yrange*ratio)+miny;

    XKmoveSlider(xpos-XKmouseXOffset, ypos-XKmouseYOffset);

}

function XKsetSemanticValue(ratio){
    var range = XKselectedSlider['max']-XKselectedSlider['min'];
    var amount = Math.floor(((range*ratio)+XKselectedSlider['min'])*10)/10;
    if (amount!=amount*1)amount = 0;
    XKsetSliderTargetValues(amount);
}

var lastXPos = 0;
var lastYPos = 0;

function XKregisterMove(e){
	if(!e)e=window.event;
	if (ns6){
		var curX = e.pageX;
		var curY = e.pageY;
	} else {
		var curX = window.event.x;
		if (document.body) {
			curX += document.body.scrollLeft;
		}
		var curY = window.event.y;
		if (document.body) {
			curY += document.body.scrollTop;
		}
	}

	lastXPos = curX;
	lastYPos = curY;

    if (XKmouseDown==true){
        XKmoveSlider(curX, curY);
    }

}


function XKmoveSlider(x, y){
    var mx = x+XKmouseXOffset;
    var my = y+XKmouseYOffset;

    var minx = findPosX(XKselectedSlider['parentobj'])+1; //-(parseInt(XKselectedSlider['slidingobj'].style.width)/2);
    var maxx = findPosX(XKselectedSlider['parentobj'])+parseInt(XKselectedSlider['parentobj'].style.width)-(parseInt(XKselectedSlider['slidingobj'].style.width)/1)-1;
    var miny = findPosY(XKselectedSlider['parentobj'])+1; //-(parseInt(XKselectedSlider['slidingobj'].style.top)/2);
    var maxy = findPosY(XKselectedSlider['parentobj'])+parseInt(XKselectedSlider['parentobj'].style.height)-(parseInt(XKselectedSlider['slidingobj'].style.height)/1)-1;

    if (mx<minx){
        mx = minx;
    }
    if (mx>maxx){
        mx = maxx;
    }
    if (my<miny){
        my = miny;
    }
    if (my>maxy){
        my = maxy;
    }

    dbg("x: "+mx+" y: "+my);

    var range = 0;
    var ratio = 0;

    if (XKselectedSlider['usex']==true){
        range = maxx-minx;
        ratio = (mx-minx)/range;
        XKsliderMoveLeft(mx);
        dbg("SETTING X: "+mx);
        XKsetSemanticValue(ratio);
    }
    if (XKselectedSlider['usey']==true){
        range = maxy-miny;
        ratio = (my-miny)/range;
        XKsliderMoveTop(my);
        XKsetSemanticValue(ratio);
    }
}

function XKsliderMoveLeft(x){
	if (typeof XKselectedSlider['slidingobj'].style.left == 'string'){
		XKselectedSlider['slidingobj'].style.left = x+"px";
	} else if (XKselectedSlider['slidingobj'].style.pixelLeft){
		XKselectedSlider['slidingobj'].style.pixelLeft = x;
	}
}

function XKsliderMoveTop(y){
	if (typeof XKselectedSlider['slidingobj'].style.top == 'string'){
		XKselectedSlider['slidingobj'].style.top = y+"px";
	} else if (XKselectedSlider['slidingobj'].style.pixelTop){
		XKselectedSlider['slidingobj'].style.pixelTop = y;
	}
}

function XKsliderSetDown(e, slidingobj){
    dbg("setting slider.");
    XKmouseDown = true;
    XKmouseXOffset = -parseInt(slidingobj.style.width)/2;
    XKmouseYOffset = -parseInt(slidingobj.style.height)/2;
    XKselectedSlider = XKgetSliderInfo(slidingobj);
}

function XKsliderRelease(){
    dbg('removing slider');
    XKmouseDown = false;
}



/// supporting functions

function XKgetSliderInfo(slidingobj){
    var ret = new Array();
    for (gsi=0; gsi<XKsliders.length; gsi++){
        if (XKsliders[gsi]['slidingobj']==slidingobj){
            dbg("found sliding obj");
            ret = XKsliders[gsi];
        }
    }
    return ret;
}

function XKremoveSlider(slidingobj){
    for (gsi=0; gsi<XKsliders.length; gsi++){
        if (XKsliders[gsi]['slidingobj']==slidingobj){
            XKsliders[gsi] = null;
        }
    }
}

function XKaddSlider(tar){
    XKsliders[XKsliders.length] = tar;
}


function XKsliderEditTextField(e, textfield, slidername){
    XKsliderSetDown(e, document.getElementById(slidername));
    XKsliderRelease();
    XKsliderSetValue(textfield.value);
}


function XKsetSliderValueQuick(name, value){
	XKselectedSlider = XKgetSliderInfo(document.getElementById(name+'sliderobj'));
	XKsliderSetValue(value);
}

document.onmouseup = XKsliderRelease;
document.onmousemove = XKregisterMove;

function dbg(x){
    //document.getElementById('debugdiv').innerHTML = x+"<br />\n"+document.getElementById('debugdiv').innerHTML;
}


function findPosX(obj){ // ripped from a free script post somewhere
    var curleft = 0;
    if (obj.offsetParent){
        while (obj.offsetParent){
            curleft += obj.offsetLeft;
            obj = obj.offsetParent;
        }
    } else if (obj.x) {
        curleft += obj.x;
    }
    return curleft;
}

function findPosY(obj){ // ripped from a free script post somewhere
    var curtop = 0;
    if (obj.offsetParent){
        while (obj.offsetParent){
            curtop += obj.offsetTop;
            obj = obj.offsetParent;
        }
    } else if (obj.y) {
        curtop += obj.y;
    }
    return curtop;
}

function XKplaceBelow(anchorO, moveO){
	anchorO = $(anchorO);
	moveO = $(moveO);
	if (typeof anchorO=="object" && typeof moveO=="object"){
		var nX = findPosX(anchorO);
		var nY = findPosY(anchorO);
		var nYheight = XKgetHeight(anchorO);
		moveO.style.left = nX+'px';
		moveO.style.top = (nY+nYheight)+'px';
	}
}
// this is for when the height of the anchor cant be figured.
function XKplaceBelowPlus(anchorO, moveO, xp, yp){
	anchorO = $(anchorO);
	moveO = $(moveO);
	if (typeof anchorO=="object" && typeof moveO=="object"){
		var nX = findPosX(anchorO)+xp;
		var nY = findPosY(anchorO)+yp;
		var nYheight = XKgetHeight(anchorO);
		moveO.style.left = nX+'px';
		moveO.style.top = (nY+nYheight)+'px';
	}
}

function XKscrollIntoView(id){
	var targ = $(id);
	if (targ) targ.scrollIntoView(false);
}

function highlightOff(id, defaultclassname) {
	if (document.getElementById) {
		var elementID = document.getElementById(id);
		if (elementID && typeof elementID.className == 'string') {
			elementID.className = defaultclassname;
		}
	}
}

function highlightOn(id, defaultclassname) {
	if (document.getElementById) {
		var elementID = document.getElementById(id);
		if (elementID && typeof elementID.className == 'string') {
			elementID.className = defaultclassname+' highlight';
		}
	}
}

function highlightOnChecked(x, target, defaultclassname){
	x = document.getElementById(x);
	if (x.checked){
		highlightOn(target, defaultclassname);
	} else {
		highlightOff(target, defaultclassname);
	}
}

function checkCheckedInAMoment(x, target, defaultclassname){
	setTimeout("highlightOnChecked('"+x+"', '"+target+"', '"+defaultclassname+"');", 100);
}

function XKtoggleFormCheckboxes(f, fieldname){
    var tmp = '';
    for (xxi = 0; xxi < f.elements.length; xxi++){
        tmp = f.elements[xxi].type;
        if (tmp=="checkbox"){
            tmp = f.elements[xxi].name.toString();
            tmp = tmp.substring(0,fieldname.length);
            if (tmp.toString()==fieldname.toString()){
				if (f.elements[xxi].checked){
					f.elements[xxi].checked = false;
				} else {
					f.elements[xxi].checked = true;
				}
				f.elements[xxi].focus();
				f.elements[xxi].blur();
            }
        }
    }
    return total;
}

function XKcheckFormCheckboxes(f, fieldname){
    var tmp = '';
    for (xxi = 0; xxi < f.elements.length; xxi++){
        tmp = f.elements[xxi].type;
        if (tmp=="checkbox"){
            tmp = f.elements[xxi].name.toString();
            tmp = tmp.substring(0,fieldname.length);
            if (tmp.toString()==fieldname.toString()){
				f.elements[xxi].checked = true;
            }
			f.elements[xxi].focus();
			f.elements[xxi].blur();
        }
    }
    return total;
}

function XKuncheckFormCheckboxes(f, fieldname){
    var tmp = '';
    for (xxi = 0; xxi < f.elements.length; xxi++){
        tmp = f.elements[xxi].type;
        if (tmp=="checkbox"){
            tmp = f.elements[xxi].name.toString();
            tmp = tmp.substring(0,fieldname.length);
            if (tmp.toString()==fieldname.toString()){
				f.elements[xxi].checked = false;
            }
			f.elements[xxi].focus();
			f.elements[xxi].blur();

        }
    }
    return total;
}


/////////////////////////////////////////////////////////////////////////////////////
////////// smooth div sizing scripting below:
/////////////////////////////////////////////////////////////////////////////////////

var XKsizeObj;
var XKsizeToFitObj;
var XKsizeIncrement = 8;
var XKsizeChangeDelay = 1;
var XKstartSize = 0;
var XKendSize = 0;
var XKdelayedContent = "";
var XKsizeObjName = "";
var XKsizeToFitObjName = "";
var XKsmoothCallback = "";

function XKgetIncrement(){
	if (XKstartSize<XKendSize){
		diff = XKendSize-XKstartSize;
	} else {
		diff = XKstartSize-XKendSize;
	}
	diff = Math.floor(diff/7);
	if (diff < XKsizeIncrement){
		return XKsizeIncrement;
	} else {
		return diff;
	}
}

function XKgetHeight(obj){
	var x = Element.getDimensions(obj);
	return x.height;
}

function XKsmoothSize(sizeObjName, sizeToFitObjName){
	XKsizeObjName = sizeObjName;
	XKsizeToFitObjName = sizeToFitObjName;
	XKsizeObj = $(sizeObjName);
	XKsizeToFitObj = $(sizeToFitObjName);
	
	if (XKsizeObj==null) return;
	if (XKsizeToFitObj==null) return;
	
	if (XKsizeObj!=null && XKsizeToFitObj!=null){
		XKstartSize = XKgetHeight(XKsizeObj);
		XKendSize = XKgetHeight(XKsizeToFitObj)+(2*parseInt(XKsizeObj.style.padding));
		dbg("start size: "+XKstartSize);
		dbg("end size: "+XKendSize);
	}
	if (XKstartSize>XKendSize){
		XKsmoothSizeDown();
	} else {
		XKsmoothSizeUp();
	}
}

function XKsmoothSizeUp(){
	XKendSize = XKgetHeight(XKsizeToFitObj)+(2*parseInt(XKsizeObj.style.padding));
	var currentsize = parseInt(XKsizeObj.style.height);
	XKstartSize = currentsize;
	var thischange = XKgetIncrement();
	if (currentsize+thischange>XKendSize){
		dbg("changing height to: "+XKendSize);
		XKsizeObj.style.height = XKendSize+"px";
		if (XKsmoothCallback!=""){
			setTimeout(XKsmoothCallback, 100);
			XKsmoothCallback = "";
		}
	} else {
		dbg("changing height to: "+(currentsize+thischange));
		XKsizeObj.style.height = (currentsize+thischange)+"px";
		setTimeout("XKsmoothSizeUp();", XKsizeChangeDelay);
	}
}

function XKsmoothSizeDown(){
	XKendSize = XKgetHeight(XKsizeToFitObj)+(2*parseInt(XKsizeObj.style.padding));
	var currentsize = parseInt(XKsizeObj.style.height);
	XKstartSize = currentsize;
	var thischange = XKgetIncrement();
	if (currentsize-thischange<XKendSize){
		dbg("changing height to: "+XKendSize);
		XKsizeObj.style.height = XKendSize+"px";
		if (XKdelayedContent!=""){
			XKsizeToFitObj.innerHTML = XKdelayedContent;
			XKdelayedContent = "";
			XKsmoothSize(XKsizeObjName, XKsizeToFitObjName);
		} else {
			if (XKsmoothCallback!=""){
				setTimeout(XKsmoothCallback, 100);
				XKsmoothCallback = "";
			}
		}
	} else {
		dbg("changing height to: "+(currentsize-thischange));
		XKsizeObj.style.height = (currentsize-thischange)+"px";
		setTimeout("XKsmoothSizeDown();", XKsizeChangeDelay);
	}
}


// example usage:
/*

have your div that you will be populating with overflow: hidden; and a height set by default (0 maybe?)
<div id="outerdiv" style="border: 1px solid black; padding: 5px; width: 400px; height: 20px; overflow: hidden;">

	<div id="innerdiv"></div>

</div>

the javascript functions you might want to write to trigger the filling and sizing of these divs would be

// sizes down to one line thick then fills and sizes to fit fill.
function fillone(){
	XKdelayedContent = "asdf<br>asdf<br>asdf<br>asdf<br>asdf<br>asdf<br>asdf<br>asdf<br>";
	document.getElementById('innerdiv').innerHTML = "&nbsp;";
	XKsmoothSize('outerdiv', 'innerdiv');
}

// sizes from whatever the current size is to whatever the new fill size is
function filltwo(){
	document.getElementById('innerdiv').innerHTML = "asdf<br>asdf<br>asdf<br>asdf";
	XKsmoothSize('outerdiv', 'innerdiv');
}



*/

function XKsmoothToggle(id, content){
	if (document.getElementById) {
		var elementID = document.getElementById(id);
		if (elementID && typeof elementID.className == 'string'){
			if (elementID.className == 'off') {
				//alert("rolling out");
				elementID.className = 'on';
				document.getElementById("inner"+id).innerHTML = unescape(content);
				XKsmoothSize('outer'+id, 'inner'+id);
			} else {
				//alert("rolling in");
				XKsmoothCallback = "toggle('"+id+"');";
				document.getElementById("inner"+id).innerHTML = "<span style='font-size: 1pt;'>&nbsp;</span>";
				XKsmoothSize('outer'+id, 'inner'+id);
			}
		}
	}
}



///////////// previously in toggle.js content:

function toggle(id) {
	if (document.getElementById) {
		var elementID = document.getElementById(id);
		if (elementID && typeof elementID.className == 'string') {
			if (elementID.className == 'off') {
				elementID.className = 'on';
			} else {
				elementID.className = 'off';
			}
		}
	}
}

function toggleOff(id) {
	if (document.getElementById) {
		var elementID = document.getElementById(id);
		if (elementID && typeof elementID.className == 'string') {
			if (elementID.className == 'off') {
				elementID.className = 'off';
			} else {
				elementID.className = 'off';
			}
		}
	}
}

function toggleOn(id) {
	if (document.getElementById) {
		var elementID = document.getElementById(id);
		if (elementID && typeof elementID.className == 'string') {
			if (elementID.className == 'off') {
				elementID.className = 'on';
			} else {
				elementID.className = 'on';
			}
		}
	}
}

/*
 * ussage: <input type="button" onClick="XKmoveUp(LISTOBJECT)" value=" &uarr; "><br>
 *         <input type="button" onClick="XKmoveDown(LISTOBJECT)" value=" &darr; "><br>
 */


// get the location in a form that an element is
function getIndex(input) {
    var index = -1, i = 0;
    while (i < input.form.length && index == -1){
        if (input.form[i] == input){
            index = i;
        } else {
            i++;
        }
    }
    return index;
}

// swap 2 indexes in a select box
function XKswap(obj, in1, in2){
    if (!obj)return false;
    if (in1==in2)return true;
    if (in1>obj.options.length || in2>obj.options.length)return false;
    var opar = new Array(obj.options.length);
    for (i=0; i<obj.options.length; i++){
        if (i==in1){
            opar[in2] = obj.options[i];
        } else if (i==in2){
            opar[in1] = obj.options[i];
        } else {
            opar[i] = obj.options[i];
        }
    }
    obj.options.length = 0;
    for (i=0; i<opar.length; i++)obj.options[i]=opar[i];
}


function XKmoveUp(obj){
    moveLast = true;
    for (xi=0; xi<obj.options.length; xi++){
        if (moveLast==false && xi==obj.options.length-1)return;
        if (obj.options[xi].selected==true && xi>0){
            XKswap(obj, xi, xi-1);
        } else if (obj.options[xi].selected==true && !(xi>0)){
            return false;
        }
    }
}

function XKmoveDown(obj){
    var moveZero = true;
    for (xi=obj.options.length-1; xi>-1; xi--){
        if (moveZero==false && xi==0)return;
        if (obj.options[xi].selected==true && xi+1<obj.options.length){
            XKswap(obj, xi, xi+1);
        } else if (obj.options[xi].selected==true && !(xi+1<obj.options.length)){
            return false;
        }
    }
}

// function for filtering a string with allowedchars

// example usage: <input type="text" name="phonenumber" onkeyup="this.value=XKfilterString(this.value, '1234567890-');">
// this would allow only numbers and hyphens

function XKfilterString(str, allowchars){

    var ret = '';
    for (var i = 0; i < str.length; i++){
        if (allowchars.indexOf(str.charAt(i))!=-1){
            ret = ret+''+str.charAt(i);
        }
    }
    return ret;

}

function XKfilterStringNumbersOnly(str){
	return XKfilterString(str, "1234567890.");
}

function XKstripWhitespace(str){

    var ret = '';
    for (var xhi = 0; xhi < str.length; xhi++){
        if (str.charAt(xhi)==" " || str.charAt(xhi)=="	" || str.charAt(xhi)=="\n"){} else {
            ret = ret+''+str.charAt(xhi);
        }
    }
    return ret;

}


// function that will take a form and a string as input, then go through the form and get the input
// from any field whos name matches the string and add it up for a total.  ONLY uses decimal point
// for currency decimal notation.

function XKgetFormFieldTotals(f, fieldname){

    var total = 0;
    var stringnum = '';
    var tmp = '';
    for (xxi = 0; xxi < f.elements.length; xxi++){
        tmp = f.elements[xxi].type;
        if (tmp=="text"){
            tmp = f.elements[xxi].name.toString();
            tmp = tmp.substring(0,fieldname.length);
            if (tmp.toString()==fieldname.toString()){
                stringnum = XKfilterString(f.elements[xxi].value.toString(), '1234567890.-');
                total = total + XKround(stringnum, 2);
            }
        }
    }

    return total;

}


// function that will take a form and a string as input, then go through the form and get the input
// from any field whos name matches the string and add it up for a total.  ONLY uses decimal point
// for currency decimal notation.

function XKcheckDebitCredit(f, fieldname){

    var stringnum = '';
    var tmp = '';
    var amount = 0;
    var amount2 = 0;
    var alerted = false;
    var ret = true;
    for (xxi = 0; xxi < f.elements.length; xxi++){
        tmp = f.elements[xxi].type;
        if (tmp=="text"){
            tmp = f.elements[xxi].name.toString();
            tmp = tmp.substring(0,fieldname.length);
            if (tmp.toString()==fieldname.toString()){
                stringnum = XKfilterString(f.elements[xxi].value.toString(), '1234567890.-');
                amount = XKround(stringnum, 2);
                stringnum = XKfilterString(f.elements[xxi+1].value.toString(), '1234567890.-');
                amount2 = XKround(stringnum, 2);
                if (amount*1>0 && amount2*1>0){
                    f.elements[xxi].style.backgroundColor = 'red';
                    f.elements[xxi+1].style.backgroundColor = 'red';
                    f.elements[xxi].style.color = 'white';
                    f.elements[xxi+1].style.color = 'white';
                    ret = false;
                    if (alerted==false){
                        alerted = true;
                        alert("You cannot have a debit and a credit in the same entry.\nPlease create separate entries.");
                    }
                } else {
                    f.elements[xxi].style.backgroundColor = '';
                    f.elements[xxi+1].style.backgroundColor = '';
                    f.elements[xxi].style.color = '';
                    f.elements[xxi+1].style.color = '';
                }
            }
        }
    }

    return ret;

}


function XKgetNumberFromLocaleFormat(number, decSep, groupSep){
    if (decSep==""){ // get the decimal separator if not passed
        decSep = ".";
    }
    if (groupSep==""){  // get the grouping separator if not passed
        groupSep = ",";
    }
	number = number.toString(); // set the number as a string
    var neg = (number.indexOf("-")==-1)?"":"-"; // index of the format string to use, 1 = second one, which is the negative number format string
	while (number.indexOf(groupSep)!=-1){
		number = number.replace(groupSep, "");
    }
    number = number.replace(decSep, ".");
	number = XKfilterString(number, "1234567890.");
	return parseFloat(neg+number);
}

// function for formatting a currency number on the fly in javascript similar to our locale array.
// uses: ANYTHING#,##0.00ANYTHING;NEGANYTHING#,##0.00NEGANYTHING style format string
// and gets the comma length by getting       ^---  (number of characters between the comma and decimal)
// gets the number of decimals by checking how many zeros are after the decimal

function XKformatNumber(formatstring, number, decSep, groupSep){

    if (decSep==""){ // get the decimal separator if not passed
        decSep = ".";
    }
    if (groupSep==""){  // get the grouping separator if not passed
        groupSep = ",";
    }
	//groupSep = groupSep.replace("?", "");
	//decSep = decSep.replace("?", "");
	//groupSep = groupSep.replace("?", "");
	//decSep = decSep.replace("?", "");
	//formatstring = formatstring.replace("?", "");
	//formatstring = formatstring.replace("?", "");
	number = number.toString(); // set the number as a string
    var neg = (number.indexOf("-")==-1)?0:1; // index of the format string to use, 1 = second one, which is the negative number format string
    var fmtStrs = formatstring.split(";"); // array of format strings
    formatstring = fmtStrs[neg]; // choose the negative or positive format string and filter it for special characters
	if (formatstring==""){
		formatstring = fmtStrs[0];
	}
	while (formatstring.indexOf("0")!=-1){
        formatstring = formatstring.replace("0", "#");
    }


    stringparts = formatstring.split("#");
    numfirst = stringparts[0];
    numlast = stringparts[stringparts.length-1];
    firstpos = numfirst.length;
    lastpos = formatstring.length;

    if (numlast!=""){
        lastpos = formatstring.indexOf(numlast);
    }

    if (lastpos==firstpos){
        lastpos = formatstring.length-1;
    }

    var innerformatstring = formatstring.substring(firstpos, lastpos);

    innerformatstring = innerformatstring.split(decSep);
    var decimals = (innerformatstring[1])?innerformatstring[1].length:0;
    innerformatstring[0] = innerformatstring[0].split(groupSep);
    var commadigits = innerformatstring[0][innerformatstring[0].length-1].length;

	number = number.replace(groupSep, "X");
	number = number.replace(decSep, ".");
	number = number.replace("X", ",");
	number = XKfilterString(number, "1234567890.");
	number = parseFloat(number);
    number = XKround(number, decimals);
    number = number.toString();
    number = number.split(".");
	if (!number[1]){
        number[1] = "";
    }
    while (number[1].length<decimals){
        number[1] = number[1]+""+"0";
    }

    numdefault = 1/Math.pow(10, decimals+1);
    numdefault = numdefault.toString().split(".");
    numdefault = numdefault[1].substring(0, decimals);
    if (!numdefault){
        numdefault = "";
    }
    while (numdefault.length<decimals){
        numdefault = numdefault+"0";
    }

    if (numfirst==numlast){
        numlast = 0;
    }

    if (parseInt(number[0])>0){

        var assume = (number[0].length % commadigits);
        if (assume>0)assume = commadigits-assume;

        var numberparts = XKchunkSplit(number[0], commadigits, assume);
        var endnumber = numfirst+''+numberparts[0];
        for (i = 1; i < numberparts.length; i++){
            endnumber = endnumber+groupSep+numberparts[i];
        }

    } else {
        var endnumber = numfirst+'0';
    }

    if (number[1]!=""){
        endnumber = endnumber+''+decSep+number[1]+''+numlast;
    } else {
        endnumber = endnumber+''+decSep+numdefault+''+numlast;
    }

    return endnumber;
}

function mydbg(x){
	if (typeof x=="Array"){
		for (key in x){
			mydbg("key: "+key);
			mydbg(x[key]);
			mydbg("end");
		}
	} else {
		document.getElementById('xdbg').innerHTML += x+"<br />";
	}
}

// splits a given string into an array of given chunk sizes

function XKchunkSplit(str, size, assume){

    var retarray = new Array();
    for (i = 0; i < str.length/size; i++){
        retarray[i] = '';
        for (x = 0; x < size; x++){
            if ((i*size)+x-assume<str.length && (i*size)+x-assume>-1){
                retarray[i] = retarray[i]+''+str.charAt((i*size)+x-assume);
            }
        }
    }

    return retarray;

}

// rounding function for decimal places in javascript

function XKround(number, decimals){

    number = parseFloat(number); // get float
    number = number * Math.pow(10, decimals); // multiply times 10 to the power of "decimals"
    number = Math.round(number); // round to whole number
    number = number / Math.pow(10, decimals); // divide by 10 to the power of "decimals"
    return number; // return number

}


// functions to copy text from one field to another on the fly with a conditional arguments

var XKfieldCopyFields = new Array();
var XKfieldCopyToFields = new Array();
var XKconditionalFields = new Array();
var XKconditionalUpdateData = new Array();

function XKcopyRegisterConditionalField(conditionaltype, conditionalfield){
    db('registering conditional field');
    if (typeof conditionalfield=='undefined')return false;
    db('got past test for conditional validity');
    XKconditionalFields[conditionalfield.name] = new Array(conditionaltype, conditionalfield);
    return true;
}

function XKcopyRegisterCopyField(copyfield){
    db("trying to register a copy field");
    if (typeof copyfield=='undefined')return false;
    db("copy field is an actual field, registering");
    XKfieldCopyFields[copyfield.name] = copyfield;
    //copyfield.onkeyup = XKcopyCheckUpdate(copyfield.name);
    //db("adding onkeyup action to copy field");
}

function XKcopyRegisterCopyToField(copyfieldname, copytofield, conditionalfieldname){
    db('trying to register copy to field');
    if (typeof copytofield=='undefined')return false;
    db('copy to field is a valid field');
    if (typeof XKfieldCopyToFields[copyfieldname]=='undefined'){
        db('created copyfieldname item in copy to fields array');
        XKfieldCopyToFields[copyfieldname] = new Array();
    }
    XKfieldCopyToFields[copyfieldname][XKfieldCopyToFields[copyfieldname].length] = new Array(copytofield, conditionalfieldname);
    XKconditionalUpdateData[XKconditionalUpdateData.length] = new Array(copytofield, conditionalfieldname, copyfieldname);
    db('done registering copy to field');
}

function XKcopyCheckMe(copyfield){
    return XKcopyCheckUpdate(copyfield.name);
}

function XKcopyCheckUpdate(copyfieldname){
    db('checking an update');
    if (typeof XKfieldCopyFields[copyfieldname]=='undefined')return false;
    db('there is a field object');
    var copyfield = XKfieldCopyFields[copyfieldname];
    db('got copy field object');
    var updateFields = XKfieldCopyToFields[copyfield.name];
    db('got updatefields');
    var thisField = new Array();

    if (typeof updateFields!='undefined'){
        db("there are fields to update");
        for (xi=0; xi<updateFields.length; xi++){

            thisField = updateFields[xi];
            db('got '+xi+' numbered field to check');
            if (XKcopyCheckConditional(thisField[1])){
                db('checked conditional and now initiating copy');
                XKcopyCopyValue(copyfield, thisField[0]);

            }

        }
    }

}


function XKcopyCheckConditional(conditionalname){
    db('checking if conditional exists');
    if (typeof XKconditionalFields[conditionalname]=='undefined')return false;

    var thisConditional = XKconditionalFields[conditionalname];
    if (thisConditional[0]=='checkbox'){
        db('conditional was checkbox returning:'+thisConditional[1].checked);
        return thisConditional[1].checked;
    }

}


function XKcopyCopyValue(copyfield, copytofield){
    db('copying values...');
    if (copyfield.type=="text"){
        copytofield.value = copyfield.value;
    } else if (copyfield.type.toString().indexOf('select') != -1) {
        copytofield.selectedIndex = copyfield.selectedIndex;
    }
}

function XKcopyUpdateConditional(conditionalfieldname){
    if (typeof XKconditionalFields[conditionalfieldname]=='undefined')return false;
    var conditionalfield = XKconditionalFields[conditionalfieldname][1];

    var updateFields = XKconditionalUpdateData;
    var thisField = new Array();

    for (xi=0; xi<updateFields.length; xi++){

        thisField = updateFields[xi];
        if (XKcopyCheckConditional(thisField[1])){
            if (typeof XKfieldCopyFields[thisField[2]]!='undefined'){
                XKcopyCopyValue(XKfieldCopyFields[thisField[2]], thisField[0]);
            }

        }

    }

}

function db(x){
    if (typeof XKdebugBox=='undefined')return true;
    XKdebugBox.value = XKdebugBox.value+"\n"+x;
    return true;
}

/*****************************

sample usage:
in your checkbox:  onmouseup="setTimeout('XKcopyUpdateConditional(\'checkboxname\');', 10);"
in your copy fields:  onkeyup="XKcopyCheckMe(this);"
<script language=javascript>
<!--

    var tf = document.tf;
    XKcopyRegisterConditionalField('checkbox', tf.conditional);

    XKcopyRegisterCopyField(tf.text1);
    XKcopyRegisterCopyToField('text1', tf.text1copy, 'conditional');


//-->
</script>

<p id="bentag">
sadf
</p>

document.getElementById('bentag').onclick = hideobjbyid('bentag');
******************************/


function showobj(x){
    x.style.display = '';
    x.style.visibility = 'visible';
}

function hideobj(x){
    x.style.display = 'none';
    x.style.visibility = 'hidden';
}

function showobjbyid(x){
    showobj(document.getElementById(x));
}

function hideobjbyid(x){
    hideobj(document.getElementById(x));
}

function toggleobjbyid(x){
	var xx = document.getElementById(x);
	if (xx.style.display=="none"){
		showobj(xx);
	} else {
		hideobj(xx);
	}
}

function XKtoggleobjbyid(x){
	toggleobjbyid(x);
}

function radioSelectedValue( form, name ) {
	for (i=0; i<form.elements.length; i++){
		if (form.elements[i].type=="radio" && form.elements[i].name==name) {
			if (form.elements[i].checked) {
				return form.elements[i].value;
			}
		}
	}
}


// function to repopulate a select menu given its object and an array of values and display values

function repopulateSelect(field, values){

	field.options.length = 0;

	for (i=0; i<values.length; i++){
		field.options[i] = new Option(unescape(values[i][0]), unescape(values[i][1]));
	}

}

/***********************
example:

<script language="javascript">
<!--

var info = new Array(

    new Array(new Array('3one', '3onename'), new Array('3two', '3twoname')),

    new Array(new Array('4one', '4onename'), new Array('4two', '4twoname'), new Array('4three', '4threename'))

);

function updateSelect(val){
    repopulateSelect(document.tform.otherfield, info[val]);
}

//-->
</script>

<form name="tform">

<select name="name" onchange="updateSelect(this.selectedIndex);">
    <option value="3">3333</option>
    <option value="4">4444</option>
</select>
<select name="otherfield">
</select>

</form>


***********************/

var mgbpopupwindows = new Array();

function openwin(page, w, h, n){
	if (n=="") {
		n = "_blank";
	}
	var s="menubar=1,scrollbars=1,resizable,left="+100+",top="+100+",screenX="+100+",screenY="+100+",width="+w+",height="+h; 		
	mgbpopupwindows[n] = window.open(page,n,s);
}

function closewin(n){
	if (mgbpopupwindows[n]) {
		mgbpopupwindows[n].close();
	}
}

function printwin() { 
	window.print(); 
}

function XKshowClientActionMenu(e, id, clientID, clientContactID){
	if(!e)e=window.event;
	if (ns6){
		var curX = e.pageX;
		var curY = e.pageY;
	} else {
		var curX = e.x;
		curX += document.body.scrollLeft;
		var curY = e.y;
		curY += document.body.scrollTop;
	}

	var content = $('clientActionMenuTemplate').innerHTML;
	content = new String(content.replace(/THECLIENTID/g,clientID));
	content = new String(content.replace(/THECLIENTCONTACTID/g,clientContactID));
	content = new String(content.replace(/THEOBJECTNAME/g,id));

	document.getElementById(id).style.left = curX;
	document.getElementById(id).style.top = curY;
	$(id).innerHTML = content;
	showobjbyid(id);
}

function XKshowPackageActionMenu(e, id, packageID){
	if(!e)e=window.event;
	if (ns6){
		var curX = e.pageX;
		var curY = e.pageY;
	} else {
		var curX = e.x;
		curX += document.body.scrollLeft;
		var curY = e.y;
		curY += document.body.scrollTop;
	}

	var content = $('packageActionMenuTemplate').innerHTML;
	content = new String(content.replace(/THEPACKAGEID/g,packageID));
	content = new String(content.replace(/THEOBJECTNAME/g,id));

	document.getElementById(id).style.left = curX;
	document.getElementById(id).style.top = curY;
	$(id).innerHTML = content;
	showobjbyid(id);
}

function XKshowProductActionMenu(e, id, productID, isAddon){
	if(!e)e=window.event;
	if (ns6){
		var curX = e.pageX;
		var curY = e.pageY;
	} else {
		var curX = e.x;
		curX += document.body.scrollLeft;
		var curY = e.y;
		curY += document.body.scrollTop;
	}
	
	if (parseInt(isAddon)>0){
		var xstyle = "display: none;";
	} else {
		var xstyle = "";
	}

	var content = $('productActionMenuTemplate').innerHTML;
	content = new String(content.replace(/THEPRODUCTID/g,productID));
	content = new String(content.replace(/THEOBJECTNAME/g,id));
	content = new String(content.replace(/MAINPRODUCTSTYLE/g,xstyle));

	document.getElementById(id).style.left = curX;
	document.getElementById(id).style.top = curY;
	$(id).innerHTML = content;
	showobjbyid(id);
}

function XKshowPrintActionMenu(e, id){
	if(!e)e=window.event;
	if (ns6){
		var curX = e.pageX;
		var curY = e.pageY;
	} else {
		var curX = e.x;
		curX += document.body.scrollLeft;
		var curY = e.y;
		curY += document.body.scrollTop;
	}
	
	document.getElementById(id).style.left = curX;
	document.getElementById(id).style.top = curY;
	showobjbyid(id);
}

var moveOffTimers = new Array();

function XKstartMoveOffTimer(id, timeperiod){
	if (moveOffTimers[id]){
		clearTimeout(moveOffTimers[id]);
	}
	moveOffTimers[id] = setTimeout("hideobjbyid('"+id+"');", 1000);
}

function XKkillMoveOffTimer(id){
	setTimeout("clearTimeout(moveOffTimers['"+id+"']);", 10);
}

String.prototype.stripSpaces=function(){
    return this.replace(/\s*/g,'');
}

String.prototype.trim=function(){
    return this.replace(/^\s*|\s*$/g,'');
}

String.prototype.ltrim=function(){
    return this.replace(/^\s*/g,'');
}

String.prototype.rtrim=function(){
    return this.replace(/\s*$/g,'');
}

function getSelText(){
	var txt = '';
	if (window.getSelection){
		txt = window.getSelection();
	} else if (document.getSelection){
		txt = document.getSelection();
	} else if (document.selection){
		txt = document.selection.createRange().text;
	} else {
		return;
	}
	return txt;
}

function handleDoubleClick(e){
	if(!e)e=window.event; // for ie
	
	var text = getSelText()+"";
	var tb = document.getElementById('topSearchQueryBox');
	var bb = document.getElementById('bottomSearchQueryBox');
	var ib = document.getElementById('invoiceSearchBox');
	
	if (tb){
		tb.value = text.trim();
	}
	if (bb){
		bb.value = text.trim();
	}
	if (ib){
		ib.value = text.trim();
	}
}

var BGCLASS = "";
var FGCLASS = "";
var CENTER = "";
var STICKY = "";
var CAPTION = "";
var CLOSECLICK = "";
var CLOSETEXT = "";
var CAPTIONFONTCLASS = "";
var SNAPX = "";
function nd(){
}
function overlib(contentHTML, bgclass, popupBG, fgclass, popupFG, center, sticky, xcaption, caption, cc, ct, closeimg){
	return XKoverlib(contentHTML, bgclass, popupBG, fgclass, popupFG, center, sticky, xcaption, caption, cc, ct, closeimg);
}
function XKoverlib(contentHTML, bgclass, popupBG, fgclass, popupFG, center, sticky, xcaption, caption, cc, ct, closeimg){
	XKol(contentHTML, caption);
}

function XKol(contentHTML, caption){
	document.getElementById('overLibReplacementDivCaption').innerHTML = caption;
	document.getElementById('overLibReplacementDivContentCell').innerHTML = contentHTML;
	document.getElementById('overLibReplacementDiv').style.top = lastYPos+"px";
	document.getElementById('overLibReplacementDiv').style.left = lastXPos+"px";
	document.getElementById('overLibReplacementDiv').style.display = "inline";
	document.getElementById('overLibReplacementDiv').style.visibility = "visible";
}

function XKPopoverElement(id){
	$(id).style.top = lastYPos+"px";
	$(id).style.left = lastXPos+"px";
	$(id).style.display = "inline";
	$(id).style.visibility = "visible";
}

function XKMoveOnScreen(id){
	var xo = $(id);
	if (typeof xo!="undefined"){
		var cx = findPosX(xo.style.left);
		if (cx==0) cx = lastXPos+28;
		var cw = parseInt(xo.style.width);
		var diff = cw+cx - parseInt(document.body.offsetWidth);
		if (diff>0){
			xo.style.left = (cx-diff-5)+"px";
			xo.style.marginTop = "19px";
		}
	}
}

function iXKtoJSON(obj, nl, tb, prefix){
	var ret = '';
	if (typeof obj=="undefined"){
		return '""';
	} else if (typeof obj!="object"){
		return '"'+obj+'"';
	} else {
		ret = "{";
		var did = false;
		for (x in obj){
			if (x.indexOf('"')==-1 && x.indexOf('\\')==-1){
				did = true;
				ret = ret+nl+prefix+tb+'"'+x+'" : ' + iXKtoJSON(obj[x], nl, tb, prefix + tb) + ',';
			}
		}
		if (did) ret = ret.substring(0, ret.length-1);
		ret = ret+nl+prefix+"}";
		return ret;
	}
}

function XKtoJSON(obj){return iXKtoJSON(obj, '', '', '');}
function prettyXKtoJSON(obj){return iXKtoJSON(obj, '\n', '\t', '');}

function XKgetCheckboxAsscArray(frm, idstart, attrname){
	if (attrname=="") attrname = "myAttr";
	var cret = 0;
	var uret = 0;
	var ret = {
		"checked" : new Object(),
		"unchecked" : new Object()
	};
	var cel = null;
	for (i=0; i<frm.elements.length; i++){
		cel = frm.elements[i];
		if (cel.type=="checkbox" && cel.getAttribute("id").substring(0, idstart.length).toLowerCase()==idstart.toLowerCase()){
			if (cel.checked){
				ret["checked"][cret++] = cel.getAttribute(attrname);
			} else {
				ret["unchecked"][uret++] = cel.getAttribute(attrname);
			}
		}
	}
	return ret;
}

function XKgetCheckedAsscArray(frm, idstart, attrname){
	var r = XKgetCheckboxAsscArray(frm, idstart, attrname);
	return r["checked"];
}

function XKgetUncheckedAsscArray(frm, idstart, attrname){
	var r = XKgetCheckboxAsscArray(frm, idstart, attrname);
	return r["unchecked"];
}

function XKcreateIndexedQueryString(dataarray, key){
	var qs = "";
	var p = 0;
	if (typeof dataarray!="undefined"){
		for (x in dataarray){
			if (typeof dataarray[x]=="string" || typeof dataarray[x]=="number"){
				qs = qs + key + "[" + p + "]=" + dataarray[x] + "&";
			} else if (typeof dataarray[x]=="object"){
				qs = qs + XKcreateIndexedQueryString(dataarray[x], key + '['+p+']');
			}
			p++;
		}
	}
	return qs;
}

function XKvalidateRoutingNumber(num){
	if (num.length!=9) return false;
	var total = 
	(num.charAt(0)*3) +
	(num.charAt(1)*7) +
	(num.charAt(2)*1) +
	(num.charAt(3)*3) +
	(num.charAt(4)*7) +
	(num.charAt(5)*1) +
	(num.charAt(6)*3) +
	(num.charAt(7)*7) +
	(num.charAt(8)*1);
	return (total%10==0) ? true : false;
}


function XKcreateAsscQueryString(dataarray, key){
	var qs = "";
	if (typeof dataarray!="undefined"){
		for (x in dataarray){
			if (typeof dataarray[x]=="string" || typeof dataarray[x]=="number"){
				if (key=='' || key==false){
					qs = qs + x + "=" + dataarray[x] + "&";
				} else {
					qs = qs + key + "[" + x + "]=" + dataarray[x] + "&";
				}
			} else if (typeof dataarray[x]=="object"){
				qs = qs + XKcreateAsscQueryString(dataarray[x], key + '['+x+']');
			}
		}
	}
	return qs;
}

function XKcreateFormQueryString(f){
	if (typeof f=="undefined"){
		return alert("Invalid form object.");
	}
	var tf;
	var qs = "";
	for (var fi=0; fi<f.elements.length; fi++){
		tf = f.elements[fi];
		switch (tf.type){
			case "hidden":
			case "text":
			case "textarea":
				qs = qs + tf.name + "=" + escape(tf.value) + "&";
			break;
			case "select":
			case "select-one":
				for (var si=0; si<tf.options.length; si++){
					if (tf.options[si].selected){
						qs = qs + tf.name + "=" + escape(tf.options[si].value) + "&";
					}
				}
			break;
			case "radio":
			case "checkbox":
				if (tf.checked){
					qs = qs + tf.name + "=" + escape(tf.value) + "&";
				}
			break;
		}
	}
	return qs;
}

function XKfirstParentWithAttribute(obj, attrname){
	if (typeof obj!="undefined"){
		var par = obj["parentElement"];
		var go = true;
		while (go==true){
			if (par.getAttribute(attrname)!=""){
				go = false;
			}
		}
		return par;
	} else {
		return false;
	}
}

function XKchangeClass(id, newClass) {
	var element = $(id);
	if (element) {
		element.className = newClass;
	}
}


function checkAll(checkname, exby) {
	for (i = 0; i < checkname.length; i++) {
		if (!checkname[i].disabled) {
			checkname[i].checked = (exby.checked) ? true : false ;
		}
	}
}

function addLoadEvent(func) {
	var oldonload = window.onload;
	if (typeof window.onload != 'function') {
		window.onload = func;
	} else {
		window.onload = function() {
			if (oldonload) {
				oldonload();
			}
			func();
		}
	}
}

function serializeContent(obj){
	var obj = $(obj);
	var content = escape(obj.innerHTML);
	obj.innerHTML = '';
	if (content) obj.setAttribute("serializedContent", content);
}
function unserializeContent(obj){
	var obj = $(obj);
	var content = unescape(obj.getAttribute('serializedContent'));
	if (content) obj.innerHTML = content;
}

function toggleCheckboxDelay(cbx, cnt){
	setTimeout("toggleCheckboxContent('"+cbx+"', '"+cnt+"');", 100);
}

function toggleCheckboxContent(cbx, cnt){
	var checkbox = $(cbx);
	var content = $(cnt);
	if (checkbox && content){
		if (checkbox.checked==true){
			content.show();
		} else {
			content.hide();
		}
	}
}

function toggleRadioDelay(rd, cnt, selector){
	setTimeout("toggleRadioContent('"+rd+"', '"+cnt+"', '"+selector+"');", 100);
}

function toggleRadioContent(rd, cnt, selector){
	var toggleBoxes = document.body.getElementsBySelector('['+selector+']');
	for (i in toggleBoxes){
		if (typeof toggleBoxes[i]=="object" && typeof toggleBoxes[i].id!="undefined"){
			toggleBoxes[i].hide();
		}
	}
	if ($(rd).checked==true){
		$(cnt).show();
	}
}


function highlightThenFade(id){
	new Effect.Highlight(id, {'duration' : 5, 'queue' : 'front'});
	new Effect.Fade(id, {'duration' : 1, 'queue' : 'end'});
}

function XKgetJSONArray(json){
	if (typeof json=="string"){
		json = !(/[^,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(json.replace(/"(\\.|[^"\\])*"/g, ''))) && eval('(' + json + ')');
		return json;
	} else if (typeof json=="object"){
		return json;
	}
}

