  /**
 * utils.js
 *
 * Johans util scripts.
 *
 * Dependencies:
 *   -none-
 */
 
 
 
	/**
	 * DEBUG UTILITY
	 *
	 * by default it writes to innerHtml of tag "dutil_msg"
	 */
	var debugUtil = new DebugUtil();
 	function DebugUtil() 
 	{
 		var strHref = window.location.href;
 		if ( strHref.indexOf("?jdebug") > -1 || strHref.indexOf("&jdebug") > -1){
 			this.debugOn = true;
 		} else {
 			this.debugOn = false; 	   			
  	}
 	}
 	DebugUtil.prototype.defaultTag = 'dutil_msg';
	DebugUtil.prototype.trace = function(p_message,p_tag) {
		// return if not debug enabled
		if(!this.debugOn) //typeof(jdebug) == "undefined" || !jdebug)
			return;
			
		if(p_tag)
	  		document.getElementById(p_tag).innerHTML += "<br/>"+jutils.getCurrentTimeString()+" - "+p_message;
		else
   		document.getElementById(this.defaultTag).innerHTML += "<br/>"+jutils.getCurrentTimeString()+" - "+p_message;
	}
 

	/***************************************
	 * JUtils - All purpose functions
	 */
	  
  jutils = new JUtils();
  function JUtils() {
  }
  
  /* Remove spaces in start and end of string
   */
  JUtils.prototype.Trim = function ( p_str ) {
 	return p_str.replace(/^\s*|\s*$/g,"");
  }
  
  /* In-place Array Shuffler/Randomizer using Fisher Yates
   *
   * Taken from http://sedition.com/perl/javascript-fy.html
   */
  JUtils.prototype.FisherYates = function ( myArray ) {
	  var i = myArray.length;
	  if ( i == 0 ) return false;
	  while ( --i ) {
	     var j = Math.floor( Math.random() * ( i + 1 ) );
	     var tempi = myArray[i];
	     var tempj = myArray[j];
	     myArray[i] = tempj;
	     myArray[j] = tempi;
	   }
	}
    
	/* 
    * Browser independent add event listener
    *
    * p_object 	the object to attach events to
    * p_trigger 	the event name (eg. load, click etc)
    * p_function	the event handler
    * p_useCapture	If to capture events before reaching the target, else done during bubble
    */
   JUtils.prototype.AddEventListener = function(p_object, p_trigger, p_function, p_useCapture)
   {
       if(window.addEventListener)
       {
           p_object.addEventListener(p_trigger,p_function, p_useCapture);
       }
       else
       {
           p_object.attachEvent('on'+p_trigger,p_function);
       }
   }
   
    /* 
     * Browser independent remove event listener
     *
     * p_object 	the object to attach events to
     * p_trigger 	the event name (eg. load, click etc)
     * p_function	the event handler
     * p_useCapture	If to capture events before reaching the target, else done during bubble
     */
    JUtils.prototype.RemoveEventListener = function(p_object, p_trigger, p_function, p_useCapture)
    {
        if(window.removeEventListener)
        {
            p_object.removeEventListener(p_trigger,p_function, p_useCapture);
        }
        else
        {
            p_object.detachEvent('on'+p_trigger,p_function);
        }
    }
   
  /*
   * Get the current time formatted as
   * HH:mm:ss.ms
   */
  JUtils.prototype.getCurrentTimeString = function()
  {
    var time = new Date();
    var hours = time.getHours();
    var minutes = time.getMinutes();
    minutes=((minutes < 10) ? "0" : "") + minutes;
    var seconds = time.getSeconds();
    seconds=((seconds < 10) ? "0" : "") + seconds;
    var dateString = hours + ":" + minutes + ":" + seconds + " ."+time.getMilliseconds();
    return dateString;
  };  
  /*
   * Get the current date and time formatted as
   * yyyy-M-D HH:mm:ss
   */
  JUtils.prototype.getCurrentDateString = function()
  {
    var time = new Date();
    var hours = time.getHours();
    var minutes = time.getMinutes();
    minutes=((minutes < 10) ? "0" : "") + minutes;
    var seconds = time.getSeconds();
    seconds=((seconds < 10) ? "0" : "") + seconds;
    var dateString = time.getFullYear() + "-"+time.getMonth()+"-"+time.getDate() + " " +hours + ":" + minutes + ":" + seconds;
    return dateString;
  };    
  /* depricated */ 
  GetCurrentDateString = function()
  {
    var time = new Date();
    var hours = time.getHours();
    var minutes = time.getMinutes();
    minutes=((minutes < 10) ? "0" : "") + minutes;
    var seconds = time.getSeconds();
    seconds=((seconds < 10) ? "0" : "") + seconds;
    var dateString = time.getFullYear() + "-"+time.getMonth()+"-"+time.getDate() + " " +hours + ":" + minutes + ":" + seconds;
    return dateString;
  };    
  
  
  /* depricated */
  JUtils.prototype.GetRequestObject = function(handler)
  {
      var reqXMLObject;
      //determine if the browser is Moz, FF, NN, Op
      if (window.XMLHttpRequest){
          reqXMLObject = new XMLHttpRequest();            //set the request
          reqXMLObject.onreadystatechange = handler;    //function to call on each set
      } else if(window.ActiveXObject) { //ActiveX - can we say IE?
          //Create our RequestObject
          reqXMLObject = new ActiveXObject("Microsoft.XMLHTTP");
          if(reqXMLObject) {
              reqXMLObject.onreadystatechange = handler;  //function to call on each step
          }
      } else {  //I do not support this so I need to do something!
					debugUtil.trace("JUtils.GetRequestObject Error");
	        //DO NOTHING this.DisplayError("Your browser does not support the javascript needed for this system.");
      }
      return reqXMLObject;
  }
  
  /*
   * Replace tag start and end with entities
   */
  function GetEscapedHtml(inputstring)
  {
    if(inputstring!=null)
      return inputstring.replace(new RegExp("<",'g'),"&lt;").replace(new RegExp(">",'g'),"&gt;");
    else
      return "";
  }
  
  /** Taken from quirksmode.org */
  function studyjapanese_getSelection()
  {
  	var txt = '';
  	//var foundIn = '';
  	if (window.getSelection)
  	{
  		txt = window.getSelection();
  		//foundIn = 'window.getSelection()';
  	}
  	else if (document.getSelection)
  	{
  		txt = document.getSelection();
  		//foundIn = 'document.getSelection()';
  	}
  	else if (document.selection)
  	{
  		txt = document.selection.createRange().text;
  		//foundIn = 'document.selection.createRange()';
  	}
  	return txt;
  }
  

  
  /*******************************************
   * AJAX UTILS
   *
   * Dependencies
   * - GraphUtil
   *******************************************/
  
  ajaxUtils = new AjaxUtils();
  
  function AjaxUtils()
  {
    this.ERR_NODATA = "Server error, please try again or contact the site administrator.[Code:AjxU-001]";
    this.ERR_XMLNOTSUPPORTED = "Server error, please try again or contact the site administrator.[Code:AjxU-002]";
    this.ERR_HANDLER = "Server error, please try again or contact the site administrator. [Code:AjxU-003]: ";
    this.ERR_JSNOTSUPPORTED="Your browser does not support the javascript needed for this system. [Code: AjxU-004]";    
    this.ERR_GNRL_AJAX = "Server error, please try again or contact the site administrator. [Code:AjxU-005]: ";
    this.ERR_NO_HANDLER_OBJECT = "Server error, please try again or contact the site administrator. [Code:AjxU-006]: ";
  }
  
  // ****************************************************************
  // Gets a HTTPRequest with a handler and object referral
  // The handler must support the input parameters
  //
  // - reqXML: The returning XML object
  // - object: any object valuable to the handler.
  //
  AjaxUtils.prototype.GetRequestObject = function(p_handler,p_object)
  {
    var reqXML;
    try{
      if(typeof(p_handler)== "undefined")
      {
        graphutils.DisplayError(this.ERR_NO_HANDLER_OBJECT);
      }
      
      localobject = this;
      //determine if the browser is Moz, FF, NN, Op
      if (window.XMLHttpRequest){
          reqXML = new XMLHttpRequest();            //set the request
          // reqXML.onreadystatechange = function() {p_handler(reqXML,p_object);}
          reqXML.onreadystatechange = function() {localobject.GeneralHandler(reqXML,p_handler,p_object);};  //function to call on each step
      } else if(window.ActiveXObject) { //ActiveX - can we say IE?
          //Create our RequestObject
          reqXML = new ActiveXObject("Microsoft.XMLHTTP");
          if(reqXML) {
              reqXML.onreadystatechange = function() {localobject.GeneralHandler(reqXML,p_handler,p_object);};  //function to call on each step
          }
      } else {  //I do not support this so I need to do something!
        graphutils.DisplayError(this.ERR_JSNOTSUPPORTED);
      }
    } catch(err) {
      debugUtil.trace(this.ERR_GNRL_AJAX+err);
    }
    return reqXML;
  }
  
  /* internal function, calls the handler with parameters (reqXML,valueobject) */  
  AjaxUtils.prototype.GeneralHandler = function(p_requestobject,p_targethandler,p_valueobject) {
    try {
      //Look to see if the request is in the 4th stage (complete)
      if(p_requestobject.readyState == 4){
        //Make sure that we get a sucess page status
        if(p_requestobject.status==0 || p_requestobject.status == 200)
        {
          p_targethandler(p_requestobject,p_valueobject);
        } else {
          graphutils.DisplayMessage(this.ERR_XMLNOTSUPPORTED,"tr_pnlError");
        }
      }
    } catch(err) {
        graphutils.DisplayMessage(this.ERR_HANDLER+err,"tr_pnlError");
    }
  };  
  
  /*******************************************
   * GRAPH UTILS
   *******************************************/
  graphutils = new GraphUtils();
  function GraphUtils()
  {}
	
  /* 
	 * getElementsByClass by Dustin Diaz
     */
	GraphUtils.prototype.GetElementsByClass = function (searchClass,node,tag) {
		var classElements = new Array();
		if ( node == null )
			node = document;
		if ( tag == null )
			tag = '*';
		var els = node.getElementsByTagName(tag);
		var elsLen = els.length;
		var pattern = new RegExp('(^|\\s)'+searchClass+'(\\s|$)');
		for (i = 0, j = 0; i < elsLen; i++) {
			if ( pattern.test(els[i].className) ) {
				classElements[j] = els[i];
				j++;
			}
		}
		return classElements;
	}

  /* alternative by James Reeves
document.getElementsByClass = function(needle) {
   var result = document.evaluate(
      "/
  /*[@class='" + needle + "']", document, null,
      XPathResult.ANY_TYPE, null);
   var resultArray = new Array();
   var element = "";
   while (element = result.iterateNext())
      resultArray.push(element);
   return resultArray;
} 
*/
  // 
  // Display the message p_message in the element p_position
  // 
  GraphUtils.prototype.DisplayMessage= function(p_message,p_position)
  {
    try {
      if(typeof p_position=='undefined' || typeof document.getElementById(p_position)!='object')
      {
        p_position = "tr_pnlInstruction"
      }
      if(typeof document.getElementById(p_position)!='object')
      {
      	debugUtil.trace("GraphUtils.DisplayMessage: Undefined placeholder ");
      }
      document.getElementById(p_position).innerHTML = p_message;
      document.getElementById(p_position).style.display = "block";
    } catch(err) {
      debugUtil.trace("Error in DisplayMessage(). "+err+" : "+p_message);
    }
  }
  // 
  // Display the error message p_message in the element p_position
  // 
  GraphUtils.prototype.DisplayError= function(p_message,p_position)
  {
    try {
      if(typeof p_position=='undefined' 
         || typeof document.getElementById(p_position)!='object')
      {
        p_position = "tr_pnlError"
      }
      if(typeof document.getElementById(p_position)!='object')
      {
        debugUtil.trace("GraphUtils.DisplayMessage: Undefined placeholder ");
      }
      document.getElementById(p_position).innerHTML += p_message;
      document.getElementById(p_position).style.display = "block";
    } catch(err) {
      debugUtil.trace("GraphUtils.DisplayError(). "+err+" : "+p_message);
    }
  }
  GraphUtils.prototype.ShowElement = function(elm)
  {
    try
    {
      // function borrowed from pasta.cantbedone.org
      // IE 5+ and NS 6...
      if (document.getElementById) {
        if(typeof elm=='object') {
          elm.style.display = "block";
        } else {
          document.getElementById(elm).style.display = "block";
        }
      // IE 4...
      } else if (document.all) {
        document.all[elm].style.display = "block";
      }
    }
    catch(err)
    {
       debugUtil.trace("Error (utils.js, ShowElement): "+elm);
    }
  };
  GraphUtils.prototype.HideElement = function(elm) {
    try
    {
      // function borrowed from pasta.cantbedone.org
      // IE 5+ and NS 6...
      if (document.getElementById) {
        if(typeof elm=='object') {
          elm.style.display = "none";
        } else {
          document.getElementById(elm).style.display = "none";
        }
      // IE 4...
      } else if (document.all) {
      	document.all[elm].style.display = "none";
      }
    }
    catch(err)
    {
      if(jdebug)
        debugUtil.trace("GraphUtils.HideElement : Error (utils.js, HideElement): "+elm);
    }
  };
  GraphUtils.prototype.ToggleElement = function(elm) {
    if (document.getElementById) {
      if(typeof elm=='object') {
        obj = elm;
      } else {
        obj = document.getElementById(elm);
      }
      if(obj.style.display == "none") {
        obj.style.display = "block"
      } else {
        obj.style.display = "none";
      }
    } else if (document.all) {
      if(document.all[obj].style.display = "none") {
        document.all[obj].style.display = "block";
      } else {
      	document.all[obj].style.display = "none";
     	}
    }
  };
  
  
  GraphUtils.prototype.MakeInvisible = function(elm) {
    try
    {
      // function borrowed from pasta.cantbedone.org
      // IE 5+ and NS 6...
      if (document.getElementById) {
        if(typeof elm=='object') {
          elm.style.visibility = "hidden";
        } else {
          document.getElementById(elm).style.visibility = "hidden";
        }
      // IE 4...
      } else if (document.all) {
      	document.all[elm].style.visibility = "hidden";
      }
    }
    catch(err)
    {
      debugUtil.trace("GraphUtils.MakeInvisible : Error (utils.js, MakeInvisible): "+elm);
    }
  };
  GraphUtils.prototype.MakeVisible = function(elm)
  {
    try
    {
      // function borrowed from pasta.cantbedone.org
      // IE 5+ and NS 6...
      if (document.getElementById) {
        if(typeof elm=='object') {
          elm.style.visibility = "visible";
        } else {
          document.getElementById(elm).style.visibility = "visible";
        }
      // IE 4...
      } else if (document.all) {
        document.all[elm].style.visibility = "visible";
      }
    }
    catch(err)
    {
      debugUtil.trace("GraphUtils.MakeVisible ("+elm+")");
    }
  };
  
  /* Replace the given element's inner html with the given code.
   */
  GraphUtils.prototype.ReplaceInnerHtml = function(elementID,code)
  {
    document.getElementById(elementID).innerHTML = code;
  };
  
    GraphUtils.prototype.FocusElement = function(element)
    {
        var emt = document.getElementById(element);
        if(emt && emt.focus && emt.visible)
            emt.focus();
    };  
    GraphUtils.prototype.ToggleBigFont = function(element)
    {
        var emt = document.getElementById(element);
        if(emt.style.fontSize=="1.7em")
        {
	        emt.style.fontSize = "2.5em";
        }
        else if(emt.style.fontSize=="2.5em")
        {
	        emt.style.fontSize = "1em";
        }
        else
        {
	        emt.style.fontSize = "1.7em";
        }
    };  
    	
	
  /**
	 * Retrieve the absolute X coordinate for an object. 
	 */
	GraphUtils.prototype.findPosX = function (obj)
	{
		var curleft = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				curleft += obj.offsetLeft
				obj = obj.offsetParent;
			}
		}
		else if (obj.x)
			curleft += obj.x;
		return curleft;
	}
	
  /**
	 * Retrieve the absolute Y coordinate for an object. 
	 */
	GraphUtils.prototype.findPosY = function(obj)
	{
		var curtop = 0;
		if (obj.offsetParent)
		{
			while (obj.offsetParent)
			{
				curtop += obj.offsetTop
				obj = obj.offsetParent;
			}
		}
		else if (obj.y)
			curtop += obj.y;
		return curtop;
	}  
	
  /***************************************************
	 * FORM UTILS
	 ***************************************************/  
  
  function FormUtils() {};      
  
  /* Get radio button value, return NULL if error or none found.       
   */ 
  FormUtils.prototype.GetRadioValue = function(p_radioGroup)
  {
    var output=null;
    try {
      for (var i=0; i < p_radioGroup.length; i++)
      {
        if (p_radioGroup[i].checked)
        {
          output = p_radioGroup[i].value;
        }
      }
    } catch(err) {
      debugUtil.trace("FormUtils.GetRadioValue : Error:"+err);
    } finally {
      return output;
    }
  }
  
  
  /**
   * Check if input string is formatted as an email.
   * Return true if ok, false if not.
   *
   * Found at http://regxlib.com
   */
  FormUtils.prototype.CheckEmailFormat = function(p_str)
  {
    return p_str.match(/^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/);
  }
  
  
  
  
   
  /*******************************************
   * POPUP UTILS
   *
   * Requires the stylesheet class jpopup
   *******************************************/
  popupUtil = new PopupUtil();
  
  function PopupUtil()
  {
    this.BGTAGID = '__popup_background';
  }
  
  PopupUtil.prototype.HidePopup = function()
  {
      var popupBG = document.getElementById(this.BGTAGID);      
      if(typeof(popupBG)=="object" && popupBG!=null)
      {
        popupBG.style.display="none";
        
        // move away the inner element
        var elems = popupBG.childNodes;
        for(elemIX=0;elemIX<elems.length;elemIX++)
        {
          if(typeof(elems[elemIX])=="object" && elems[elemIX]!=null && elems[elemIX].style)
          {
            elems[elemIX].style.display="none";
            document.body.appendChild(elems[elemIX]);        	
          }
        }
        popupBG.innerHTML ="";
      }
  }
  
  
  /* Show a popup containing the given element */
  PopupUtil.prototype.ShowPopup = function(p_popupInsideID)
  {
      var popupBG = document.getElementById(this.BGTAGID);      
      
      if(typeof(popupBG)=="undefined" || popupBG==null)
      {
        popupBG = document.createElement('div');
	      popupBG.id = this.BGTAGID;
      }
 	    popupBG.className = "jpopup"
 	    popupBG.onclick = new function() {popupUtil.HidePopup();};
      var elem = document.getElementById(p_popupInsideID);
      if(typeof(elem)=="undefined" || elem==null)
      {
        debugUtil.trace("PopupUtil.ShowPopup element 'elem' not found ");
      }
      else
      {
        popupBG.appendChild(elem);
        elem.style.display="block";        
      }
      popupBG.style.top = document.body.scrollTop;    
      popupBG.style.display="block";
      popupBG.style.position="absolute";
      document.body.appendChild(popupBG);
      
      // TODO: complete esc key to cancel
      
      //popupUtil.RepositionPopup();
        setTimeout('popupUtil.RepositionPopup();',50);
    }
    
  /* INTERNAL FUNCTION 
     * repositions popupBG in case the user scrolls the screen */
  	PopupUtil.prototype.RepositionPopup = function () 
    {
      var popupBG = document.getElementById(this.BGTAGID);      
      var scrollTop = 0;
      if (window.pageYOffset) {
        scrollTop = window.pageYOffset;
      }
      else if (document.documentElement)
      {
        scrollTop = document.documentElement.scrollTop; 
      } 
      else 
      {
        scrollTop = document.body.scrollTop;
      }
      popupBG.style.top = scrollTop+"px";
      //popupBG.style.top = document.body.scrollTop;    
      if(popupBG.style.display!='none') 
      {
        setTimeout('popupUtil.RepositionPopup()',10);
      }
      return false;
    }  