/**********************************

SCAinteractive
Promotion Engine JS Library
Use: common js functions
Author: Paul Dunn
Comments: some of this code depends on the YUI, so YUI code segments must be preloaded

Version: 2.0
Modified: Jan-21/08

***********************************/

yui_dir = '/contests/html/xhtml_master/yui';
js_dir  = '/contests/html/xhtml_master/js';


/**********************************************************************/
// Maybe we shouldn't be doing it this way, this won't work in ie6 anyhow!

//require(yui_dir+'/build/yahoo-dom-event/yahoo-dom-event.js');
//require(yui_dir+'/build/connection/connection-min.js');
//require(yui_dir+'/build/container/container-min.js');
//require(yui_dir+'/build/button/button-min.js');

// included for backwards compatability, newer contests should avoid using functions
// from core.js as it will eventually be eliminated altogether
//require(js_dir+'/core.js'); 

//onEvent(window,'load',pageLoaders);
if (typeof(YAHOO)!="undefined") YAHOO.util.Event.addListener(window,'load',pageLoaders);
/**********************************************************************/


function analyze(obj) {
  var str = '';
  for ( var n in obj ) {
    str += '['+n+']: '+obj[n]+'\n';
  }
  return str;
}


// this function manages currently loaded js files 
// and dynamically loads new ones when necessary
function require(jsfile) {
	// first of all check if it already exists (by checking against a fully qualified url)
	req_parts = window.location.toString().split('/');
	req_url = req_parts[0]+'//'+req_parts[2]+jsfile;

	exists = false;
	jslist = '';
	scripts = document.getElementsByTagName('script');
	for (i=0;i<scripts.length;i++) {
		if ( scripts[i].src == req_url ) exists = true;
	}
	// if it doesn't exist, include it now
	if (!exists) {
		var s = document.createElement('script');
		s.src = req_url;
		s.dynamic = true;
		document.getElementsByTagName('head')[0].appendChild(s);
		onEvent(window,'load',updatejslist);
	}
}


function updatejslist() {
	// now update our debug info
	debugplug = document.getElementById("debug_plugins");
	if ( debugplug ) {
		debugplug.innerHTML = "";
		scripts = document.getElementsByTagName('script');
		for (i=0;i<scripts.length;i++) {
			jsrc = '';
			jsrc = scripts[i].src;
			if (!jsrc) jsrc = "<i>inline:</i> ";
			if (scripts[i].id) jsrc += ' "'+scripts[i].id+'" ';
			if (scripts[i].dynamic) jsrc = '<i>dynamic:</i> '+jsrc;
			debugplug.innerHTML += jsrc+"<br/>\n";
		}
	}
}

function plugin(id,url) {
	// loads a plugin from url and inserts its responseText into the DOM element identified by id
	plug_parts = window.location.toString().split('/');
	plug_url = plug_parts[0]+'//'+plug_parts[2]+'/'+plug_parts[3]+'/'+plug_parts[4]+'/'+url;

	var plug_handleSuccess = function(o) {
	  if (o.responseText !== undefined) {
		document.getElementById(o.argument).innerHTML = o.responseText;
		Table.init();
	  }
	}

	var plug_handleFailure = function(o) {
	  if (o.responseText !== undefined) {
		// just keep quiet
	  }
	}

	var plug_callback = {	
		success: plug_handleSuccess, 
		failure: plug_handleFailure,
		argument: id
	}

	function load_plugin() { 
		YAHOO.util.Connect.asyncRequest('GET',plug_url,plug_callback);
	}

	onEvent(window,'load',load_plugin);
}


function onEvent(object,event,func) {
	if ( object.addEventListener ) {
		object.addEventListener(event,func,false);
	}
	else {
		object.attachEvent('on'+event,func);  // IE
	}
}


/** Loading Function **/
function pageLoaders() {
	identifyUser();
	Table.init();
	Login.init();
}



/** Table Object **/
var Table = {
	init : function() {
      if (YAHOO && YAHOO.util && YAHOO.util.Dom) {
        var tables = YAHOO.util.Dom.getElementsByClassName('data');
        for (var t=0;t<tables.length;t++) {
          var rows = tables[t].getElementsByTagName('tr');
          for (var i=1,len=rows.length;i<len;i++) {
            if (i % 2 == 0) {
              YAHOO.util.Dom.removeClass(rows[i],'odd');
              YAHOO.util.Dom.addClass(rows[i],'even');
            }
            else {
              YAHOO.util.Dom.removeClass(rows[i],'even');
              YAHOO.util.Dom.addClass(rows[i],'odd');
            }
            YAHOO.util.Event.addListener(rows[i],'mouseover',Table.mouseover);
            YAHOO.util.Event.addListener(rows[i],'mouseout',Table.mouseout);
            cols = rows[i].getElementsByTagName('td');
            for (var j=0;j<cols.length;j++) {
              YAHOO.util.Dom.addClass(cols[j],'col'+j);
            }
          }
        }   
      }
	},
	mouseover : function(row) {
    YAHOO.util.Dom.addClass(this,'over');
	},
	mouseout : function(row) {
    YAHOO.util.Dom.removeClass(this,'over');
	}
/*
  stripe : function(table) {
    var rows = table.getElementsByTagName('tr');
    for (var i=1,len=rows.length;i<len;i++) {
      if (i % 2 == 0) rows[i].className = 'even';
      else            rows[i].className = 'odd';
    }
  }
*/
}


var Login = {
        username : Object,
        pwd : Object,
        init : function() {
                if(document.getElementById('login_form')) {
                        this.username = document.getElementById('username');
                        this.pwd = document.getElementById('password');
                        if (!this.username.value) this.username.style.background = '#fff url(/contests/html/master/img/login_username.gif) no-repeat left center;';
                        if (!this.pwd.value) this.pwd.style.background = '#fff url(/contests/html/master/img/login_password.gif) no-repeat left center;';
                        YAHOO.util.Event.addListener(this.username,'focus',this.focus);
                        YAHOO.util.Event.addListener(this.username,'blur',this.user_blur);
                        YAHOO.util.Event.addListener(this.pwd,'focus',this.focus);
                        YAHOO.util.Event.addListener(this.pwd,'blur',this.pwd_blur);
                }
        },
        focus : function() {
                this.style.background = '#fff';
        },
        user_blur : function() {
                if (!this.value) this.style.background = '#fff url(/contests/html/xhtml_master/img/login_username.gif) no-repeat bottom left;';
        },
        pwd_blur : function() {
                if (!this.value) this.style.background = '#fff url(/contests/html/xhtml_master/img/login_password.gif) no-repeat bottom left;';
        }
}



var HtmlEntities = {
    // expand as necessary
    subs : Array ( '&lt;','<',
                   '&gt;','>'
                  ),

    convert : function(str) {
        for (i=0;i<this.subs.length;i+=2) {
            expr = new RegExp(this.subs[i],'g');
            repl = this.subs[i+1];
            str = str.replace(expr,repl);
        }

        return str;
    }
}


var Alert = {
    show : function(msg,oncomplete) {
        var fallback = function() {
            // replace all html tags with nothingness
            msg = msg.replace(/<[^>]*>/g,'');
            // replace entities with appropriate symbols
            msg = HtmlEntities.convert(msg);
            alert(msg);
        }

        if ( typeof(YAHOO) != 'undefined' ) {
            if (YAHOO.util.Dom) {
                // Define various event handlers for Dialog
                var handleOK = function() {
                    this.hide();
                    if ( oncomplete ) oncomplete();
                    //delete this;
                }
                // Instantiate the Dialog
                var alertBox =
                    new YAHOO.widget.SimpleDialog("alertDialog",
                                                  { width: "350px",
                                                    fixedcenter: true,
                                                    modal: true,
                                                    visible: true,
                                                    draggable: true,
                                                    close: true,
                                                    text: msg,
                                                    icon: YAHOO.widget.SimpleDialog.ICON_WARN,
                                                    constraintoviewport: true,
                                                    buttons: [
                                                               { text:"OK",  handler:handleOK, isDefault:true }
                                                             ]
                                                    } );
                alertBox.setHeader("Alert!");
                // Render the Dialog
                alertBox.render(document.body);
                return;
            }
       }
       fallback();
    }
}



// attach some trim functions as part of the String object
String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/g,"");
}
String.prototype.ltrim = function() {
	return this.replace(/^\s+/,"");
}
String.prototype.rtrim = function() {
	return this.replace(/\s+$/,"");
}

function setCookie(key,val,days,path,host) {
	today = new Date();
	expires = new Date();
	
	toset = key+"="+escape(val);
	if ( days ) {
		expires.setTime(today.getTime() + 3600000*24*days);
		toset += "; expires="+expires.toGMTString();
	}
	if ( path ) {
		toset += "; path="+path;
	}
	if ( host ) {
		toset += "; host="+host;
	}
	document.cookie = toset;
}

function getCookie(key) {
	toget = document.cookie.split(";");
	for (i=0;i<toget.length;i++) {
		keyval = toget[i].split("=");
		if (key==keyval[0].trim()) return unescape(keyval[1]);
	}
	return null;
}

function getUinfo(key) {
	Ucookie = getCookie("U");
	if ( Ucookie!=null ) {
		U = Ucookie.split("|");
		for (i=0;i<U.length;i+=2) {
			if (key==U[i]) return U[i+1];
		}
	}
  /*
	else { // check the old CDE paths for existence of a cookie
		urlparts = window.location.toString().split("/");
		sUrl = "/cgi-bin/"+urlparts[3]+"-"+urlparts[4]+"/cU.cgi?delete=1";
		YAHOO.util.Connect.asyncRequest('GET',sUrl,uCookieCallback,null);
	}
  */
	return null;
}

function uCookieResponse(o) {
    urlparts = window.location.toString().split("/");
    U = unescape(o.responseText);
    //alert("retrieved old cookie: "+U); //************************************************
    //if ( !U ) U = "not_present";
    host = "."+urlparts[2];
    path = "/"+urlparts[3];
    if (U) {
      setCookie("U",U,3*366,path,host);
      identifyUser();
    }
}

function uCookieIgnore(o) {
}

uCookieCallback = {
	success: uCookieResponse,
	failure: uCookieIgnore
}

function identifyUser() {
	username = getUinfo("username");
	udiv = document.getElementById("userinfo");
	if ( udiv && username ) {
		udiv.innerHTML = username;
	}
}
















































function GetValidationFormMessages(form,forminfo) {

  var one_at_a_time = false;
  if ( arguments.length>2 ) one_at_a_time = arguments[2];

	/*
  2008-02-28   Paul R Dunn

  will return a string of concatenated error messages or 0 for 'no problems'


  set second parameter to true to only report one invalid field at a time
  the second element in the returned array will be the invalid fieldname 
  or set the second parameter to flase (or omit it) to report all messages at once


	Currently (2008-02-27) the ZendValidate functions are:
	(see also: http://framework.zend.com/manual/en/zend.validate.set.html for detailed explanations)

    39.2.1.    Alnum        ()                                   must be alphabetic and digits only
    39.2.2.    Alpha        ()                                   must be alphabetic only
    39.2.3.    Barcode      (??)                               
    39.2.4.    Between      ($min, $max, $inclusive = true)      must be between $min and $max
    39.2.5.    Ccnum        ()                                   must match Luhn Algorithm for credit card numbers
    39.2.6.    Date         ()                                   must be a valid date in the form YYYY-MM-DD 
    39.2.7.    Digits       ()                                   must be digits only    
    39.2.8.    EmailAddress ($allow = Zend_Validate_Hostname::ALLOW_DNS, $validateMx = false)
    39.2.9.    Float        ()                                   must be a floating point number 
    39.2.10.   GreaterThan  ($min)                               must be larger than $min
    39.2.11.   Hex          ()                                   must only contain 0-9 and a-f or A-F  
    39.2.12.   Hostname     ($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true) 
    39.2.13.   InArray      (array $haystack, $strict = false)   must be one of the array values
    39.2.14.   Int          ()                                   must be an integer value
    39.2.15.   Ip           ()                                   must be a valid ip address
    39.2.16.   LessThan     ($max)                               must be less than $max
    39.2.17.   NotEmpty     (??)                                    
    39.2.18.   Regex        ($pattern)                           must match the regex pattern
    39.2.19.   StringLength ($min = 0, $max = null)              must be at least $min and at most $max chars in length

    Plus the PE custom validation function:
	           Profanity    ()                                   must not contain any profanities (plain or disguised)


    Notes:
	  We don't need to be as strict as the php ZendValidator, since after form submission the PE engine
	  will do a final validation on all relevant fields. But if we can catch as many problems here as possible,
      then we eliminate the need for unneccessary data transmissions between client and server.
	  For example, we should allow the PE engine to validate Profanity, rather than javascripting it.
	*/

  function build_message(val,msg) {
  	return msg.replace('%value%',val)
  }

  function in_array(test,varray) {
    for (var i=0;i<varray.length;i++) {
      if ( test==varray[i] ) return 1;
    }
    return 0;
  }

  function filter_digits(val) {
    var digits = "0123456789".split("");
    val = val.toString();
    var rval = '';
    for (var i=0;i<val.length;i++) {
      if ( in_array(val.charAt(i),digits) ) rval += val.charAt(i);
    }
    return rval;
  }

  ////////////////////////////////////////////////////////////
  // Validators (mimic behaviour of the ZendValidators in PHP)

  function vAlnum() {
    var value = unescape(arguments[0].toString());
    var regex = /^[a-zA-Z0-9]*$/;
    if ( !regex.test(value) ) {
      return "'"+value+"' has not only alphabetic and digit characters";
    }
    return 0;
  }

  function vAlpha() {
    var value = unescape(arguments[0].toString());
    var regex = /^[a-zA-Z]*$/;
    if ( !regex.test(value) ) {
      return "'"+value+"' has not only alphabetic characters";
    }
    return 0;
  }

  function vBarcode() {
    // Not Yet Incorporated
    // we could just let the PHP server handle this
    var value = unescape(arguments[0].toString());
    return 0;
  }

  function vBetween() {
    var value = unescape(arguments[0].toString());
    var min = null;
    var max = null;
    var inclusive = null;
    if ( arguments.length>1 ) min = arguments[1];
    if ( arguments.length>2 ) max = arguments[2];
    if ( arguments.length>3 ) inclusive = arguments[3];
    if (inclusive) {
      if ( min>value || value>max ) {
        return "'"+value+"' is not between '"+min+"' and '"+max+"', inclusively";
      }
    }
    else {
      if ( min>=value || value>=max ) {
        return "'"+value+"' is not strictly between '"+min+"' and '"+max+"'";
      }
    }
    return 0;
  }

  function vCcnum() {
    var value = unescape(arguments[0].toString());
    var filtval = filter_digits(value);

    var length = filtval.length;
    if ( length<13 || length>19 ) {
      return "'"+value+"' must contain between 13 and 19 digits";
    }
    var sum = 0;
    var weight = 2;
    for (var i=length-2;i>=0;i--) {
      digit = weight * filtval.charAt(i);
      sum += Math.floor(digit/10) + digit%10;
      weight = weight % 2 + 1;
    }
    if ( (10 - sum % 10) % 10 != filtval.charAt(length-1) ) {
      return "Luhn algorithm (mod-10 checksum) failed on '"+filtval+"'";
    }
    return 0;
  }

  function vDate() {
    var value = unescape(arguments[0].toString());
    var regex = /^\d{4}-\d{2}-\d{2}$/;
    if ( ! regex.test(value) ) {
      return "'"+value+"' is not of the format YYYY-MM-DD";
    }
    //         X   J  F  M  A  M  J  J  A  S  O  N  D
    days = [ [ 0, 31,28,31,30,31,30,31,31,30,31,30,31 ],      // non-leap years
             [ 0, 31,29,31,30,31,30,31,31,30,31,30,31 ] ];    // leap years
    parts = value.split("-");
    year = parseInt(parts[0],10);
    month = parseInt(parts[1],10);
    date = parseInt(parts[2],10);
    leap = 0;
    invalid = 0; // assume it's valid until we find a problem
    if ( year%1000==0 || ( year%4==0 && year%100!=0 ) ) leap = 1;
    if ( month<1 || month>12 ) invalid = 1;
    if ( date<1 || date>days[leap][month] ) invalid = 1;
    if ( invalid ) {
      return "'"+value+"' does not appear to be a valid date";
    }

    return 0;
  }

  function vDigits() {
    var value = unescape(arguments[0].toString());
    var regex = /^[0-9]*$/;
    if ( !regex.test(value) ) {
      return "'"+value+"' contains not only digit characters";
    }
    return 0;
  }

  function vEmailAddress() {
    var value = unescape(arguments[0].toString());
    var regex = /^.+@[^@]+$/;
    if ( !regex.test(value) ) {
      return "'"+value+"' is not a valid email address in the basic format local-part@hostname";
    }
    // allow Zend to do do the more complicated checking
    return 0;
  }

  function vFloat() {
    var value = unescape(arguments[0].toString());
    if ( value != parseFloat(value) ) {
      return "'"+value+"' does not appear to be a float";
    }
    return 0;
  }

  function vGreaterThan() {
    var value = unescape(arguments[0].toString());
    var min = 0;
    if ( arguments.length>1 ) min = arguments[1];
    if ( min >= value ) {
      return "'"+value+"' is not greater than '"+min+"'";
    }
    return 0;
  }

  function vHex() {
    var value = unescape(arguments[0].toString());
    var regex = /^[0-9a-fA-F]$/;
    if ( !regex.test(value) ) {
      return "'"+value+"' has not only hexadecimal digit characters";
    }
    return 0;
  }

  function vHostname() {
    // allow ZendValidate to do the more complicated checking    
    var value = unescape(arguments[0].toString());
    var parts = value.split('.');
    if ( parts.length>1 && value.length>=4 && value.length<=254 ) {
      return 0;
    }
    return "'"+value+"' does not match expected structure for a DNS hostname";
  }

  function vInArray() {
    // we will pass the array in as a comma delimited string
    var value = unescape(arguments[0].toString());
    var haystack = [ ];
    var strict = false; // strict checking not avaialble in javascript
    if ( arguments.length>1 ) haystack = arguments[1].split(',');
    if ( !in_array(value,haystack) ) {
      return "'"+value+"' was not found in the haystack";
    }
    return 0;
  }

  function vInt() {
    var value = unescape(arguments[0].toString());
    if ( value != parseInt(value) ) {
      return "'"+value+"' does not appear to be an integer";
    }
    return 0;
  }

  function vIp() {
    var invalid = 0;
    var value = unescape(arguments[0].toString());
    var parts = value.split('.');
    if ( parts.length!=4 ) invalid = 1;
    for (var i=0;i<4;i++) {
      if ( parts[i]<0 || parts[i]>255 ) invalid = 1;
    }
    if ( invalid ) {
      return "'"+value+"' does not appear to be a valid IP address";
    }
    return 0;
  }

  function vLessThan() {
    var value = unescape(arguments[0].toString());
    var max = 0;
    if ( arguments.length>1 ) max = arguments[1];
    if ( max <= value ) {
      return "'"+value+"' is not less than '"+max+"'";
    }
    return 0;
  }

  function vNotEmpty() {
    var value = unescape(arguments[0].toString());
    if ( value.length == 0 ) {
      return "'"+value+"' appears to be empty";
    }
    return 0;
  }

  function vRegex() {
    var value = unescape(arguments[0].toString());
    var regex = /^$/;
    if ( arguments.length>1 ) {
      try { regex = new RegExp(arguments[1]); }
      catch(err) { alert(err.description);    }
    }
    if ( !regex.test(value) ) {
      return "'"+value+"' does not match against pattern '"+regex+"'";
    }
    return 0;
  }

  function vStringLength() {
    var value = unescape(arguments[0].toString());
    var min = 0;
    var max = null;
    if ( arguments.length>1 ) min = arguments[1];
    if ( arguments.length>2 ) max = arguments[2];
    if ( value.length<min ) return "'"+value+"' is less than "+min+" characters long";
    if ( max!=null && value.length>max ) return "'"+value+"' is greater than "+max+" characters long";
    return 0;
  }

  // end of Validators 
  ////////////////////////////////////////////////////////////

  function getFormValue(fieldname) {
    var val = '';
    // the formfield should exist
    if ( eval("form."+fieldname) ) {
      // if it is a checkbox, see if it is checked
      if ( eval("form."+fieldname+".type")=='checkbox' ) {
        if ( eval("form."+fieldname+".checked")) {
          val = eval("form."+fieldname+".value");
        }
      }
      else {
        val = eval("form."+fieldname+".value");
      }
    }
    return val;
  }

  function createFormField(name,value) {
    if ( eval('form.'+name) ) {
      // element exists, just set its value
      eval("form."+name+".value = '"+value+"'");
    }
    else {
      // create an element
      formelem = document.createElement('input');
      formelem.setAttribute('type','hidden');
      formelem.setAttribute('name',name);
      formelem.setAttribute('id',name); // because IE is stupid and won't recognize form.name_element unless id is set to match nname
      formelem.setAttribute('value',value);
      form.appendChild(formelem);
    }
  }

  ///////////////////
  // BEGIN PROCEDURAL

  var messages = [ ];
  var fields = [ ];

  // do all constructors and sameas fields first
  for (var p in forminfo) {

    // build all compound fields from constructors
    if ( typeof(forminfo[p]['sameas']) == 'string' ) {
      var fieldname = p;
      var sameas = forminfo[p]['sameas'];
      var value = eval('form.'+sameas+'.value');
      createFormField(fieldname,value);
    }
    if ( typeof(forminfo[p]['constructor']) == 'string' ) {
      var fieldname = p;

      // decompose into constr where 
      // every even element (0 based) is a literal string and  
      // every odd element is a form var to substitute
      var constr = forminfo[p]['constructor'].split('%');
      var cvalue = '';
      for (var j=0;j<constr.length;j++) {
        if (j%2) { // odd
          cvalue += eval("form."+constr[j]+".value");
        }
        else { // even
          cvalue += constr[j];
        }
      }
      //isIE  = (navigator.appName.indexOf("Microsoft") != -1) ? true : false;
      createFormField(fieldname,cvalue);
    }
  }

  // then do all validators
  for (var p in forminfo) {

    if ( typeof(forminfo[p]['validator']) == 'string' ) {
      var fieldname = p;//elems[i].name.substr(0,elems[i].name.length-'_validator'.length);
      var value = getFormValue(fieldname);
      var validators = forminfo[p]['validator'].split(';');
      var nerrors = 0;
      // go through each validator (for this element) in turn
      for (var j=0;j<validators.length;j++) {
        parts = validators[j].split('(');
        if ( parts[1]!=')' ) parts[1] = ','+parts[1];
        var vcode = "v"+parts[0]+"(\""+escape(value)+"\""+parts[1];
        var err = eval(vcode);
        if ( err ) {
          nerrors++;
          // keep fields synchronized with messages because there might be multiple messages per field
          messages.push(err);
          fields.push(fieldname);
        }
      }
      // if we have defined a custom error for this element then 
      // pop the pre generated ones and replace them
      if ( nerrors>0 && typeof(forminfo[p]['message'])=='string' ) {
        for (var j=0;j<nerrors;j++) {
          // keep fields synchronized with messages because there might be multiple messages per field
          messages.pop();
          fields.pop();
        }
        var custom_msg = build_message( value, forminfo[p]['message'] );
        // keep fields synchronized with messages because there might be multiple messages per field
        messages.push(custom_msg);
        fields.push(fieldname);
      }

      // if we've found an invalid field and one_at_time flag is set, then we have 
      // enough info to end the function, of course its still possible that we could 
      // have multiple messages for a single invalid field (when there are multiple validators)
      if ( messages.length>0 && one_at_a_time ) {
        return [ messages, fields ];
      }

    }
  }

  // now return the array of error messages
  // an empty array signifies success
  return [ messages, fields ];
}


