// global variables
var ExpEleCount = 0;
var MonthNames = new Array("January", "February", "March", "April", "May", "June", 
"July", "August", "September", "October", "November", "December");
var DOWNames = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");

//Only all characters that are found in phone numbers: (), 0-9, -, x
function AllowPhoneNoOnly(suceso) {
//include the following for the onkeypress attribute: onkeypress="return AllowPhoneNoOnly(event)"
var E = null;
var kp = 0;
//Get reference to the KeyPress event
if (suceso) {E = suceso;}               //If W3C broswer sends reference automatically
else if (window.event) {E = window.event;}  // If IE4+ browser
else {return true;}

//Get a reference to the Key that was pressed
if (E.charCode) {kp = E.charCode;}		 //non-IE browsers: distinguish between KeyCode and CharCode; use CharCode if available
else if (E.keyCode) {kp = E.keyCode;}  //for onkeypress events, returns character code (returns keycode for onkeydown/up events)
else if (E.which) {kp = E.which;}	//NN4 only
else {return true;}

//Only allow some characters to pass
if (kp == 45) {return true;}				//-
else if (kp == 8) {return true;}		//BS
else if (kp == 127){return true;}  // Del
else if (kp == 40) {return true;}		//(
else if (kp == 41) {return true;}		//)
else if (kp == 101) {return true;}		//e
else if (kp == 69) {return true;}		//E
else if (kp == 88) {return true;}		//X
else if (kp == 120) {return true;}		//x
else if (kp == 215) {return true;}		//×
else if (kp == 116) {return true;}		//t
else if (kp == 84) {return true;}		//T
else if (kp == 46) {return true;}		//.
else if (kp == 32) {return true;}		//(space)
else if (kp < 48) {return false;}		//<0
else if (kp > 57) {return false;}		//>9
else {return true;}			//JIC
} //end fcn AllowPhoneNoOnly


function AllowIntOnly(suceso) {
//Use this for the onkeypress event: onkeypress="return AllowIntOnly(event)"
var E = null;
var kp = 0;
//Get reference to the KeyPress event
if (suceso) {               //If W3C broswer sends reference automatically
	E = suceso;
} else if (window.event) {  // If IE4+ browser
	E = window.event
} else {
	return true;
}  //end if

//Get a reference to the Key that was pressed
if (E.charCode) {		 //non-IE browsers: distinguish between KeyCode and CharCode; use CharCode if available
	kp = E.charCode;
} else if (E.KeyCode) {  //for onkeypress events, returns character code (returns keycode for onkeydown/up events)
	kp = E.keyCode;
} else if (E.which) {	//NN4 only
	kp = E.which;
} else {
	return true;
}  // end if

//Only allow digits
if (kp == 8) {				//BS
	return true;
} else if (kp < 48) {		//<0
	return false;
} else if (kp > 57) {		//>9
	return false;
} else {
	return true;			//JIC
}}  //end if  //end fcn


function AllowDecimalOnly(suceso) {
//Use this for the onkeypress event: onkeypress="return AllowDecimalOnly(event)"
var E = null;
var kp = 0;
//Get reference to the KeyPress event
if (suceso) {               //If W3C broswer sends reference automatically
	E = suceso;
} else if (window.event) {  // If IE4+ browser
	E = window.event
} else {
	return true;
}  //end if

//Get a reference to the Key that was pressed
if (E.charCode) {		 //non-IE browsers: distinguish between KeyCode and CharCode; use CharCode if available
	kp = E.charCode;
} else if (E.KeyCode) {  //for onkeypress events, returns character code (returns keycode for onkeydown/up events)
	kp = E.keyCode;
} else if (E.which) {	//NN4 only
	kp = E.which;
} else {
	return true;
}  // end if

//Only allow digits, BS, and decimal
if (kp == 8) {				//BS
	return true;
} else if (kp == 46) {				//.
	return true;
} else if (kp < 48) {		//<0
	return false;
} else if (kp > 57) {		//>9
	return false;
} else {
	return true;			//JIC
}}  //end if  //end fcn


function AllowTimeOnly(suceso) {
//include the following for the onkeypress attribute: onkeypress="return AllowTimeOnly(event)"
var E = null;
var kp = 0;

//Get reference to the KeyPress event
if (suceso) {E = suceso;}               //If W3C broswer sends reference automatically
else if (window.event) {E = window.event;}  // If IE4+ browser
else {return true;}

//Get a reference to the Key that was pressed
if (E.charCode) {kp = E.charCode;}		 //non-IE browsers: distinguish between KeyCode and CharCode; use CharCode if available
else if (E.keyCode) {kp = E.keyCode;}  //for onkeypress events, returns character code (returns keycode for onkeydown/up events)
else if (E.which) {kp = E.which;}	//NN4 only
else {return true;}

//Only allow some characters to pass
if (kp == 8) {return true;}		//BS
else if (kp == 58) {return true;}		//:
else if (kp == 32) {return true;}		//(space)
else if (kp < 48) {return false;}		//<0
else if (kp > 57) {return false;}		//>9
else {return true;}			//JIC
} //end fcn AllowTimeOnly


function CheckMaxLength(e, gob, lar){
if(!gob){return true;}
if(!gob.value){return true;}
var L = gob.value.length;

// get the key that was pressed
var kp = GetCharCode(e);

// allow or prohibit the keypress
if(kp == 8){return true;}
else if(kp == 127){return true;}
else if(L < lar){return true;} 
else {return false;}
} //end fcn CheckMaxLength


function FillStrLen(gob, lar, ctr, trunc){
// add this to onkeyup handler for the object with the max length:
// gob.onkeyup = function(){FillStrLen(this, 100, 'u1', truncTF);};
// add this indicator somewhere near the text area:
// limit: 100 characters. Used: <span id="u1">0</span><br />
// customize character lengths and ids.
// make sure this file is reverence by the calling file
/* 
gob: ctrl to limit
lar: character limit
ctr: span showing number of char
trunc: boolean indicating to trunc or not
*/

// initialize
var L = null;
var v = null;
var s = null;
var estilo = new Array();
gob = ReturnObjRef(gob);
if(!gob){return;}

// get text length
v = gob.value;
L = v.length;
if(!isNaN(parseInt(L))){
if(!isNaN(parseInt(lar))){
if(L >= lar){
estilo['color'] = "#ffffff";
estilo['backgroundColor'] = "#800000";
estilo['fontWeight'] = "bold";
estilo['padding'] = "0px 2px";
estilo['border'] = "solid 1px #000000";
if(trunc){
s = v.substr(0, lar);
gob.value = s;}}
else {
estilo['color'] = "#000000";
estilo['backgroundColor'] = "transparent";
estilo['fontWeight'] = "normal";
estilo['padding'] = "0px 2px";
estilo['border'] = "none";
}}
FillElementWithText(ctr, L, estilo);}
} // end fcn FillStrLen


function MakeProdID(){
var Base36 = "0abcdefghijkLmnopqrstuvwxyz123456789";
var ABC = "";
var tnow = new Date();
var tmo = tnow.getMonth();
var tda = tnow.getDate();
var thr = tnow.getHours();
var tmi = tnow.getMinutes();
var tse = tnow.getSeconds();

//calculate approximate seconds since Jan 1
var asj = tmo*2678400 + tda*86400 + thr*3600 + tmi*60 + tse;

//convert to base 36
for(var i=0; i<5; i++){

//get remainder
var r = asj % 36;
asj = Math.floor(asj / 36);

//get string position
r = Base36.substr(r, 1);

//assign result string
ABC = r + ABC;
} //end for i

ABC = "_" + ABC;
return ABC;
} //end fcn MakeProdID


function ShowHide(s, h, d, scr, f, x, cb){
/*
s id to show
h id to hide
d display type for id to show
scr Instructions for scroll into view: "top", "bottom", falsy, or a non-zero integer for ScrollBy
f id of element to receive focus
x total expand amount (high estimated is better than low)
cb callback function on completion
*/

// make default display type
if(!d){d = "block";}
var E = null;

// hide element
if(h){E = ReturnObjRef(h);
if(E){E.style.display = "none";}}

// expand element
if(x){
ExpandAndShow(s, d, scr, f, x, cb);
return;}

// or show element et al. if height is not specified
if(s){E = ReturnObjRef(s);
if(E){E.style.display = d;

// scroll element into view
if(scr){
if(scr === "top"){E.scrollIntoView(true);}
else if(scr === "bottom"){E.scrollIntoView(false);}
else if(typeof scr == "number"){
scr = parseInt(scr);
if(!isNaN(scr)){window.scrollBy(0, scr);}}}}}

// focus
if(f){E = ReturnObjRef(f);
if(E){E.focus();}}
// call callback function
if(cb){cb();}
} // end fcn ShowHide


function JStrim(s){
var t = s.replace(/^\s+/, "");
var u = t.replace(/\s+$/, "");
return u;
} // end fcn JStrim


function JSPaidTF(pasta, xdati, xid, xp, xap, xpm){
// check payment status
if(pasta){switch(pasta){
case "Processed": return true;
case "Completed": return true;
case "Canceled_Reversed": return true;
case "Pending": return true;
case "Refunded": return false;
case "Reversed": return false;
case "Expired": return false;
case "Voided": return false;
case "Failed": return false;
case "Denied": return false;
case "Paid": if(xp == "CC"){return true;}
case "Paid-CC": return true;
case "$0 Due": return true;
case "Unpaid": return false;}}

// check XacnDaTi and XacnID
if(xdati){return true;}
else if(xid){return true;}
else if(xap){
var fxap = parseFloat(xap);
if(fxap >= 0.01){return true;}}

// check for valid payment method
if(xpm){
if(xpm == 2){return true;}				// PP
else if(xpm == 3){return true;}		// CC
else if(xpm == 4){return true;}}	// Waived

// if all are empty, then reservation is unpaid
return false;
} // end fcn JSPaidTF


function ViewReservationsPolicy(a){
// establish URL
var rp = "reservationspolicy.php";
if(a){rp = rp + "#" + a;}

// open new window
var w = window.open(rp, "respol", "height=600,width=600,resizable=1,scrollbars=1,status=1");

// fine tune window
if(w){
w.focus();

if(a){
var wd = w.window.document.getElementById(a);
if(wd){wd.scrollIntoView();}}

// prevent link action
return false;}
/*
<!--
// Recommended link to reservations policy.  Has backup href in case JS is disabled:
// Read the <a href="reservationspolicy.php" onclick="return ViewReservationsPolicy();">Reservations Policy</a>
-->
*/
} // end fcn ViewReservationsPolicy


function ExpandAndShow(gid, b, scr, f, y, cb){
// show element with minimal height
var g = ReturnObjRef(gid);
if(!g){
alert("Error: Page element (id = " + gid + ") cannot be shown.");
return;}
g.style.overflow = "hidden";
g.style.maxHeight = "1px";
g.style.display = b;

// determine expansion increment (50 ms increments; 700 ms max time = 14 intervals)
if(y > 600){y = 600;}
x = (y / 14);
x = parseInt(x);
if(x < 5){x = 5;}

// compensate for variables being boolean or string
// if(scr){if(typeof scr == "string"){scr = "'" + scr + "'";}}

// set interval
var stfr = function(){ExpandElement(g, scr, f, x, cb);};
//var gidstr = "ExpandElement(" + g + "," + scr + ",'" + f + "'," + x + "," + cb + ")";
// var cd = setTimeout(gidstr, 50);
var cd = setTimeout(stfr, 50);
g.Stoppp = cd;
if(cb){if(typeof cb == "function"){
ExpEleCount++;}}
} // end fcn ExpandAndShow


function ExpandElement(gid, tf, f, x, cb){
// initialize
var eefr = function(){ExpandElement(gid, tf, f, x, cb);};
if(tf){if(typeof tf == "string"){tf = "'" + tf + "'";}}
var gidstr = "ExpandElement('" + gid + "'," + tf + ",'" + f + "'," + x + "," + cb + ")";
var rx = "/[^0-9]/g";
var y = x * 17;
scr = null;

// get reference to element to show
var g = ReturnObjRef(gid);
if(!g){
alert("Error: Page element (id = " + gid + ") cannot be displayed.");
return;}
var mh = g.style.maxHeight;

// get max height (remove units from css maxHeight value)
if(mh){
mh = mh.replace(rx, "");
mh = parseInt(mh);}
else {mh = 1;}

// increase max height
mh += x;
g.style.maxHeight = mh + "px";

// if maxHeight is not maxed out, call next increment
if(mh < y){
var cd = setTimeout(eefr, 50);
// var cd = setTimeout(gidstr, 50);
g.Stoppp = cd;

// if scroll is a number, scroll up the amount expanded
if(typeof tf == "number"){
scr = parseInt(tf);
if(!isNaN(scr)){window.scrollBy(0, scr);}}}

// if maxHeight reached, exit recursion
else{
g.style.maxHeight = "none";
if(g.Stoppp){clearTimeout(g.Stoppp);}

// scroll into view
if(tf){
if(tf === "'top'"){g.scrollIntoView(true);}
else if(tf === "'bottom'"){g.scrollIntoView(false);}}

// set focus
if(f){
var E = document.getElementById(f);
if(E){E.focus();}}

// call callback function
if(cb){if(typeof cb == "function"){
ExpEleCount--;
if(ExpEleCount == 0){cb();}}}}
} // end fcn ExpandElement


function FillDiscountChecks(s, p){
// s = string of checkbox id's that should be checked
// p = id of or object reference to element ancestor containing checkboxes
// split key string by commas
// To make sure that only the appropriate check boxes are altered, 
// this function relies on the fact that:
// (1) Only the parent (i.e. ancestor) container that is sent as the p argument is checked
// (2) only checkboxes are checked
// (3) only checkboxes that have id = value (and value is in csv argument) are altered.
var i = null;
var g = null;

// make sure p is an object reference
if(!p){return;}
else if(typeof p == "string"){
  p = document.getElementById(p);
  if(!p){return;}}
if(typeof p != "object"){return;}

// initialize all discount checkboxes to unchecked
var ip = p.getElementsByTagName("input");
if(ip){
for(i in ip){if(ip[i]){
if(ip[i].nodeName){if(ip[i].nodeName == "INPUT"){
if(ip[i].type){if(ip[i].type == "checkbox"){
if(ip[i].value){if(ip[i].id){if(ip[i].value = ip[i].id){
ip[i].checked = false;}}}}}}}}}}

// scan array of checkbox id's
if(s){
var a = s.split(",");
for(i in a){if(a[i]){
a[i] = JStrim(a[i]);
g = document.getElementById(a[i]);
if(g){

// make sure element is one of the discount checkboxes
if(g.nodeName){if(g.nodeName == "INPUT"){
if(g.type){if(g.type == "checkbox"){
if(g.value){if(g.value == a[i]){
g.checked = true;}}}}}}}}}}
} // end fcn FillDiscountChecks


function ReturnCheckedDiscounts(p){
// p = id of or object reference to element ancestor containing checkboxes
// Returns no. of checked + csv of ids from checked discounts;
// e.g., 3,reg,atg,comp (note comma after no.)
// if no. of checked entries is zero, returns just "0", not "0,".
var csv = "";
var n = 0;

// make sure p is an object reference
if(!p){return;}
p = ReturnObjRef(p);
if(typeof p != "object"){return;}

// initialize all discount checkboxes to unchecked
var ip = p.getElementsByTagName("input");
if(ip){
for(i in ip){if(ip[i]){
if(ip[i].nodeName){if(ip[i].nodeName == "INPUT"){
if(ip[i].type){if(ip[i].type == "checkbox"){
if(ip[i].value){if(ip[i].id){if(ip[i].value = ip[i].id){
if(ip[i].disabled == false){if(ip[i].checked == true){
n++;
csv += "," + ip[i].id;}}}}}}}}}}}}

// return formatted string
csv = n + csv;
return csv;
} // end fcn ReturnCheckedDiscounts


function FillElementWithText(ele, txt, sty){
// ele can be an id string or an object reference
// txt can be empty string to remove text only
// array of style nvp: arrayName[propName] = propValue
var k = null;
ele = ReturnObjRef(ele);
if(typeof ele != "object"){return;}

// resolve text
if(txt == null){txt = "";}
else if(typeof txt == "undefined"){txt = "";}
else if(typeof txt != "string"){txt = txt.toString();}

// remove any existing text
while(ele.firstChild){ele.removeChild(ele.firstChild);}

//create text node and append it
if(typeof txt == "string"){
var tn = document.createTextNode(txt);
if(tn){ele.appendChild(tn);}}

// change element style
if(sty instanceof Array){
for(k in sty){if(sty[k]){ele.style[k] = sty[k];}}}
} // end fcn FillElementWithText


function FillDropdownUtility(dd, A, ml){
/*
dd is object reference or id of dropdown to fill
A is array to text strings for each dd option.
text string format is: XY Z
X = 0 or 1 selected flag
Y = value
Z = option text.
Returns the number of options added to dropdown (exception: return 0 if only reg added)
*/
var j = null;
var s = null;
var ss = null;
var si = null;
var k = null;
var t = null;
var tn = null;
var o = null;

// get reference to dropdown
if(!dd){return 0;}
else if(typeof dd == "string"){
dd = document.getElementById(dd);
if(!dd){return 0;}}
if(typeof dd != "object"){return 0;}

// clear previous dd options
while(dd.firstChild){dd.removeChild(dd.firstChild);}

// scan array of option text (instanceof won't work across frames)
if(!(A.length)){return 0;}
var L = A.length;
for(var i = 0; i < L; i++){

// extract selected flag and value
if(A[i]){
s = A[i];
j = s.indexOf(" ");
ss = JStrim(s.substr(0, 1));
k = JStrim(s.substring(1, j));
t = JStrim(s.substr(j+1));

// create text node
if(!t){continue;}
if(ml){
var m = t.length;
if(m > ml){
t = t.substr(0, ml-3) + "...";}}

// add text node
tn = document.createTextNode(t);
if(!tn){continue;}

// create option node, set properties, and append
o = document.createElement("option");
if(!o){continue;}
o.value = k;
o.appendChild(tn);
dd.appendChild(o);}

// check for default option
if(ss){if(ss == 1){si = i;}}}

// select the default option
if(!si){dd.selectedIndex = 0;}
if(typeof si == "object"){dd.selectedIndex = 0;}
else if (typeof si == "undefined"){dd.selectedIndex = 0;}
else if(isNaN(parseInt(si))){dd.selectedIndex = 0;}
else {dd.selectedIndex = parseInt(si);}

// check for regular price only
if(L == 1){if(k.toLowerCase() == "reg"){return 0;}}

// return number of options added
if(dd.childNodes){return dd.childNodes.length;}
else {return 0;}
} // end fcn FillDropdown


function ReturnObjRef(gob){
if(typeof gob == "string"){gob = document.getElementById(gob);}
if(typeof gob == "object"){return gob;}
else {return null;}
} // end fcn ReturnObjRef


function GetCharCode(e){
var kp = null;

//Get reference to the event
if(e){E = e;}               //If W3C broswer sends reference automatically
else if(window.event){E = window.event;}  // If IE4+ browser
if(!E){return null;}

// get event type
var t = E.type
if(!t){return null;}
t = t.toLowerCase();
var i = t.indexOf("keypress");
if(i < 0){return null;}

//Get a reference to the Key that was pressed
if (E.charCode) {kp = E.charCode;}		 //Moz: have separate KeyCode and CharCode properties; use CharCode if available
else if (E.keyCode) {kp = E.keyCode;}  //IE: for onkeypress, KeyCode property contains charCode (returns keycode for onkeydown/up events)
else {return null;}

// return character code
return kp;
} // end fcn GetCharCode


function GetNumericPrice(p, strictTF){
// strictTF: The string sent ($p) must exactly
// equal the cleaned up input.  If not, 0 is returned.

// remove non-digits to get "pure price"
if(!p){return 0;}
var pp = p.replace(/[^0-9.]/g, "");

// check for uninterpretable cases
if(!pp){return 0;}
else if(strictTF){
if(pp != p){return 0;}}

//check for more than one decimal point
var i = pp.indexOf(".");
var j = pp.lastIndexOf(".");
if(i != j){return 0;}

// convert string to float
var f = parseFloat(pp);
if(isNaN(f)){return 0;}
return f;
} //end fcn GetNumericPrice


function EmailFormatValidTF(em){
// check that email comparison seems valid
if(typeof em != "string"){return false;}
n = em.match(/^[^@]+@[^@]+\.[^@]+[^.@]$/gi);
if(n == null){return false;}
return true;
} // end EmailFormatValid


function GetText(gob){
var t = null;
var c = null;
gob = ReturnObjRef(gob);
if(!gob){return "";}
if(gob.normalize){gob.normalize();}

// get node type
var nt = gob.nodeType

// process text node type
if(nt == 3){
var nv = gob.nodeValue;
return nv;}

// process element node type
else if(nt == 1){
var cn = gob.childNodes;

// scan child nodes
if(cn){
var L = cn.length;
for(var i = 0; i < L; i++){

// check for child node text
c = cn[i];
t = GetText(c);
if(t){return t;}}}}

// if all child nodes have been checked w/o text,
// return empty string
return null;
} // end fcn GetText 


function TimeoutMessage(p, divid, msg, dt, rc){
/*
p: parent div to hold message div
divid: id of message div, so styles can be set elsewhere
msg: the innerHTML for the message div
dt: the time interval before showing message
rc (boolean): remove children from parent before show msg div
*/
// create a div with the message
var dwm = document.createElement("div");
if(!dwm){return;}
dwm.innerHTML = msg;
dwm.id = divid;
dwm.style.marginLeft = "auto";
dwm.style.marginRight = "auto";
dwm.style.display = "none";

// reference parent
p = ReturnObjRef(p);
if(!p){
if(document.documentElement){p = document.documentElement;}
else if(document.body){p = document.body;}
if(!p){return;}}

// append div to parent
if(rc){while(p.firstChild){p.removeChild(p.firstChild);}}
p.appendChild(dwm);

// set timeout
var stf = function(){ShowHide(dwm, null, "block", 2, null, 200, null);}
var tid = setTimeout(stf, dt);
} // end fcn TimoutMessage


function ShowProblemCodes(){
var s = "Problem codes:\n"; 
s += "These codes show a mismatch between payment information sent to the Vortex by PayPal ";
s += "and information in the Vortex Reservations database.\n\n";
s += "A - The amount paid does not match to total ticket cost.\n";
s += "E - The business email address in the PayPal payment notification does not match the Vortex business email.\n";
s += "I - The transaction ID sent by PayPal does not match the value in the database.\n";
s += "N - The invoice number does not match the expected value.\n";
s += "Q - The number of reserved seats does not match the number of tickets purchased.\n";
s += "R - The PayPal transaction has been refunded.\n\n";
s += "OK - No problems were found.";
alert(s);
} // end fcn ShowProblemCodes

