//////////////////////////////////////
//
// Generic Help methods
// 
function trim(value) {
  // trim leading spaces
  while ('' + value.charAt(0) == ' ')
    value = value.substring(1);
  // trim trailing spaces
  while ('' + value.charAt(value.length-1) == ' ')
    value = value.substring(0,value.length-1);
  return value;
}

function noNull(v, def)
{
  if(v)
    return v;
  if(def)
    return def;
  return "";
}


function log(str)
{
  var divName = "logOutput";
  var logOutput = $(divName);
  if(!logOutput){
    var logOutput = document.createElement('textarea');
    logOutput.setAttribute("id", divName);
    document.body.appendChild(logOutput);
  }
  //logOutput.innerHTML += str;
  logOutput.value+=str + "\n";
}

function dumpObject(o)
{
  var str = "";
  for (x in o)
    str += x + ":" + o[x] + "\n";
  return str;
}

/**
*  return the selected option value. 
*  @param option  The option control
*/

function getSelectedOptionValue(option)
{
  return option.options[option.options.selectedIndex].value;
}

///////////////////////////////////////////////////
//
// Pagination support
// author: cjw
//
/**
* Relase a key value in a url.
* @param url - The original url
* @param key - The key to be replaced
* @param val - The new value for the key
* @return  The new url
* @author Chen Jianwu
*/
function URLReplace(url,key,val) {
  var start;
  while((start=url.indexOf(key + "="))>0){
    var last=url.charAt(start-1);
    if(last=='&'||last=='?')
      break;   //find it
  }
  
  var keyValue = "";
  if(val != null)
    keyValue = key + "=" + val;
  
  if(start < 0){  //this is a new key
    if(val != null)
      url+=((url.indexOf("?")<0)?"?":"&")+keyValue;
    return url;
  }
  var end=url.indexOf('&',start);
  return url.substring(0,start) + keyValue + (end>0?url.substring(end):"");
}

function gotoPage(page,total) {
  var url=document.URL;
  url=URLReplace(url,"pageNumber",page);
  url=URLReplace(url,"total",total);
  
  //To restore to search mode. avoid continue to restore from session.
  url=URLReplace(url,"listType","search");
  
  //Delete is only used in the current page. shouldn't keep.
  url=URLReplace(url,"delete",null);
  
  //	prompt("test",url);
  //	document.URL=url;
  window.open(url,"_self");
}

/*
function gotoPage(page,total,currentProductType) {
var url=document.URL;
url=URLReplace(url,"pageNumber",page);
url=URLReplace(url,"total",total);
url=URLReplace(url,"currentProductType",currentProductType);

//To restore to search mode. avoid continue to restore from session.

//url=URLReplace(url,"listType","search");

//Delete is only used in the current page. shouldn't keep.
url=URLReplace(url,"delete",null);

//	prompt("test",url);
//	document.URL=url;
window.open(url,"_self");
}
*/

function orderBy(column, desc)
{
  var url=document.URL;
  url=URLReplace(url,"orderBy",column);
  url=URLReplace(url,"desc",desc);
  //To restore to search mode. avoid continue to restore from session.
  url=URLReplace(url,"listType","search");
  //Delete is only used in the current page. shouldn't keep.
  url=URLReplace(url,"delete",null);
  window.open(url,"_self");
}

function openWindow(url) {
  top.open(url,top.name);
}

/**
*  get the url encode string of the form
*  If there are no argument of action, then use the
*  forms default action url.
*
*  It's a pity that I have no way to get the value of image input.
*  The javascript's inconsistency makes me very sad. You can use form.elemets get all
*  other element but not image.
*
*  @param form  The form the get the url from
*  @param action  optional,the action url,if not provided, it will use form's action url.
*  @author cjw
*/
function getFormSubmitURL(form,action) {
  if(getFormSubmitURL.arguments.length==1)
    action=form.action;
  
  var qry="";
  var els=form.elements;
  for(var i=0;i<els.length;i++){
    var e=els[i];
    if(e.type=="checkbox"||e.type=="radio"){
      if(!e.checked)
        continue;
      qry+="&"+e.name+"="+escape(e.value);
      //		}else if(e.type=="image"){
      //			qry+="&"+e.name+".x="+e.x+"&"+e.name+".y="+e.y;
    }else{
    qry+="&"+e.name+"="+escape(e.value);
  }
}
if(qry.length>0)
  qry=qry.substring(1);

return action+"?"+qry;
}

//////////////////////////////////////////////////
//
// Field validation methods
// author: cjw
//

function validField(field,min,max,message) {
  if(field==null)
    return true;
  if(field.value==null||field.value.length<min||field.value.length>max){
    if(message==null)
      message=field.name+" should have the length of : "+min+" to "+ max;
    alert(message);
    field.focus();
    return false;
  }
  return true;
}

function validPhoneNumberField(field,min,max,message, isOptional) {
  if(isOptional && (field.value == null || field.value == ""))
    return true;
  
  if(!validField(field,min,max,message))
    return false;
  
  for(var i=0; i<field.value.length; i++){
    var c = field.value.charAt(i);
    if(!(isDigit(c) || c == '+' || c=='(' || c==')' || c == ' ')){
      if(message == null)
        message=field.name+" is not a valid phone number.";
      alert(message);
      field.focus();
      return false;
    }
  }
  
  return true;
}

// --------------------------------------
function validateEmailAddress(str, message, isOptional) {
        
        if (isOptional && (str == null || str == "")) return true;
    
        var at="@";
        var dot=".";
        var lat=str.indexOf(at);
        var lstr=str.length;
        var ldot=str.indexOf(dot);
        if (str.indexOf(at)==-1){
           alert(message);
           return false;
        }

        if (str.indexOf(at)==-1 || str.indexOf(at)==0 || str.indexOf(at)==lstr){
           alert(message);
           return false;
        }

        if (str.indexOf(dot)==-1 || str.indexOf(dot)==0 || str.indexOf(dot)==lstr){
            alert(message);
            return false;
        }

         if (str.indexOf(at,(lat+1))!=-1){
            alert(message);
            return false;
         }

         if (str.substring(lat-1,lat)==dot || str.substring(lat+1,lat+2)==dot){
            alert(message);
            return false;
         }

         if (str.indexOf(dot,(lat+2))==-1){
            alert(message);
            return false;
         }

         if (str.indexOf(" ")!=-1){
            alert(message);
            return false;
         }

         return true;				
}


//---------------------------------------


function validEmailField(field, message, isOptional) 
{
  if(isOptional && (field.value == null || field.value == ""))
    return true;
  
  var email=field.value;
  var pAt=-1;pDot=-1;
  if(email!=null&&email.length>0){
    pAt=email.indexOf('@');
    pDot=email.lastIndexOf('.');
  }
  if(pAt<0||pDot<0||pDot<pAt){
    if(message==null)
      message="Invalid emailaddress";
    alert(message);
    field.focus();
    return false;
  }
  return true;
}

//will be fully implemented later
function validNumberField(field, min, max, message, isOptional) 
{
  if(isOptional && (field.value == null || field.value == ""))
    return true;
  if(
    field.value==null||
    field.value.length==0||
    field.value.length<min||
    field.value.length>max||
    !isInteger(field.value)){
  if(message==null)
    message=field.name+" should be a number and have the length of : "+min+" to "+ max;
  alert(message);
  field.focus();
  return false;
}
return true;
}

// check that field contain valid float value
function validFloat(fieldObject,minValue,maxValue) {
    var fieldValue = fieldObject.value;

    var regex = /^\d+(\.\d+)?$/;
    
    if (regex.test(fieldValue)) {
        if (parseFloat(fieldValue) < minValue || parseFloat(fieldValue) > maxValue) {
            alert(fieldValue + " is out of range.\nPlease enter a value between " + minValue + " and " + maxValue);
        } else return true;
    } else {
        alert(fieldValue + " is not valid");
    }
    
    fieldObject.focus();
    //fieldObject.style.backgroundColor = "#FFAEAE";
    return false;
}

//will be fully implemented later
function validDoubleField(field, min, max, message, isOptional) 
{
  if(isOptional && (field.value == null || field.value == ""))
    return true;
  if(
    field.value==null||
    field.value.length==0||
    field.value.length<min||
    field.value.length>max||
    !isDouble(field.value)){
  if(message==null)
    message=field.name+" should be a float number value and have the length of : "+min+" to "+ max;
  alert(message);
  field.focus();
  return false;
}
return true;
}

/**
* validate if a field match a specified reg expression
* @param field  The field to verfy
* @param regexp  The regexp pattern to match against
* @param message The optional message
* @param isOptional  If this field is optional 
*/
function validRegExpField(field, regexp, message, isOptional) 
{
  if(isOptional && (field.value == null || field.value == ""))
    return true;
  
  if(field.value.match(regexp) != null)
    return true;
  
  if(message==null)
    message=field.name+" should have the pattern of: "+ regexp;
  alert(message);
  field.focus();
  
  return false;
}

//will be fully implemented later
function validEqualFields(field1, field2, message) 
{
  if(field1.value != field2.value){
    if(message == null)
      message=field1.name+" should be equal to "+ field2.name;
    alert(message);
    field2.focus();
    return false;
  }
  return true;
}

function validNotEmpty(field , message) 
{
  empty = (field.value == "" || field.value == "<undefined>");
  if (empty) {
    if(message == null)
      message=field.name + " can't be empty";
    alert(message);
    field.focus();
    return false;
  }
  return true;
}

//Validate CheckBox
function validateCheckBox(checkbox, message)
{
  if(isCheckboxChecked(checkbox))
    return true;
  
  if(message == null)
    message = "Please select using the checkboxes provided.";
  alert(message);
  return false;
}

function isDouble(s)
{
  var hasDecimalPoint = false;
  for(var i=0;i<s.length;i++){
    var c = s.charAt(i);
    if(!isDigit(c) && c != '.') return false;
    if( c == '.'){
      if(hasDecimalPoint)  //Already encounter '.'
        return false;
      hasDecimalPoint = true;
    }
  }
  return true;
}

function isInteger (s)
{
  for(var i=0;i<s.length;i++)
    if(!isDigit(s.charAt(i))) return false;
  return true;
}

function isDigit(c)
{
  return c>='0'&&c<='9';
}

function isCheckboxChecked(checkbox)
{
  if(!checkbox)
    return false;
  
  if(checkbox.length == null)
    return checkbox.checked;
  
  for (var i=0; i<checkbox.length; i++)
    if (checkbox[i].checked)
      return true;
    return false;
  }
  
  function checkAll(checkbox,checked)
  {
    for (var i=0;i<checkbox.length;i++)
      checkbox[i].checked=checked;
  }
  
  function isDigit(c) {
    return c>='0'&&c<='9';
  }
  
  ////////////////////////////////////////
  //
  //  Application specific
  //  By default the action is delete, and need confirm
  //  deferent action can be specified.
  //
  function validateDelete(action, needConfirm)
  {
    //Set the default value
    if(action == null)
      action = "delete";
    if(needConfirm == null)
      needConfirm = true;
    
    if(document.searchForm.selected+"" == "undefined"){
      alert("No item to "+ action);
      return false;
    }
    if(!isCheckboxChecked(document.searchForm.selected)){
      alert("Please select item to " + action);
      return false;
    }
    var res = true;
    if(needConfirm)
      res = confirm('Are you sure to ' + action + '?');
    return res;
  }
  
  function popWindow(url, windowName, options) {
    var win = window.open(url, windowName, options);
    win.focus();
  }
  
  //////////////////////////////////////
  //
  // AJAX support
  //
  function getXMLHttpRequest(){
    if(window.XMLHttpRequest) 
      return new XMLHttpRequest();
    
    if(window.ActiveXObject){
      try{
        return new ActiveXObject("Msxml2.XMLHTTP");
      } catch(e) {
      try {
        return new ActiveXObject("Microsoft.XMLHTTP");
      } catch(e) {
      return null;
    }
  }
}
}

function isString(it){
  // summary:  Return true if it is a String.
  return (it instanceof String || typeof it == "string");
}

function hitch(thisObject, method) {
  if(isString(method)) {
    var fcn = thisObject[method];
  } else {
  var fcn = method;
}

return function() {
  return fcn.apply(thisObject, arguments);
}
}

/*
* Hanlder can be a function or and DOM element, 
* if it's a DOM element, the inner html will be replaced with the response
*/
function AJAXRequest(_url, _handler)
{
  this.url = _url;
  this.handler = _handler;
  this.send = function(){
    this.req = getXMLHttpRequest();
    this.req.open("GET", this.url, /*async*/true);
    this.req.onreadystatechange = hitch(this, "onreadystatechange");
    this.req.send(/*no params*/null);
  }
  
  this.onreadystatechange = function(){
    if (this.req.readyState != 4) //not complete
      return;
    if (this.req.status != 200){
      alert("There was a problem retrieving the XML data:\n" + this.req.statusText + ":" + this.req.status);
      this.req = null;
      return;
    }
    if(typeof(this.handler) == 'function')
      this.handler(this.req.responseText, this);
    else  //It's an DOM element, we will fillin it with the response
      this.handler.innerHTML=this.req.responseText;
  }
}

function isIn(values, value)
{
  for(var i=0; i<values.length; i++){
    if(values[i] == value)
      return true;
  }
  return false;
}

//////////////////////////////////
//DOM helper 
//Get the element by id
function el(id)
{
  return document.getElementById(id);
}

//////////////////////////////////
//
// Browser detect.
//
function isFirefox()
{
  return navigator.userAgent.indexOf("Firefox") >= 0;
}


// Mark's auxiliary functions ///////////////////////////////////////////////

// global variable that keeps track if advanced search panel is visible
var searchFilterVisible = false;

/////////////////////////////////////
// params: src => the source of event
// return: none
// this function shows or hides the advanced search panel
var searchFilter = function(src) {
  if (searchFilterVisible) {
    $('searchFilter').hide();
    searchFilterVisible = false;
  } else {
  $('searchFilter').show();
  searchFilterVisible = true;
}
};

/**
*
* AJAX IFRAME METHOD (AIM)
* http://www.webtoolkit.info/
* File Upload support
* 
*    <form action="upload.jsp?handler=../move.jsp" method="post" 
*        enctype='multipart/form-data' 
*        onsubmit="return AIM.submit(this, completeCallback)">
*        <input type="hidden" name="uploadId">
*        <div><label>File:</label> <input type="file" name="file" /></div>
*        <div><input type="submit" value="SUBMIT" /></div>
*    </form>
*    <div id=r/>
*    <script>
*        function completeCallback(response) {
*            // make something useful after (onComplete)
*            el('r').innerHTML = response;
*        }
*     </script>
*    
*/
AIM = {
  submit : function(form, onComplete) {
    if(form.action.indexOf("uploadId=") > 0)  //done already
      return true;
    
    //Create the iFrame      
    var id = 'f' + Math.floor(Math.random() * 99999);
    var div = document.createElement('DIV');
    div.innerHTML = '<iframe style="display:none" id=' + id + ' name=' + id + ' onload="AIM.loaded(\''+id+'\')" />';
    document.body.appendChild(div);
    form.setAttribute('target', id);
    
    var hasParam = form.action.indexOf("?") > 0
    form.action += hasParam ? "&" : "?";
    form.action += "uploadId=" + id;
    
    document.getElementById(id).onComplete = onComplete;
    return id;
  },
  
  loaded : function(id) {
    var i = document.getElementById(id);
    if (i.contentDocument) {
      var doc = i.contentDocument;
    } else if (i.contentWindow) {
    var doc = i.contentWindow.document;
  } else {
  var doc = window.frames[id].document;
}
if (doc.location.href == "about:blank") {
  return;
}

if (i.onComplete) {
  i.onComplete(doc.body.innerHTML);
}
}
}

/**
form:  Have to have a submit button named submit.
onUploadComplete(form, response)
onProgressChange(form)
progressURL: must take a uploadId as parameter
form.action URL: must take a uploadId as parameter
*/
function Uploader(form, onUploadComplete, progressURL, onProgressChange)
{
  this.form = form;
  this.onUploadComplete = onUploadComplete;
  this.progressURL = progressURL;
  this.onProgressChange = onProgressChange;
  this.orgOnSubmit = form.onsubmit;
  this.inProgress = false;
  
  //Create the iFrame
  this.id = 'f' + Math.floor(Math.random() * 9999999);
  
  var hasParam = form.action.indexOf("?") > 0
  form.action += hasParam ? "&" : "?";
  form.action += "uploadId=" + this.id;
  
  
  this.loaded = function() {
    if(progressURL)
      clearTimeout(this.timer);
    
    var doc = window.frames[this.id].document;
    if (doc.location.href == "about:blank")
      return;
    if (this.onUploadComplete)
      this.onUploadComplete(form, doc.body.innerHTML);
    
    this.inProgress = false;
  }
  
  this.onSubmit = function() {
    if(this.inProgress){
      alert("Previous uploading is still in progress!");
      return false;  //Prevent repeated submit
    }
    
    if(this.orgOnSubmit && !this.orgOnSubmit.apply(this.form))
      return false;
    
    if(!$(this.id)){
      //Following code have to put in the event handler, if put outside which will be load
      //together with page loading, IE will fail.
      var div = document.createElement('div');
      div.innerHTML = '<iframe style="display:none" id=' + this.id + ' name=' + this.id + ' onload="this.onload_1();" />';
      document.body.appendChild(div);
      //Stupid IE bug, you can't get and set the onload event for IFrame
      $(this.id).onload_1 = hitch(this, "loaded");
      form.setAttribute('target', this.id);
    }
    //alert(form.target + ";" + form.action);
    this.inProgress = true;
    //log("onSubmit -- Before start timer");
    if(this.progressURL)
      this.timer = setTimeout(hitch(this, "updateProgress"), 2000);
    return true;
  }
  
  form.onsubmit = hitch(this, "onSubmit");
  
  this.updateProgress = function(){
    //log("updateProgress");
    //Add random to prevent get from cache. I.E. has this issue even for ajax request
    var ajaxRequest = new AJAXRequest(this.progressURL+"?uploadId=" + this.id + "&random=" + Math.random(), hitch(this, "ajaxHandler"));
    ajaxRequest.send();
  }
  
  this.ajaxHandler = function(response, ajaxRequest)
  {
    //log("ajaxHandler");
    if(!this.inProgress)
      return;
    this.onProgressChange(form, response);
    this.timer = setTimeout(hitch(this, "updateProgress"), 2000);
  }
}

/**
* implement a JSP like template using javascript syntax
* [% %] is equivalent to <% %>
* [%= %] is equivalent to <%= %>
* alternative:  %{} will be equivalent to [%= %]
* and <!--%  %--> is equilent to [% %] to prevent some un-necessary XML escape of '<', etc symbol.
*
* To prevent browser escape special XML symbols, the template can be put inside <textarea> instead of <div>
* and user ${id}.value  to retrieve the original string.
*/
function JSPTemplate(_tmpl){
  this.tmpl = _tmpl.replace(/<!--%/mg, '[%').replace(/%-->/mg, '%]').replace(/%{([^%]*)}/mg, '[%=$1%]');
  this.tmpl = this.tmpl.replace(/=(\[%=[^%]*%\])/mg, "='$1'"); //fix for I.E., IE may remove quote for attribute values
  
  this.compile = function()
  {
    var re = /\[%([^%]*)%\]/mg;
    var lastIndex = 0;
    var code = '';
    var match;
    while((match = re.exec(this.tmpl)) != null){
      var matchedStr = match[1];
      code += 'result+=this.tmpl.substring(' + lastIndex + ',' + match.index + ');\n';
      if(matchedStr.charAt(0) == '=')
        code += 'result += ' + matchedStr.substring(1) + ';\n';
      else
        code += matchedStr;
      lastIndex = re.lastIndex;
    }
    code += 'result+=this.tmpl.substring(' + lastIndex + ');\n';
    return code;
  }
  this.code = this.compile(); 
  
  this.evaluate = function ()
  {
    var result = '';
    eval(this.code);
    return result;
  }
}
