// Fix issues (background image and nodeName tests) in IE.
(function() {
  if (YAHOO.env.ua.ie) {
    // Fix the background image flicker in IE6 on mouse rollovers of links
    try {
      document.execCommand("BackgroundImageCache", false, true);
    } catch(err) {}
    /*
    var env = YAHOO.env,
        Event = YAHOO.util.Event,
        Dom = YAHOO.util.Dom;

    // Fix YAHOO.util.Connect._hasSubmitListener in IE with VML
    var fixHasSubmit = function() {
      if (env.getVersion("connection")) {
        var listeners = Event.getListeners(document, 'click'),
            oListen;
        for (var i = 0, l = listeners.length; i < l; i++) {
          oListen = listeners[i];
          if (YAHOO.lang.isUndefined(oListen.obj)) {
            var oldFn = oListen.fn;
            Event.removeListener(document, 'click', oldFn);
            Event.addListener(document, 'click', function() {
              try { oldFn.apply(document, arguments); } catch(err) {}
            }, {});
          }
        }
        return true;
      }
      else {
        return false;
      }
    };

    if (!fixHasSubmit()) {
      env.listeners.push(function(info) {
        if (info.name == "connection") {
          fixHasSubmit();
        }
      });
    }

    // Fix YAHOO.util.Dom.getElementsBy so that any code that tests by nodeName
    // or tagName won't inexplicably break when testing for nodes.
    var oldGetElementsBy = Dom.getElementsBy;

    // Wrap a method in a try-catch block 
    var wrapMethod = function(method) {
      return function() {
        try {
          return method.apply(this, arguments);
        } catch (error) {
          return false;
        }
      };
    };

    Dom.getElementsBy = function() {
      arguments[0] = wrapMethod(arguments[0]);
      return oldGetElementsBy.apply(this, arguments);
    };
  */
  }

})();

function olderBrowserTest() {
  var Cookie = YAHOO.util.Cookie,
      ua = YAHOO.env.ua,

      // The cookie name for the older browser test.
      olderBrowser = "ob";
  if (Cookie && ( Cookie.get(olderBrowser) === null ||
                  Cookie.get(olderBrowser) !== "/math/practice/") ) {
    if ( (ua.ie && ua.ie < 6) ||
         (ua.gecko && ua.gecko < 1.8) ||
         (ua.webkit && ua.webkit < 522) ||
         (ua.opera && ua.opera < 9) 
        ) {

      Cookie.set(olderBrowser, window.location.pathname, {
        path: "/"
      });

      window.location = "/math/olderbrowser";
    }
  }
}

// Helper function used by addLoadEvent to ensure the canvas items are inited
function initCanvasTags(func) {
  var fString = func.toString();
  var startOfQGen = fString.indexOf("drawqgencanvas");
  if (startOfQGen != -1) {
    var cName = fString.substring(
        startOfQGen + "draw".length,
        fString.indexOf("()"));
    YAHOO.util.Event.onContentReady(cName, function() {
      if (window['G_vmlCanvasManager'] && !this['getContext'])
        G_vmlCanvasManager.initElement(this);
    });
    return cName;
  }
  return null;
}

// Function used by canvas tags to draw themselves
function addLoadEvent(func) {
  var cName = initCanvasTags(func);
  if (cName != null) {
    YAHOO.util.Event.onContentReady(cName, func);
  }
  else {
    func();
  }
}

function loadContentAndExecuteScripts(rawContent, oDiv, onComplete, oScratch) {
  var scopedObject = {};
  scopedObject.embeddedScripts = [];
  scopedObject.oDiv = oDiv;
  scopedObject.onComplete = onComplete;
  scopedObject.oScratch = oScratch;
  scopedObject.isComplete = false;

  var _t = rawContent;
  while (_t.indexOf("<script") != -1) {
    var realStart = _t.indexOf("<script");
    var scriptElementEnd = _t.indexOf(">", realStart);
    var end = _t.indexOf("</script>", (realStart)) + "</script>".length;

    // now remove the script body
    var scriptBodyStart = scriptElementEnd + 1;
    var sBody = _t.substring(scriptBodyStart, end - "</script>".length);
    // Fix bug with style.width or style.height not specifying px
    sBody = sBody.replace(/\b(width|height) = ([0-9.]+)\b/g, "$1 = '$2px'");
    if (sBody.length > 0) {
      scopedObject.embeddedScripts.push(sBody);
    }
    //remove script
    _t = _t.substring(0, realStart) + _t.substring(end, _t.length);
  }
  scopedObject.bodyText = _t;

  function finishLoadingContents(o, fromTimeout, ignoreScripts) {
    // If the object says it's already loaded it's contents, just move on.
    if (o.isComplete) {
      return;
    }

    var bdDiv = o['oScratch'];
    if (bdDiv == null || fromTimeout) bdDiv = o.oDiv;
    bdDiv.innerHTML = o.bodyText;

    // evaluate the embedded javascripts in the order they were added
    for (var loop = 0;
         !ignoreScripts && o.embeddedScripts && loop < o.embeddedScripts.length;
         loop++) {
      var script = o.embeddedScripts[loop];
      eval(script);
    }

    // If we're from the timeout, just fire the onComplete at this point.
    if (fromTimeout) {
      if (o['onComplete']) o.onComplete();
      o.isComplete = true;
      return;
    }

    YAHOO.util.Event.onContentReady([o.oDiv], function(obj) {
      var Dom = YAHOO.util.Dom;
      if (obj.oScratch != null) {
        var child = Dom.getFirstChild(o.oDiv);
        if (child) obj.oDiv.replaceChild(Dom.getFirstChild(obj.oScratch), child);
        else obj.oDiv.appendChild(Dom.getFirstChild(obj.oScratch)); 
      }
      if (obj['onComplete']) obj.onComplete();
      obj.isComplete = true;
    }, o);
  }

  if (_t.indexOf("<img") != -1) {
    preLoadBodyTextImages(_t, finishLoadingContents, scopedObject);
  }
  else {
    finishLoadingContents(scopedObject);
  }

  // Set a couple of timeouts to force finishing the loading of the contents.

  // First timeout just forces it to finish, ignoring the scratch area.
  setTimeout(function() { finishLoadingContents(scopedObject, true); }, 3000);

  // Second timeout forces it to finish, ignoring the scratch area and the scripts.
  setTimeout(function() { finishLoadingContents(scopedObject, true, true); }, 7000);
}

function getImgSrcFromHTML(text) {
  var aMatch = text.match(/<\s*img [^\>]*src\s*=\s*[\""\']?([^\""\'\s>]*)/i);
  return (aMatch ? aMatch[1] : null);
}

function preLoadBodyTextImages(_t, func, obj) {
  var images = {};
  var matches = _t.match(/<img src=("|')(.*?)\1( |>|\/>)/g);
  for (var indexM = 0; matches && indexM < matches.length; indexM++) {
    var imgSrc = getImgSrcFromHTML(matches[indexM]);
    images[imgSrc] = new Image();
    images[imgSrc].src = imgSrc;
  }

  var clEvent = new YAHOO.util.CustomEvent("checkLoadedEvent", this, false, YAHOO.util.CustomEvent.FLAT);
  var notloaded = [];
  var timeout = setTimeout(function() {
    clEvent.fire("timeout");
  }, 1000);
  clEvent.subscribe(function(whichImg, o) {
    for (var i = 0; i < o.nl.length; i++) {
      if (o.nl[i].complete || o.nl[i].src == whichImg) {
        o.nl.splice(i, 1);
      }
    }
    if (o.nl.length == 0 || whichImg == "timeout") {
      o.fn(o.obj);
      clEvent.unsubscribeAll();
      clearTimeout(o.timeout)
    }
  }, {nl: notloaded, timeout: timeout, fn: func, obj: obj});


  for (var tempImgSrc in images) {
    var tempImg = images[tempImgSrc];
    if (!tempImg.complete) {
      notloaded.push(tempImg);
      var mySrc = tempImg.src;
      tempImg.onload = function () {
        clEvent.fire(mySrc);
      }
    }
  }
  clEvent.fire(null);
}

// ---------------------------------------------------------------------
// Global custom events are handled through YAHOO.ixl.topic.
// Only create the event provider if it hasn't been created yet.
// ---------------------------------------------------------------------
if (! (YAHOO.ixl && YAHOO.ixl.topic) ) {
  var IXLTopic = function() { };
  YAHOO.lang.extend(IXLTopic, YAHOO.util.EventProvider);
  YAHOO.namespace("ixl");
  YAHOO.ixl.topic = new IXLTopic();
}

// ---------------------------------------------------------------------
// Helper function to open the help links in a new popup window
// ---------------------------------------------------------------------
var win;
function openHelpTopic(link, wname) {
  wname = wname || "help_body";
  win = window.open(link.href,wname,"height=600,width=700,status=yes,toolbar=yes,scrollbars=yes,resizable=yes,menubar=no,location=no");
  win.focus();
}

function openHelpMain(link) {
  openHelpTopic(link, "IXL_Help");
}

function getLocationHash() {
  var i, href;
  href = window.location.href;
  i = href.indexOf("#");
  return i >= 0 ? href.substr(i + 1) : null;
}

/**
 * extractReplaceQuery - find, return, replace value of a specific variable
 * in a query string
 *
 * @input
 *
 * - targetStr: the variable of which you want to find or replace the value.
 * - objOrStr: string or DOM object with 'href' attribute (ex. link or location)
 * - newValue: if false, return target variable value, else replace with newValue
 *
 * @return
 * - value of variable spcificed by targetStr or updated string of objOrStr
 * - if objOrStr.href exists, it will be updated with newValue, if newValue !false
 * 
 * @note 
 * If a question mark is present, '?', query string starts after '?'.
 *
 * @usage
 * testObj.herf =  'http://www.yahoo.com?doc=1234&rand=2233'
 * Query string would be 'doc=1234&rand=2233'
 *
 * extractReplaceQuery('doc', testObj, '8888')
 * will change testObj.href to 'http://www.yahoo.com?doc=8888&rand=2233' 
 * will return new testObj.href string
 * 
 * extractReplaceQuery('doc', 'doc=1234&rand=2233', false)
 * will return '1234'
 *
 **/
function extractReplaceQuery(targetStr, objOrStr, newValue){

  // validate input
  if (targetStr === '' || targetStr === null || objOrStr === 'number'
    || objOrStr === null || objOrStr === 'function' || objOrStr === 'boolean' 
    || typeof newValue === 'object' || typeof newValue === 'function'){
    return false;
  }

  var fullStr = '', workingStr = '';

  // prepare input, take whole string or string after first '?'
  if (typeof objOrStr === 'object'){
    fullStr = objOrStr.href;
  }
  else {
    fullStr = objOrStr;
  }
 
  var questionDel = '?'; 
  var firstDel = '&';
  var secondDel = '=';
  var newStr = '';

  // separate the string by '?'
  var dataArr = fullStr.split(questionDel);
  workingStr = dataArr[0];
  if (dataArr.length > 1){
    // has '?', taking first string after '?'
    workingStr = dataArr[1];
    newStr = dataArr[0] + questionDel;
  } // if dataArr.length > 1
  
  if (workingStr.length === 0){
    // there is nothing to work on, return original string
    return fullStr;
  }

  // take the working string, the portion we are interested in,
  // look for '&" as delimiter
  var indexValueArr = workingStr.split(firstDel);
  for (var i=0; i<indexValueArr.length; i++){
    if (i>0){
      // looping second time, add a delimiter
      newStr = newStr + firstDel;
    } // if i>0

    // for each nameValue pair, split them by '=' to get name and value
    var nameValue = indexValueArr[i].split(secondDel);
    newStr = newStr + nameValue[0];
    if (nameValue.length > 1){
      // name value pair has value available
      if (nameValue[0] === targetStr){
        // if we are interested in this name value pair
        if (newValue){
          // newValue has value, add it to new string
          newStr = newStr + secondDel + newValue;
        }
        else {
          // newValue is false, return the value only
          return nameValue[1];
        }
      }
      else {
        newStr = newStr + secondDel + nameValue[1];
      } // if nameValue[0] === targetStr
    } // if nameValue.length > 1
  } // for

  if (dataArr.length > 2){
    // there are more than one '?', this function will only process first
    // query string, so we attach the string after second '?' back
    for (var j=2; j<dataArr.length; j++){
      newStr = newStr + questionDel + dataArr[j];
    }
  } // if dataArr.length > 2
  if (typeof objOrStr === 'object' && objOrStr.href !== ''){
    objOrStr.href = newStr;
  }
  return newStr; 
};

// ---------------------------------------------------------------------
// Number formatter
// ---------------------------------------------------------------------
/*
Author: Robert Hashemian
http://www.hashemian.com/

You can use this code in any manner so long as the author's
name, Web address and this disclaimer is kept intact.
********************************************************
Usage Sample:
FormatNumberBy3("1234512345.12345", ".", ",");
*/

// function to format a number with separators. returns formatted number.
// num - the number to be formatted
// decpoint - the decimal point character. if skipped, "." is used
// sep - the separator character. if skipped, "," is used
function FormatNumberBy3(num, decpoint, sep) {
  // No formatting necessary
  if (num < 1000 && arguments.length == 1) return num.toString();

  // check for missing parameters and use defaults if so
  if (arguments.length == 2) {
    sep = ",";
  }
  if (arguments.length == 1) {
    sep = ",";
    decpoint = ".";
  }
  // need a string for operations
  num = num.toString();
  // separate the whole number and the fraction if possible
  var a = num.split(decpoint);
  var x = a[0]; // decimal
  var y = a[1]; // fraction
  var z = "";


  if (typeof(x) != "undefined") {
    // reverse the digits. regexp works from left to right.
    for (var i=x.length-1;i>=0;i--)
      z += x.charAt(i);
    // add seperators. but undo the trailing one, if there
    z = z.replace(/(\d{3})/g, "$1" + sep);
    if (z.slice(-sep.length) == sep)
      z = z.slice(0, -sep.length);
    x = "";
    // reverse again to get back the number
    for (var i=z.length-1;i>=0;i--)
      x += z.charAt(i);
    // add the fraction back in, if it was there
    if (typeof(y) != "undefined" && y.length > 0)
      x += decpoint + y;
  }
  return x;
}


// Functions to test if a form has been modified
// ===================================================================
// Author: Matt Kruse <matt@mattkruse.com>
// WWW: http://www.mattkruse.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download. 
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================
function LTrim(str){if(str==null){return null;}for(var i=0;str.charAt(i)==" ";i++);return str.substring(i,str.length);}
function RTrim(str){if(str==null){return null;}for(var i=str.length-1;str.charAt(i)==" ";i--);return str.substring(0,i+1);}
function Trim(str){return LTrim(RTrim(str));}
function LTrimAll(str){if(str==null){return str;}for(var i=0;str.charAt(i)==" " || str.charAt(i)=="\n" || str.charAt(i)=="\t";i++);return str.substring(i,str.length);}
function RTrimAll(str){if(str==null){return str;}for(var i=str.length-1;str.charAt(i)==" " || str.charAt(i)=="\n" || str.charAt(i)=="\t";i--);return str.substring(0,i+1);}
function TrimAll(str){return LTrimAll(RTrimAll(str));}
function isNull(val){return(val==null);}
function isBlank(val){if(val==null){return true;}for(var i=0;i<val.length;i++){if((val.charAt(i)!=' ')&&(val.charAt(i)!="\t")&&(val.charAt(i)!="\n")&&(val.charAt(i)!="\r")){return false;}}return true;}
function isInteger(val){if(isBlank(val)){return false;}for(var i=0;i<val.length;i++){if(!isDigit(val.charAt(i))){return false;}}return true;}
function isNumeric(val){return(parseFloat(val,10)==(val*1));}
function isArray(obj){return(typeof(obj.length)=="undefined")?false:true;}
function isDigit(num){if(num.length>1){return false;}var string="1234567890";if(string.indexOf(num)!=-1){return true;}return false;}
function setNullIfBlank(obj){if(isBlank(obj.value)){obj.value="";}}
function setFieldsToUpperCase(){for(var i=0;i<arguments.length;i++){arguments[i].value = arguments[i].value.toUpperCase();}}
function disallowBlank(obj){var msg=(arguments.length>1)?arguments[1]:"";var dofocus=(arguments.length>2)?arguments[2]:false;if(isBlank(getInputValue(obj))){if(!isBlank(msg)){alert(msg);}if(dofocus){if(isArray(obj) &&(typeof(obj.type)=="undefined")){obj=obj[0];}if(obj.type=="text"||obj.type=="textarea"||obj.type=="password"){obj.select();}obj.focus();}return true;}return false;}
function disallowModify(obj){var msg=(arguments.length>1)?arguments[1]:"";var dofocus=(arguments.length>2)?arguments[2]:false;if(getInputValue(obj)!=getInputDefaultValue(obj)){if(!isBlank(msg)){alert(msg);}if(dofocus){if(isArray(obj) &&(typeof(obj.type)=="undefined")){obj=obj[0];}if(obj.type=="text"||obj.type=="textarea"||obj.type=="password"){obj.select();}obj.focus();}setInputValue(obj,getInputDefaultValue(obj));return true;}return false;}
function commifyArray(obj,delimiter){if(typeof(delimiter)=="undefined" || delimiter==null){delimiter = ",";}var s="";if(obj==null||obj.length<=0){return s;}for(var i=0;i<obj.length;i++){s=s+((s=="")?"":delimiter)+obj[i].toString();}return s;}
function getSingleInputValue(obj,use_default,delimiter){switch(obj.type){case 'radio': case 'checkbox': return(((use_default)?obj.defaultChecked:obj.checked)?obj.value:null);case 'text': case 'hidden': case 'textarea': return(use_default)?obj.defaultValue:obj.value;case 'password': return((use_default)?null:obj.value);case 'select-one':
if(obj.options==null){return null;}if(use_default){var o=obj.options;for(var i=0;i<o.length;i++){if(o[i].defaultSelected){return o[i].value;}}return o[0].value;}if(obj.selectedIndex<0){return null;}return(obj.options.length>0)?obj.options[obj.selectedIndex].value:null;case 'select-multiple':
if(obj.options==null){return null;}var values=new Array();for(var i=0;i<obj.options.length;i++){if((use_default&&obj.options[i].defaultSelected)||(!use_default&&obj.options[i].selected)){values[values.length]=obj.options[i].value;}}return(values.length==0)?null:commifyArray(values,delimiter);}/*alert("FATAL ERROR: Field type "+obj.type+" is not supported for this function");*/return null;}
function getSingleInputText(obj,use_default,delimiter){switch(obj.type){case 'radio': case 'checkbox': 	return "";case 'text': case 'hidden': case 'textarea': return(use_default)?obj.defaultValue:obj.value;case 'password': return((use_default)?null:obj.value);case 'select-one':
if(obj.options==null){return null;}if(use_default){var o=obj.options;for(var i=0;i<o.length;i++){if(o[i].defaultSelected){return o[i].text;}}return o[0].text;}if(obj.selectedIndex<0){return null;}return(obj.options.length>0)?obj.options[obj.selectedIndex].text:null;case 'select-multiple':
if(obj.options==null){return null;}var values=new Array();for(var i=0;i<obj.options.length;i++){if((use_default&&obj.options[i].defaultSelected)||(!use_default&&obj.options[i].selected)){values[values.length]=obj.options[i].text;}}return(values.length==0)?null:commifyArray(values,delimiter);}/*alert("FATAL ERROR: Field type "+obj.type+" is not supported for this function");*/return null;}
function setSingleInputValue(obj,value){switch(obj.type){case 'radio': case 'checkbox': if(obj.value==value){obj.checked=true;return true;}else{obj.checked=false;return false;}case 'text': case 'hidden': case 'textarea': case 'password': obj.value=value;return true;case 'select-one': case 'select-multiple':
var o=obj.options;for(var i=0;i<o.length;i++){if(o[i].value==value){o[i].selected=true;}else{o[i].selected=false;}}return true;}/*alert("FATAL ERROR: Field type "+obj.type+" is not supported for this function");*/return false;}
function getInputValue(obj,delimiter){var use_default=(arguments.length>2)?arguments[2]:false;if(isArray(obj) &&(typeof(obj.type)=="undefined")){var values=new Array();for(var i=0;i<obj.length;i++){var v=getSingleInputValue(obj[i],use_default,delimiter);if(v!=null){values[values.length]=v;}}return commifyArray(values,delimiter);}return getSingleInputValue(obj,use_default,delimiter);}
function getInputText(obj,delimiter){var use_default=(arguments.length>2)?arguments[2]:false;if(isArray(obj) &&(typeof(obj.type)=="undefined")){var values=new Array();for(var i=0;i<obj.length;i++){var v=getSingleInputText(obj[i],use_default,delimiter);if(v!=null){values[values.length]=v;}}return commifyArray(values,delimiter);}return getSingleInputText(obj,use_default,delimiter);}
function getInputDefaultValue(obj,delimiter){return getInputValue(obj,delimiter,true);}
function isChanged(obj){return(getInputValue(obj)!=getInputDefaultValue(obj));}
function setInputValue(obj,value){var use_default=(arguments.length>1)?arguments[1]:false;if(isArray(obj)&&(typeof(obj.type)=="undefined")){for(var i=0;i<obj.length;i++){setSingleInputValue(obj[i],value);}}else{setSingleInputValue(obj,value);}}
function isFormModified(theform,hidden_fields,ignore_fields){if(hidden_fields==null){hidden_fields="";}if(ignore_fields==null){ignore_fields="";}var hiddenFields=new Object();var ignoreFields=new Object();var i,field;var hidden_fields_array=hidden_fields.split(',');for(i=0;i<hidden_fields_array.length;i++){hiddenFields[Trim(hidden_fields_array[i])]=true;}var ignore_fields_array=ignore_fields.split(',');for(i=0;i<ignore_fields_array.length;i++){ignoreFields[Trim(ignore_fields_array[i])]=true;}for(i=0;i<theform.elements.length;i++){var changed=false;var name=theform.elements[i].name;if(!isBlank(name)){var type=theform.elements[i].type;if(!ignoreFields[name]){if(type=="hidden"&&hiddenFields[name]){changed=isChanged(theform[name]);}else if(type=="hidden"){changed=false;}else{changed=isChanged(theform[name]);}}}if(changed){return true;}}return false;}

