////////////////////////////////////////////////////////////////////
// FormFilter class
FormFilter.CLASS_NAME = "FormFilter";

// Constants
FormFilter.FILTER_DIV_ID = 'PopupFilterDiv';

// Constants for calendar
FormFilter.curMonth = "";
FormFilter.curParentID = "";
FormFilter.curYear = "";

// Constants for colors
FormFilter.HIGHLIGHT_COLOR = '#73aee9';

// Constants for dimensions
FormFilter.DFLT_WIDTH = 250;
FormFilter.DFLT_HEIGHT = 250;

FormFilter.MULTI_SELECT_FILTER_WIDTH = 420;
FormFilter.MULTI_SELECT_FILTER_HEIGHT = 320;

FormFilter.MULTI_TEXT_FILTER_WIDTH = 420;
FormFilter.MULTI_TEXT_FILTER_HEIGHT = 320;

FormFilter.DATE_RANGE_FILTER_WIDTH = 470;
FormFilter.DATE_RANGE_FILTER_HEIGHT = 350;

FormFilter.NUMERIC_RANGE_FILTER_WIDTH = 450;
FormFilter.NUMERIC_RANGE_FILTER_HEIGHT = 300;

FormFilter.curWidth = FormFilter.DFLT_WIDTH;
FormFilter.curHeight = FormFilter.DFLT_HEIGHT;

// Constants for filter type
FormFilter.FILTER_TYPE_CHECKBOX       = 'cb';
FormFilter.FILTER_TYPE_DATE           = 'dt';
FormFilter.FILTER_TYPE_DATE_RANGE     = 'dtrg';
FormFilter.FILTER_TYPE_MULTI_SELECT   = 'sel';
FormFilter.FILTER_TYPE_MULTI_TEXT     = 'mt';
FormFilter.FILTER_TYPE_NUMERIC_RANGE  = 'nr';
FormFilter.FILTER_TYPE_TIME           = 'tm';

// Contants for range type text field type
FormFilter.RANGE_TYPE_SRC_EQUALS  = 'rtEq';
FormFilter.RANGE_TYPE_SRC_GREATER_THAN  = 'rtGt';
FormFilter.RANGE_TYPE_SRC_GREATER_EQUAL_THAN  = 'rtGet';
FormFilter.RANGE_TYPE_SRC_LESS_THAN  = 'rtLt';
FormFilter.RANGE_TYPE_SRC_LESS_EQUAL_THAN  = 'rtLet';

// Constants/Hash of range types
FormFilter.htRangeType = new Hashtable();
FormFilter.htRangeType.put(FormFilter.RANGE_TYPE_SRC_GREATER_THAN, ">");
FormFilter.htRangeType.put(FormFilter.RANGE_TYPE_SRC_GREATER_EQUAL_THAN, ">=");
FormFilter.htRangeType.put(FormFilter.RANGE_TYPE_SRC_LESS_THAN, "<");
FormFilter.htRangeType.put(FormFilter.RANGE_TYPE_SRC_LESS_EQUAL_THAN, "<=");

// Constants of numeric range multipliers
FormFilter.htNumRangeMult = new Hashtable();
FormFilter.htNumRangeMult.put('', 'None');
FormFilter.htNumRangeMult.put('K', 'Thousands (K)');
FormFilter.htNumRangeMult.put('M', 'Millions (M)');
FormFilter.htNumRangeMult.put('B', 'Billions (B)');

// Hashtable to store the special filter info
FormFilter.htFilterInfo = new Hashtable();

// Hashtable to store select info
FormFilter.htSelectInfo = new Hashtable();

// Constructor
function FormFilter() {
}

/////////////////////////////////////////////////////////////////////////////////////
// Static functions
/////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////
// Shared functions

// Static method to cancel the changes
FormFilter.cancelChanges = function() {
  FormFilter.hideFilterPopup();
}

// Static method to check if the popup is alredy open
FormFilter.checkPopup = function(id) {
  var tf = $(id);
  var popupDiv = $(FormFilter.FILTER_DIV_ID);

  // Div already showing so close it
  if (popupDiv != null) {
    var disp = popupDiv.style.display;
    popupDiv.style.display = 'none';
    if (FormFilter.curParentID != id) {
      return false;
    }
    if (disp=='block') {
      return true;
    } else if (disp=='none') {
      return false;
    }
    if (FormFilter.curParentID == id) {
      return true;
    }
  }
  return false;
}

// Static method to clear the changes
FormFilter.clearFilter = function(filterType) {
  FormFilter.htFilterInfo.remove(FormFilter.curParentID);
  $(FormFilter.curParentID).value = '';
  FormFilter.hideFilterPopup();
  FormFilter.initFilter(FormFilter.curParentID, filterType);
}

// Static method to clear all the filters
FormFilter.clearAll = function() { 
  FormFilter.htFilterInfo.clear();
  FormFilter.htFilterInfo = new Hashtable();
}

// Static method to hide the popup filter
FormFilter.hideFilterPopup = function() {
  var popupFilterDiv = $(FormFilter.FILTER_DIV_ID);
  if (popupFilterDiv != null) {
    document.body.removeChild(popupFilterDiv);
  }
}

// Static method to highlight a checkbox when checked
FormFilter.highlightCB = function(cb) {
  var clr = "#ffffff";
  var fw = "100"; 
  if (cb.checked) {
    clr = FormFilter.HIGHLIGHT_COLOR;
    fw = "900";
  }
  var fs = $(cb.id+'FS');
  
  fs.style.backgroundColor = clr;
  fs.style.fontWeight = fw;
}

// Static method to register a filter
FormFilter.initFilter = function(filterID, filterType) {
  FormFilter.curParentID = filterID;

  switch(filterType) {
    case FormFilter.FILTER_TYPE_CHECKBOX:
      break;
    case FormFilter.FILTER_TYPE_MULTI_TEXT:
      FormFilter.initMultiTextFilter();
      break; 
    case FormFilter.FILTER_TYPE_MULTI_SELECT:
      FormFilter.initMultiSelectFilter();
      break;
    case FormFilter.FILTER_TYPE_DATE_RANGE:
      FormFilter.initDateRangeFilter();
      break;
    case FormFilter.FILTER_TYPE_NUMERIC_RANGE:
      FormFilter.initNumericRangeFilter();
      break;
    default:
      alert("FormFilter.registerFilter() Unknown filter type: " + filterType + ", filterID: " + filterID);
      break;
  }

}

// Static method to set the current dimensions
FormFilter.setDim = function(w, h) {
  FormFilter.curWidth = w;
  FormFilter.curHeight = h;
}

// Static method to set the filter display text
FormFilter.setDisplayText = function(dt) { 
  $(FormFilter.curParentID).value = dt;
  FormFilter.hideFilterPopup();
}

// Static method to set the popup inner html
FormFilter.setPopupInnerHTML = function(id, filterType, title, midContent, arrBtns) {
  var extraBtns = "";
  
  var numBtns = arrBtns.length;
  for (var i=0; i<numBtns; i++) {
    var ht = arrBtns[i];
    extraBtns += '<div class="btn" style="float: right;" onclick="' + ht.js + '">' + ht.n + '</div>';
  }

  var buttonContent = '<div class="btn" onclick="FormFilter.clearFilter(\'' + filterType + '\')">Clear</div>' +
                      extraBtns +  
                      '<div class="btn" style="float: right;" onclick="FormFilter.cancelChanges()">Cancel</div>';

  var innerHTML = '<div class="splFltTop">' + title + '</div>' +
                  '<div class="splFltMiddle">' + midContent + '</div>' +
                  '<div class="splFltBottom">' + buttonContent + '</div>';

//  var innerHTML = midContent;

  FormFilter.showFilterPopup(id, innerHTML);

  $(FormFilter.FILTER_DIV_ID).style.width = FormFilter.curWidth + "px";
  $(FormFilter.FILTER_DIV_ID).style.height = FormFilter.curHeight + "px";
}

// Static method to show the popup filter
FormFilter.showFilterPopup = function(id, innerHTML) {
  var tf = $(id);
  var popupDiv = $(FormFilter.FILTER_DIV_ID);

  FormFilter.curParentID = id;

  if (popupDiv == null) {
    popupDiv = document.createElement('div');
    popupDiv.setAttribute('id', FormFilter.FILTER_DIV_ID);
    popupDiv.style.display = 'none';
    document.body.appendChild(popupDiv);
  }

  var coords = $findPos(tf);

  var winPos = IBCSUtils.getWinPos();
  var popX = parseInt(coords.x+1+FormFilter.curWidth);
  var maxL = parseInt(winPos.w)

  var l = '';
  var t = '';
  if (popX < maxL) {
    l = coords.x + 1;
    t = coords.y + coords.h;
  } else {
    l = coords.x + coords.w - 1 - FormFilter.curWidth;
    t = coords.y + coords.h;
  }

  popupDiv.style.left = l + "px";
  popupDiv.style.top = t + "px";

  popupDiv.innerHTML = innerHTML;
  popupDiv.style.display = 'block';

  return true;
}

/////////////////////////////////////////////////////////////////////////////////////
// Date filter functions

FormFilter.buildCalendar = function(startEnd) {
  var c = FormFilter.buildCalHeader(startEnd);
  for (var i=0; i<=5; i++) {
    c += '<tr class="calDay">';
    for (var j=1; j<=7; j++) {
      var k = 7*i+j;
      c += '<td id="cal' + startEnd + k + '" onclick="FormFilter.changeDate(\'ID-' + k + '\',\'' + startEnd + '\')">&nbsp;</td>';
    }
    c += '</tr>';
  }

  var btns = '<div class="btn" onclick="FormFilter.changeDate(\'clear\',\'' + startEnd + '\')">Clear</div>' +
             '<div class="btn" style="float: right;" onclick="FormFilter.changeDate(\'today\',\'' + startEnd + '\')">Today</div>' +
             '<div class="btn" style="float: right;" onclick="FormFilter.changeDate(\'yesterday\',\'' + startEnd + '\')">Yesterday</div>';
  c += '<tr class="calBtns"><th colspan=7>' + btns + '</th></tr>' +
       '</table>';
  return c;
}

FormFilter.buildCalHeader = function(startEnd) {
  var btns = '<div class="btn" onclick="FormFilter.changeDate(\'prevMonth\',\'' + startEnd + '\')">Prev</div>' +
             '<div class="btn" onclick="FormFilter.changeDate(\'nextMonth\',\'' + startEnd + '\')">Next</div>';

  var title = '';
  if (startEnd == 'Start') {
    title = 'Start Date';
  } else if (startEnd == 'End') {
    title = 'End Date';
  }

  var calHeader = '<table class="calSmlTbl" id="Cal' + startEnd + '">' +
                  '<tr><th colspan=7 height=25 align=left>' + title + '</th></tr>' +
                  '<tr class="calTop"><th colspan=7>' + btns + '<span id="CalMonth' + startEnd + 'Disp" style="float:right;">CurMonth</span></th></tr>' +
                  '<tr class="dayHd"><th width="15%">S</th><th width="14%">M</th><th width="14%">T</th><th width="14%">W</th><th width="14%">T</th><th width="14%">F</th><th width="15%">S</th></tr>';
  return calHeader;
}

// Static method to show the next month
FormFilter.changeDate = function(newDate, startEnd) {

  var calCfg = FormFilter.htFilterInfo.get(FormFilter.curParentID);

  var cellID = "";

  var nd = "";
  var nm = "";
  var ny = "";

  if (/^ID-/.test(newDate)) {
    cellID = newDate.substr(3);  
    newDate = 'diffDay';
  }

  // We only need the current date when changing to new/prev month
  if (newDate == 'diffDay' || newDate == 'clear' || newDate == 'nextMonth' || newDate == 'prevMonth') {
    var d = "";
    var m = "";
    var y = "";

    if (startEnd == 'Start') {
      d = calCfg.sd;
      m = calCfg.sm;
      y = calCfg.sy;
    } else if (startEnd == 'End') {
      d = calCfg.ed;
      m = calCfg.em;
      y = calCfg.ey;
    } else {
      return;
    }

    d = ""+d;
    d = d.replace(/^0/, "");
    d = parseInt(d);

    m = ""+m;
    m = m.replace(/^0/, "");
    m = parseInt(m);

    y = parseInt(y);

    nd = d;
    nm = m;
    ny = y;

  }

  switch(newDate) {
    case 'clear':
      nd = 0;
      break;
    case 'diffDay':
      nd = $('cal' + startEnd + cellID).innerHTML;
      if (nd == '&nbsp;') {
        nd = 0;
      }
      break;
    case 'today':
      var dt = new Date();
      nd = dt.getDate();
      nm = dt.getMonth()+1;
      ny = dt.getFullYear();
      break;
    case 'yesterday':
      var dt = new Date();
      nd = dt.getDate();
      nm = dt.getMonth()+1;
      ny = dt.getFullYear();
      break;
    case 'nextMonth':
      if (m == 12) {
        nm = 1;
        ny = y + 1;
      } else {
        nm = m+1;
      }
      break;
    case 'prevMonth':
      if (m == 1) {
        nm = 12;
        ny = y - 1;
      } else {
        nm = m-1;
      }
      break;
  }

  nd = $zeroPad(nd);
  nm = $zeroPad(nm);

  if (startEnd == 'Start') {
    calCfg.sd = nd;
    calCfg.sm = nm;
    calCfg.sy = ny;
  } else if (startEnd == 'End') {
    calCfg.ed = nd;
    calCfg.em = nm;
    calCfg.ey = ny;
  }

  FormFilter.htFilterInfo.put(FormFilter.curParentID, calCfg)
  FormFilter.initDateSelector(startEnd);
}

// Static mehod to clear the data
FormFilter.clearData = function() {
  $(FormFilter.curParentID).value = "";
  FormFilter.hideFilterPopup();
}

// Static method to get the date range value
FormFilter.getDateRangeValue = function(id) {
  var dispText = $(id).value;
  if (dispText == "") {
    return "";
  }

  var retVal = "";

  var s = FormFilter.htFilterInfo.get(id);

  var dtRngType = s.dtRngType;

  var sd = s.sd;
  var sm = s.sm;
  var sy = s.sy;
  var start = "" + sy + sm + sd;

  var ed = s.ed;
  var em = s.em;
  var ey = s.ey;
  var end = "" + ey + em + ed;

  switch(dtRngType) {
    case 'eq':
      retVal = "eq|" + start;
      break;
    case 'ge':
      retVal = "ge|" + start;
      break;
    case 'le':
      retVal = "le|" + end;
      break;
    case 'rg':
      retVal = "rg|" + start + "," + end;
      break;
  }
  retVal = encodeURIComponent(retVal);
  return retVal;
}

// Static method to initialize the date range filter
FormFilter.initDateRangeFilter = function() {
  var tf = $(FormFilter.curParentID);
  var text = tf.value;

  var dtRngType = "";
  var queryStr = "";
  var arrInfo = text.split("|");
  var numParts = arrInfo.length;
  if (numParts==1) {
    queryStr = text;
  } else {
    dtRngType = arrInfo[0];
    queryStr = arrInfo[1];
  }

  queryStr = dtRngType + queryStr;

  var dispText = "";

  var startDay = "00";
  var startMonth = "00";
  var startYear = "0000";

  var endDay = "00";
  var endMonth = "00";
  var endYear = "0000";

  var arrDate;

  // String is empty
  var isEmpty = FormFilter.isEmpty(queryStr);
  if (isEmpty) {
    var dt = new Date();
    startMonth = $zeroPad(dt.getMonth()+1);
    startYear = dt.getFullYear();
    endMonth = startMonth;
    endYear = startYear;
  } else {

    // String is a date (yyyy/mm/dd)
    arrDate = FormFilter.isDateYYYYMMDD(queryStr);
    if (arrDate != null) {
      dtRngType = 'eq';
      startDay = arrDate[3];
      startMonth = arrDate[2];
      startYear = arrDate[1];
      endMonth = startMonth;
      endYear = startYear;
      dispText = startYear + "/" + startMonth + "/" + startDay;
    } else {

      // String is greater equals
      arrDate = FormFilter.isDateYYYYMMDDGreaterEquals(queryStr);
      if (arrDate != null) {
        dtRngType = 'ge';
        startDay = arrDate[3];
        startMonth = arrDate[2];
        startYear = arrDate[1];
        endMonth = startMonth;
        endYear = startYear;
        dispText = ">=" + startYear + "/" + startMonth + "/" + startDay;
      } else {

        // String is less equals 
        arrDate = FormFilter.isDateYYYYMMDDLessEquals(queryStr);
        if (arrDate != null) {
          dtRngType = 'le';
          endDay = arrDate[3];
          endMonth = arrDate[2];
          endYear = arrDate[1];
          startMonth = endMonth;
          startYear = endYear;
          dispText = "<=" + endYear + "/" + endMonth + "/" + endDay;

        } else {

          // String is date range
          var arrDateRange = FormFilter.isDateRange(queryStr);
          if (arrDateRange != null) {
            dtRngType = 'rg';
            startDay = arrDateRange[3];
            startMonth = arrDateRange[2];
            startYear = arrDateRange[1];
            endDay = arrDateRange[6];
            endMonth = arrDateRange[5];
            endYear = arrDateRange[4];
            dispText = startYear + "/" + startMonth + "/" + startDay + " - " + endYear + "/" + endMonth + "/" + startDay;
          }
        }
      }
    }
  }

  var settings = {'dtRngType':dtRngType,'sd':startDay,'sm':startMonth,'sy':startYear,'ed':endDay,'em':endMonth,'ey':endYear};
  FormFilter.htFilterInfo.put(FormFilter.curParentID, settings);
  FormFilter.setDisplayText(dispText);
}

// Static method to init the date selector with the current month
FormFilter.initDateSelector = function(startEnd) {
  var monthDisp = $('CalMonth' + startEnd + 'Disp');

  var tf = $(FormFilter.curParentID);
  var tfVal = tf.value;

  var calCfg = FormFilter.htFilterInfo.get(FormFilter.curParentID);

  var d = "";
  var m = "";
  var y = "";

  if (startEnd == 'Start') {
    d = calCfg.sd;
    m = calCfg.sm;
    y = calCfg.sy;
 
  } else if (startEnd == 'End') {
    d = calCfg.ed;
    m = calCfg.em;
    y= calCfg.ey;

  } else {
    return;
  }

  y = parseInt(y);

  m = ""+m;
  m = m.replace(/^0/, "");
  m = parseInt(m);
  m -= 1;

  d = ""+d;
  d = d.replace(/^0/, "");
  d = parseInt(d);

  var dt = new Date();
  dt.setDate(1);
  dt.setMonth(m);
  dt.setFullYear(y);

  var thisMonth = dt.format("mmm yyyy");
  monthDisp.innerHTML = thisMonth;

  var thisDOW = dt.format("ddd");

  var initInd = 0;
  switch(thisDOW) {
    case 'Sun':
      initInd = 1;
      break;
    case 'Mon':
      initInd = 2;
      break;
    case 'Tue':
      initInd = 3;
      break;
    case 'Wed':
      initInd = 4;
      break;
    case 'Thu':
      initInd = 5;
      break;
    case 'Fri':
      initInd = 6;
      break;
    case 'Sat':
      initInd = 7;
      break;
  }

  var dy = 0;
  for (var i=1; i<=42; i++) {
    var cd = $('cal'+startEnd+i);
    var t = "&nbsp;";
    if (i>=initInd) {
      dy += 1;

      // Add 1 to the cal's date and if the month is still this month then its ok
      dt.setDate(dy);
      var newMonth = dt.format("mmm yyyy");
      if (newMonth == thisMonth) {
        t  = dy;
      }
    }

    var cls = null;
    if (d != 0 && dy == d) {
      cls = 'today';
    }
    cd.className = cls;
    cd.innerHTML = t;
  }
}

// Static method to save calendar date changes
FormFilter.saveDateRangeFilterChanges = function() {
  var calCfg = FormFilter.htFilterInfo.get(FormFilter.curParentID);

  var errors = "";

  var dtRngType = $getRBVal('dtRngType');

  var sd = calCfg.sd;
  var sm = calCfg.sm;
  var sy = calCfg.sy;
  var start = "" + sy + "/" + sm + "/" + sd;

  var ed = calCfg.ed;
  var em = calCfg.em;
  var ey = calCfg.ey;
  var end = "" + ey + "/" + em + "/" + ed;

  var dt = "";

//  alert("saveDateRange, t: " + dtRngType + ", sd: " + start);

  switch(dtRngType) {
    case 'eq':
      if (sd == '00') {
        errors += "Please enter a 'Start Date'!\n";
      } else {
        dt = start;
      }
      break;
    case 'ge':
      if (sd == '00') {
        errors += "Please enter a 'Start Date'!\n";
      } else {
        dt = ">=" + start;
      }
      break;
    case 'le':
      if (ed == '00') {
        errors += "Please enter an 'End Date'!\n";
      } else {
        dt = "<=" + end;
      }
      break;
    case 'rg':
      var p = true;
      if (sd == '00') {
        errors += "Please enter a 'Start Date'!\n";
        p = false;
      }
      if (ed == '00') {
        errors += "Please enter an 'End Date'!\n";
        p = false;
      }
      if (p) {
        var startDateTest = "" + parseInt("" + sy + sm + sd);
        var endDateTest = parseInt("" + ey + em + ed);
        if (startDateTest>=endDateTest) {
          errors += "'Start Date' should be less than 'End Date'!\n";
        } else {
          dt = start + " - " + end;
        }
      }
      break;
    default:
      errors += "Please enter a 'Search Type'!\n";
      break;
  }

  if (errors != "") {
    alert(errors);
    return;
  }

  calCfg.dtRngType = dtRngType;
  FormFilter.htFilterInfo.put(FormFilter.curParentID, calCfg);
  FormFilter.setDisplayText(dt);
}

// Static method called when the user changes the date range type
FormFilter.changeDateRangeType = function(o) {
  var s = FormFilter.htFilterInfo.get(FormFilter.curParentID);
  s.dtRngType = o.value;
  FormFilter.htFilterInfo.put(FormFilter.curParentID, s);

  var dtRngType = s.dtRngType;
  FormFilter.setDateRangeVisibility(dtRngType);
}

// Static method to change the date range calendar visibility
FormFilter.setDateRangeVisibility = function(dtRngType) {
  switch(dtRngType) {
    case 'eq':
    case 'ge':
      $('CalEnd').style.visibility = 'hidden';
      $('CalStart').style.visibility = 'visible';
      break;
    case 'le':
      $('CalStart').style.visibility = 'hidden';
      $('CalEnd').style.visibility = 'visible';
      break;
    case 'rg':
      $('CalStart').style.visibility = 'visible';
      $('CalEnd').style.visibility = 'visible';
      break;
  }
}

// Static method to display a date range filter
FormFilter.showDateRangeFilter = function(id) {
  var tf = $(id);

  var title = "Date Range Filter";

  var isSame = FormFilter.checkPopup(id);
  if (isSame) {
    return;
  }

  FormFilter.curParentID = id;

  var s = FormFilter.htFilterInfo.get(id);
  if (s == null) {
    FormFilter.initDateRangeFilter();
    s = FormFilter.htFilterInfo.get(id);
  }

  var dtRngType = s.dtRngType;

  var checkEquals = "";
  var checkGreaterEqual = "";
  var checkLessEqual = "";
  var checkRange = "";

  switch(dtRngType) {
    case 'eq':
      checkEquals = ' checked ';
      break;
    case 'ge':
      checkGreaterEqual = ' checked ';
      break;
    case 'le':
      checkLessEqual = ' checked ';
      break;
    case 'rg':
      checkRange = ' checked ';
      break;
    default:
      checkEquals = ' checked ';
      break;
  }

  var radios = "";

  var btns = new Array(
{'v':'eq',lt:'Equals','chk':checkEquals},
{'v':'ge',lt:'Greater/=','chk':checkGreaterEqual},
{'v':'le',lt:'Less/=','chk':checkLessEqual},
{'v':'rg',lt:'Range','chk':checkRange}
);

  radios += IBCSUtils.mkRdBtnGrp({'n':'dtRngType','b':btns,'onc':'FormFilter.changeDateRangeType(this)'});

  var inTbl = '<table class="stdTbl" width=100%>' +
              '<tr class="w"><td width=1%><b>QueryType:</b></td><td>' + radios + '</td></tr>' +
              '</table><br>';

  var midContent = "";

  var calStart = FormFilter.buildCalendar('Start');
  var calEnd = FormFilter.buildCalendar('End');

  midContent += inTbl + calStart + calEnd;

  var arrBtns = new Array(
{'n':'OK','js':'FormFilter.saveDateRangeFilterChanges()'}
);

  FormFilter.setDim(FormFilter.DATE_RANGE_FILTER_WIDTH, FormFilter.DATE_RANGE_FILTER_HEIGHT);
  FormFilter.setPopupInnerHTML(id, FormFilter.FILTER_TYPE_DATE_RANGE, title, midContent, arrBtns);
  FormFilter.initDateSelector('Start');
  FormFilter.initDateSelector('End');
  FormFilter.setDateRangeVisibility(dtRngType);
}

/////////////////////////////////////////////////////////////////////////////////////
// Multi Select filter functions

// Static method to cache a multiple select filter
FormFilter.cacheMultiSelectFilter = function(qryType, htChecked, showErrors) {
  var errors = "";
  var dt = "";

  switch(qryType) {
    case 'eq':
    case 'ne':
      break;
    default:
      errors += "You must select a Query Type!\n";
  }

  var htItems = FormFilter.htSelectInfo.get(FormFilter.curParentID);

  var numLines = 0;
  var numItems = htChecked.size();
  if (numItems>1) {
    dt = numItems + " items";
    numLines = numItems;
  } else {
    for (var k in htChecked.hash) {
      var val = htChecked.get(k);
      if (val==null) {
        continue;
      }
      var disp = htItems.get(k);
      if (disp != null) {
        dt = disp;
      }
      numLines++;
    }
  }

  if (numLines == 0) {
    errors += "You must select one or more items!\n";
  }

  if (showErrors && errors != "") {
    alert(errors);
    return;
  }
  
  var settings = {'qryType':qryType,'htChecked':htChecked};
  FormFilter.htFilterInfo.put(FormFilter.curParentID, settings);
  FormFilter.setDisplayText(dt);
}

// Static method to get the multi select value
FormFilter.getMultiSelectValue = function(id) {
  var dispText = $(id).value;
  if (dispText == "") {
    return "";
  }

  var s = FormFilter.htFilterInfo.get(id);
  var qryType = s.qryType;
  var htChecked = s.htChecked;

  var t = qryType+"|";
  t = encodeURIComponent(t);
  for (var f in htChecked.hash) {
    var b = htChecked.get(f);
    if (b==null) {
      continue;
    }
    t += encodeURIComponent(f) + ",";
  }
  t =  t.substr(0,t.length-1);

  return t;
}

// Static method to get the multi select value
FormFilter.getMultiSelectValueForObj = function(id) {
  var dispText = $(id).value;
  if (dispText == "") {
    return "";
  }

  var s = FormFilter.htFilterInfo.get(id);
  var qryType = s.qryType;
  var htChecked = s.htChecked;

  var t = "";
  t = encodeURIComponent(t);
  for (var f in htChecked.hash) {
    var b = htChecked.get(f);
    if (b==null) {
      continue;
    }
    t += f + ",";
  }
  t =  t.substr(0,t.length-1);

  return t;
}

// Static method to initialize a multi text filter
FormFilter.initMultiSelectFilter = function() {
  var tf = $(FormFilter.curParentID);
  var text = tf.value;

  var qryType = "";
  var qryStr = "";

  var arrInfo = text.split("|");
  var numParts = arrInfo.length;
  if (numParts==1) {
    qryType = 'eq';
    qryStr = text;
  } else {
    qryType = arrInfo[0];
    qryStr = arrInfo[1];
  }

  var htItems = new Hashtable();
  var htTemp = new Hashtable();
  var itemsText = $(FormFilter.curParentID+'SelHlder').innerHTML;
  var arrLines = itemsText.split("\n");
  for(var i=0; i<arrLines.length; i++) {
    var l = arrLines[i].trim();
    if (l == "") {
      continue;
    }
    var arrParts = l.split("|");
    var val = arrParts[0];
    var disp = arrParts[1];

    htItems.put(val, disp);
    htTemp.put(disp, val);
  }

  var htChecked = new Hashtable();
  var arrKeys = qryStr.split(",");
  var numKeys = arrKeys.length;
  for (var i=0; i<numKeys; i++) {
    var key = arrKeys[i].trim();
    if (key=="") {
      continue;
    }
    // Reverse disp to key
    if (!htItems.containsKey(key) && htTemp.containsKey(key)) {
      key = htTemp.get(key);
    }
    htChecked.put(key, key);
  }

  FormFilter.htSelectInfo.put(FormFilter.curParentID, htItems);

  FormFilter.cacheMultiSelectFilter(qryType, htChecked, false);
}

// Static method to save a multi select value
FormFilter.saveMultiSelectFilterChanges = function() {
  var qryType = $getRBVal('qryType');
  var s = FormFilter.htFilterInfo.get(FormFilter.curParentID);
  var htChecked = s.htChecked;

  FormFilter.cacheMultiSelectFilter(qryType, htChecked, true);
}

// Static method to display a multi text filter
FormFilter.showMultiSelectFilter = function(id) {

  var isSame = FormFilter.checkPopup(id);
  if (isSame) {
    return;
  }

  var s = FormFilter.htFilterInfo.get(id);
  
  var qryType = s.qryType;
  var htChecked = s.htChecked;

  var title = 'Select Filter';

  var checkEquals = "";
  var checkNotEquals = "";

  switch(qryType) {
    case 'eq':
      checkEquals = ' checked ';
      break;
    case 'ne':
      checkNotEquals = ' checked ';
      break;
  }

  var radios = "";

  var btns = new Array(
{'v':'eq',lt:'Equals','chk':checkEquals},
{'v':'ne',lt:'NotEquals','chk':checkNotEquals}
);

  radios += IBCSUtils.mkRdBtnGrp({'n':'qryType','b':btns});

  var itemsText = "";
  var htItems = FormFilter.htSelectInfo.get(id);
  for (var val in htItems.hash) {
    var disp = htItems.get(val);

    var cls = 'selectItemDiv';
    var defaultChk = false;
    if (htChecked.containsKey(val)) {
      cls = 'selectItemDivChk';
      defaultChk = true;
    }

    var cbid = "xoso"+val;
    var cfg = {'id':cbid,'text':disp,'value':val,'dis':'Y','defaultChk':defaultChk};
    var cb = $mkCB(cfg);

    itemsText += '<div class="' + cls + '" id="div' + cbid + '" onclick="FormFilter.changeSelectItem(\'' + cbid + '\')">' + cb + '</div>';
  }

  var midContent = '<table class="stdTbl" width=100%>' +
                   '<tr class="w"><td width=1%><b>QueryType:</b></td><td>' + radios + '</td></tr>' +
                   '</table>' + 
                   '<br><div class="filterSelectDiv">' + itemsText + '</div>';

  var arrBtns = new Array(
{'n':'OK','js':'FormFilter.saveMultiSelectFilterChanges()'}
);

  FormFilter.setDim(FormFilter.MULTI_SELECT_FILTER_WIDTH, FormFilter.MULTI_SELECT_FILTER_HEIGHT);
  FormFilter.setPopupInnerHTML(id, FormFilter.FILTER_TYPE_MULTI_SELECT, title, midContent, arrBtns);
}

FormFilter.changeSelectItem = function(id) {
  var s = FormFilter.htFilterInfo.get(FormFilter.curParentID);
  var htChecked = s.htChecked;

  var cb = $(id);
  var val = cb.value;
  var newChecked = !cb.checked;
  cb.checked = newChecked;
  var div = $("div"+id);
  var cls = 'selectItemDiv';
  if (newChecked==true) {
    cls = 'selectItemDivChk';
    htChecked.put(val, val);
  } else {
    htChecked.remove(val);
  }
  div.className = cls;
  s.htChecked = htChecked;
  FormFilter.htFilterInfo.put(FormFilter.curParentID, s);
}

/////////////////////////////////////////////////////////////////////////////////////
// Multi Text filter functions

FormFilter.cacheMultiTextFilter = function(txtFltType, text, notQuery, showErrors) {
  var errors = "";
  var dt = "";

  var leftStar = "";
  var rightStar = "";

  switch(txtFltType) {
    case 'eq':
      break;
    case 'lk':
      leftStar = "*";
      rightStar = "*";
      break;
    case 'lkl':
      leftStar = "*";
      break;
    case 'lkr':
      rightStar = "*";
      break;
    case 'em':
      break;
    default:
      errors += "You must select a Query Type!\n";
  }

  var fltTxt = "";
  var numLines = 0;
  var htLines = new Hashtable();
  var arrLines = text.split("\n");
  for(var i=0; i<arrLines.length; i++) {
    var l = arrLines[i].trim();
    if (l == "") {
      continue;
    }

    if (htLines.containsKey(l)) {
      continue;
    }

    numLines++;

    htLines.put(l, l);

    fltTxt += l + "\n";
  }

  if (txtFltType == 'em') {
    dt = 'Empty';
  } else {
    if (numLines == 0) {
      errors += "You must enter some text!\n";
    } else if (numLines<2) {
      var dt = fltTxt.trim();
    } else {
      var dt = numLines + " items";
    }
  }

  if (dt != "") {
    if (leftStar != "") {
      dt = leftStar + dt;
    }
    if (rightStar != "") {
      dt += rightStar;
    }
  }

  if (showErrors && errors != "") {
    alert(errors);
    return;
  }

  var settings = {'txtFltType':txtFltType,'htLines':htLines,'notQuery':notQuery};
  FormFilter.htFilterInfo.put(FormFilter.curParentID, settings);
  FormFilter.setDisplayText(dt);
}

// Static method to get the multi text value
FormFilter.getMultiTextValue = function(id) {
  var dispText = $(id).value;
  if (dispText == "") {
    return "";
  }

  var s = FormFilter.htFilterInfo.get(id);
  var txtFltType = s.txtFltType;
  var htLines = s.htLines;

  var t = txtFltType+"|";
  t = encodeURIComponent(t);
  for (var f in htLines.hash) {
    t += encodeURIComponent(f) + ",";
  }
  t =  t.substr(0,t.length-1);

  return t;
}

// Static method to save a multi text value
FormFilter.saveMultiTextFilterChanges = function() {
  var text = $('fltMltTxt').value;
  var txtFltType = $getRBVal('txtFltType');
  var notQuery = "";
  FormFilter.cacheMultiTextFilter(txtFltType, text, notQuery, true);
}

// Static method to initialize a multi text filter
FormFilter.initMultiTextFilter = function() {
  var tf = $(FormFilter.curParentID);
  var text = tf.value;

  var notQuery = "";
  var txtFltType = "";
  var queryStr = ""; 
  var arrInfo = text.split("|");
  var numParts = arrInfo.length;
  if (numParts==1) {
    txtFltType = 'eq';
    queryStr = text;

    if (queryStr != "") {
      var isEquals = FormFilter.isTextEquals(queryStr);
      if (isEquals != null) {
        queryStr = isEquals;
        txtFltType = 'eq';
      } else {
        var isLike = FormFilter.isTextLike(queryStr);
        if (isLike != null) {
          queryStr = isLike;
          txtFltType = 'lk';
        } else {
          var isLikeRight = FormFilter.isTextLikeRight(queryStr);
          if (isLikeRight != null) {
            queryStr = isLikeRight;
            txtFltType = 'lkr';
          } else {
            var isLikeLeft = FormFilter.isTextLikeLeft(queryStr);
            if (isLikeLeft != null) {
              queryStr = isLikeLeft;
              txtFltType = 'lkl';
            }
          }
        }
      }
    }
  } else {
    txtFltType = arrInfo[0];
    queryStr = arrInfo[1];
  }

  var fltTxt = "";
  var htLines = new Hashtable();

  var arrLines = queryStr.split(",");
  for(var i=0; i<arrLines.length; i++) {
    var l = arrLines[i].trim();
    if (l == "") {
      continue;
    }

    if (htLines.containsKey(l)) {
      continue;
    }

    htLines.put(l, l);

    fltTxt += l + "\n";
  }

  FormFilter.cacheMultiTextFilter(txtFltType, fltTxt, notQuery, false);
}

// Static method to display a multi text filter
FormFilter.showMultiTextFilter = function(id) {

  var isSame = FormFilter.checkPopup(id);
  if (isSame) {
    return;
  }

  var taStuff = '';

  var s = FormFilter.htFilterInfo.get(id);
  var htLines = s.htLines;
  var txtFltType = s.txtFltType;

  var arrSort = new Array();
  var i = 0;
  for (var l in htLines.hash) {
    arrSort[i] = l;
    i++;
  }

  arrSort.sort();
  taStuff = arrSort.join('\n');

  var title = 'Text Filter';

  var checkEquals = "";
  var checkLike = "";
  var checkLikeLeft = "";
  var checkLikeRight = "";
  var checkEmpty = "";

  switch(txtFltType) {
    case 'eq':
      checkEquals = ' checked ';
      break;
    case 'lk':
      checkLike = ' checked ';
      break;
    case 'lkr':
      checkLikeRight = ' checked ';
      break;
    case 'lkl':
      checkLikeLeft = ' checked ';
      break;
    case 'em':
      checkEmpty = ' checked ';
      break;
    default:
      checkEquals = ' checked ';
      break;
  }

  var radios = "";

  var btns = new Array(
{'v':'eq',lt:'Equals','chk':checkEquals},
{'v':'lk',lt:'<font color=red>*</font>Like<font color=red>*</font>','chk':checkLike},
{'v':'lkr',lt:'Like<font color=red>*</font>','chk':checkLikeRight},
{'v':'lkl',lt:'<font color=red>*</font>Like','chk':checkLikeLeft},
{'v':'em',lt:'Empty','chk':checkEmpty}
);

  radios += IBCSUtils.mkRdBtnGrp({'n':'txtFltType','b':btns});

  var midContent = '<table class="stdTbl" width=100%>' +
                   '<tr class="w"><td width=1%><b>QueryType:</b></td><td>' + radios + '</td></tr>' +
                   '<tr class="w" valign=top><td colspan=2><b>Search Strings</b> <span class="infoMesg">(separate w \\n)</span></td></tr>' +
                   '<tr class="w" valign=top><td colspan=2><textarea id="fltMltTxt" class="smlTxtFldNew" rows="12" cols="5" wrap="virtual">' + taStuff + '</textarea></td></tr>' +
                   '</table>';

  var arrBtns = new Array(
{'n':'OK','js':'FormFilter.saveMultiTextFilterChanges()'}
);

  FormFilter.setDim(FormFilter.MULTI_TEXT_FILTER_WIDTH, FormFilter.MULTI_TEXT_FILTER_HEIGHT);
  FormFilter.setPopupInnerHTML(id, FormFilter.FILTER_TYPE_MULTI_TEXT, title, midContent, arrBtns);
  $('fltMltTxt').focus();
}

/////////////////////////////////////////////////////////////////////////////////////
// Numeric Range Text filter functions

// Static method called when the user changes the numeric range type
FormFilter.changeNumericRangeType = function(o) {
  var s = FormFilter.htFilterInfo.get(FormFilter.curParentID);
  var numRngType = o.value;
  s.numRngType = numRngType;
  FormFilter.htFilterInfo.put(FormFilter.curParentID, s);

  FormFilter.setNumericRangeVisibility(numRngType);
}

// Static method to change the numeric range visibility
FormFilter.setNumericRangeVisibility = function(numRngType) {
  var nr1 = $('numRng1');
  var nr2 = $('numRng2');

  switch(numRngType) {
    case 'eq':
    case 'g':
    case 'ge':
      nr2.style.visibility = 'hidden';
      nr1.style.visibility = 'visible';
      break;
    case 'l':
    case 'le':
      nr1.style.visibility = 'hidden';
      nr2.style.visibility = 'visible';
      break;
    case 'rge':
    case 'rgi':
      nr1.style.visibility = 'visible';
      nr2.style.visibility = 'visible';
      break;
  }
}

// Static method to check a numeric range filter
FormFilter.checkRangeFilter = function(tf) {
  var id = tf.id;

  switch(id) {
    case FormFilter.RANGE_TYPE_SRC_EQUALS:
      FormFilter.clearRangeFilters();
      break;
    case FormFilter.RANGE_TYPE_SRC_GREATER_THAN:
      FormFilter.clearEqualFilter();
      FormFilter.switchRangeFilter(id, FormFilter.RANGE_TYPE_SRC_GREATER_EQUAL_THAN);
      break;
    case FormFilter.RANGE_TYPE_SRC_GREATER_EQUAL_THAN:
      FormFilter.clearEqualFilter();
      FormFilter.switchRangeFilter(id, FormFilter.RANGE_TYPE_SRC_GREATER_THAN);
      break;
    case FormFilter.RANGE_TYPE_SRC_LESS_THAN:
      FormFilter.clearEqualFilter();
      FormFilter.switchRangeFilter(id, FormFilter.RANGE_TYPE_SRC_LESS_EQUAL_THAN);
      break;
    case FormFilter.RANGE_TYPE_SRC_LESS_EQUAL_THAN:
      FormFilter.clearEqualFilter();
      FormFilter.switchRangeFilter(id, FormFilter.RANGE_TYPE_SRC_LESS_THAN);
      break;
  } 
}

// Static method to clear the equal filter
FormFilter.clearEqualFilter = function() {
  $('eqOrRngRng').checked = true;
  $(FormFilter.RANGE_TYPE_SRC_EQUALS).value = '';
}

// Static method to clear the range filters
FormFilter.clearRangeFilters = function() {
  $('eqOrRngEq').checked = true; 
  $(FormFilter.RANGE_TYPE_SRC_GREATER_THAN).value = '';
  $(FormFilter.RANGE_TYPE_SRC_GREATER_EQUAL_THAN).value = '';
  $(FormFilter.RANGE_TYPE_SRC_LESS_THAN).value = '';
  $(FormFilter.RANGE_TYPE_SRC_LESS_EQUAL_THAN).value = '';
}

// Static method to get the numeric range value
FormFilter.getNumericRangeValue = function(id) {
  var dispText = $(id).value;
  if (dispText == "") {
    return "";
  }

  var s = FormFilter.htFilterInfo.get(id);

  var mult = s.mult;
  var numRng1 = s.numRng1;
  var numRng2 = s.numRng2;
  var numRngType = s.numRngType;

  var t = numRngType;
  if (mult != "") {
    t += "|" + mult;
  }
  t += "|";
  if (numRng1 != "" && numRng2 != "") {
    t += numRng1 + "," + numRng2;
  } else if (numRng1 != "") {
    t += numRng1;
  } else if (numRng2 != "") {
    t += numRng2;
  }

  t = encodeURIComponent(t);
 
  return t;
}

// Static method to initialize a numeric range filter
FormFilter.initNumericRangeFilter = function() {
  var tf = $(FormFilter.curParentID);
  var text = tf.value;

  var queryStr = "";

  var mult = "";
  var numRng1 = "";
  var numRng2 = "";
  var numRngType = "eq";

  var arrInfo = text.split("|");
  var numParts = arrInfo.length;
  switch(numParts) {
    case 1:
      queryStr = arrInfo[0];
      break;
    case 2:
      numRngType = arrInfo[0];
      queryStr = arrInfo[1];
      break;
    case 3:
      numRngType = arrInfo[0];
      mult = arrInfo[1];
      queryStr = arrInfo[2];
      break;
  }

  switch(numRngType) {
    case 'eq':
    case 'g':
    case 'ge':
      numRng1 = queryStr;
      break;

    case 'l':
    case 'le':
      numRng2 = queryStr;
      break;

    case 'rgi':
    case 'rge':
      var arrRng = queryStr.split(",");
      var np = arrRng.length;
      if (np==1) {
        numRng1 = arrRng[0];
      } else {
        numRng1 = arrRng[0];
        numRng2 = arrRng[1];
      }
      break;
  }

  FormFilter.cacheNumericRangeFilter(numRngType, numRng1, numRng2, mult, false);
}

// Static method to cache a numeric range filter
FormFilter.cacheNumericRangeFilter = function(numRngType, numRng1, numRng2, mult, showErrors) {
  var errors = "";

  if (mult != "" && mult != "K" && mult != "M" && mult != "B") {
    mult = "";
  }

  var preL = "";
  var preR = "";

  switch(numRngType) {
    case 'eq':
      preL = "=";
      break;

    case 'g':
      preL = ">";
      break;

    case 'ge':
      preL = ">=";
      break;

    case 'l':
      preL = "<";
      break;

    case 'le':
      preL = "<=";
      break;

    case 'rgi':
      preL = ">=";
      preR = "<=";
      break;

    case 'rge':
      preL = ">";
      preR = "<";
      break;
      
    default:
      numRngType = 'eq';
      preL = "=";
      break;
  }

  var dt = "";

  if (numRng1 != "" || numRng2 != "") {
    switch(numRngType) {
      case 'eq':
      case 'g':
      case 'ge':
        errors += FormFilter.checkNumeric('Value 1', numRng1);
        dt += preL + numRng1 + mult;
        break;
      case 'l':
      case 'le':
        errors += FormFilter.checkNumeric('Value 2', numRng2);
        dt += preL + numRng2 + mult;
        break;
      case 'rgi':
      case 'rge':
        errors += FormFilter.checkNumericRange('Value 1', 'Value 2', numRng1, numRng2);
        dt += preL + numRng1 + mult + " AND " + preR + numRng2 + mult;
        break;

      default:
        errors += "You must select a QueryType!\n";
        break;
    }
  }

  if (showErrors && errors != "") {
    alert(errors);
    return;
  }

  var settings = {'numRngType':numRngType,'numRng1':numRng1,'numRng2':numRng2,'mult':mult};
  FormFilter.htFilterInfo.put(FormFilter.curParentID, settings);
  FormFilter.setDisplayText(dt);
}

// Static method to save the changes to a numeric filter
FormFilter.saveNumericRangeFilterChanges = function() {

  var numRngType = $getRBVal('numRngType');
  var numRng1 = $('numRng1').value;
  var numRng2 = $('numRng2').value;
  var mult = $('numRangeMult').value;

  FormFilter.cacheNumericRangeFilter(numRngType, numRng1, numRng2, mult, true);
}

// Static method to display a numeric range filter
FormFilter.showNumericRangeFilter = function(id) {

  var isSame = FormFilter.checkPopup(id);
  if (isSame) {
    return;
  }

  FormFilter.curParentID = id;

  var s = FormFilter.htFilterInfo.get(id);
  if (s == null) {
    FormFilter.initNumericRangeFilter();
    s = FormFilter.htFilterInfo.get(id);
  }

  var mult = s.mult;
  var numRng1 = s.numRng1;
  var numRng2 = s.numRng2;
  var numRngType = s.numRngType;

  var checkEquals = '';
  var checkGreater = '';
  var checkGreaterEquals = '';
  var checkLess = '';
  var checkLessEquals = '';
  var checkRangeIncl = '';
  var checkRangeExcl = '';

  var title = 'Numeric Range Filter';

  switch(numRngType) {
    case 'eq':
      checkEquals = ' checked ';
      break;
    case 'g':
      checkGreater = ' checked ';
      break;
    case 'ge':
      checkGreaterEquals = ' checked ';
      break;
    case 'l':
      checkLess = ' checked ';
      break;
    case 'le':
      checkLessEquals = ' checked ';
      break;
    case 'rgi':
      checkRangeIncl = ' checked ';
      break;
    case 'rge':
      checkRangeExcl = ' checked ';
      break;
  }

  var radios = "";
  
  var btns = new Array(
{'v':'eq',lt:'Equals(=)','chk':checkEquals},
{'v':'g',lt:'Greater(>)','chk':checkGreater},
{'v':'ge',lt:'GreaterEqual(>=)','chk':checkGreaterEquals},
{'v':'l',lt:'Less(<)','chk':checkLess},
{'v':'le',lt:'LessEqual(<=)','chk':checkLessEquals},
{'v':'rgi',lt:'RangeInclusive(>= AND <=)','chk':checkRangeIncl},
{'v':'rge',lt:'RangeExclusive(> AND <)','chk':checkRangeExcl}
);
        
  radios += IBCSUtils.mkRdBtnGrp({'n':'numRngType','b':btns,'onc':'FormFilter.changeNumericRangeType(this)'});

  var selInfo = '<select name="numRangeMult" id="numRangeMult" class="smlTxtFld">';
  for (var k in FormFilter.htNumRangeMult.hash) {
    var t = FormFilter.htNumRangeMult.get(k);
    var sel = '';
    if (k == mult) {
      sel = ' selected  ';
    }
    selInfo += '<option value="' + k + '"' + sel + '>' + t;
  }
  selInfo += '</select>';

  var midContent = '<table class="stdTbl" width=100%>' + 
                   '<tr class="w" valign=top><td width=1%><b>QueryType:</b></td><td>' + radios + '</td></tr>' +
                   '<tr class="w" valign=top><td<b>Multplier:</b></td><td>' + selInfo + '</td></tr>' +
                   '<tr class="w" valign=top><td<b>Value(s):</b></td><td>' +
		   '<input type="text" class="smlTxtFldNew" id="numRng1" value="' + numRng1 + '"><br><br>' + 
                   '<input type="text" class="smlTxtFldNew" id="numRng2" value="' + numRng2 + '">' + 
		   '</td></tr>' +
                   '</table>';

  var arrBtns = new Array(
{'n':'OK','js':'FormFilter.saveNumericRangeFilterChanges()'}
);

  FormFilter.setDim(FormFilter.NUMERIC_RANGE_FILTER_WIDTH, FormFilter.NUMERIC_RANGE_FILTER_HEIGHT);
  FormFilter.setPopupInnerHTML(id, FormFilter.FILTER_TYPE_NUMERIC_RANGE, title, midContent, arrBtns);
  FormFilter.setNumericRangeVisibility(numRngType);
}

// Static method to switch the value between two text fields
FormFilter.switchRangeFilter = function(newID, oldID) {
  var newField = $(newID);
  var oldField = $(oldID);

  if (oldField.value != '') {
    newField.value = oldField.value;
  } 
  oldField.value = '';
}

/////////////////////////////////////////////////////////////////////////////////////
// Form Validation functions

// Validation
FormFilter.addError = function(validated, errorText) {
  if (validated) {
    return "";
  }
  return errorText + "\n";
}

// Validate a string is numeric
// If not return an error message
FormFilter.checkNumeric = function(f, s) {
  var e = "";
  if (!FormFilter.isNumeric(s)) {
    e = "'" + f + "' must be a number!\n";
  }
  return e;
}

// Validate a numeric range has the first value less than the second
// If not return an error message
FormFilter.checkNumericRange = function(f1, f2, v1, v2) {
  var e = "";

  var t1 = FormFilter.isNumeric(v1);
  var t2 = FormFilter.isNumeric(v2);

  v1 = parseFloat(v1);
  v2 = parseFloat(v2);
  if (!t1 || !t2) {
    e = "'" + f1 + "' and '" + f2 + "' must be numbers!\n";
  } else {
    v1 = parseFloat(v1);
    v2 = parseFloat(v2);
    if (v1>=v2) {
      e = "'" + f1 + "' must be less than '" + f2 + "'!\n"; 
    }
  }
  return e;
}

// Validate is a date range like yyyy/mm/dd - yyyy/mm/dd
FormFilter.isDateRange = function(s) {
  var re = new RegExp("^(\\d{4})\/{0,1}(\\d{2})\/{0,1}(\\d{2})\\s*-\\s*(\\d{4})\/{0,1}(\\d{2})\/{0,1}(\\d{2})$");
  return re.exec(s);
}

// Validate is a date in yyyy/mm/dd format
FormFilter.isDateStartOrEnd = function(s) {
  var re = new RegExp("^([><]=) (\\d{4})\/{0,1}(\\d{2})\/{0,1}(\\d{2})$");
  return re.exec(s);
}

// Validate is a date in yyyy/mm/dd format
FormFilter.isDateYYYYMMDD = function(s) {
  var re = new RegExp("^(\\d{4})\/{0,1}(\\d{2})\/{0,1}(\\d{2})$");
  return re.exec(s);
}

// Validate is a date in yyyy/mm/dd format
FormFilter.isDateYYYYMMDDGreaterEquals = function(s) {
  var re = new RegExp("^>=(\\d{4})\/{0,1}(\\d{2})\/{0,1}(\\d{2})$");
  return re.exec(s);
}

// Validate is a date in yyyy/mm/dd format
FormFilter.isDateYYYYMMDDLessEquals = function(s) {
  var re = new RegExp("^<=(\\d{4})\/{0,1}(\\d{2})\/{0,1}(\\d{2})$");
  return re.exec(s);
}

// Validate if empty
FormFilter.isEmpty = function(s) {
  if (s == undefined || s == '') {
    return true;
  }
  return false;
}

// Validate if sel is empty
FormFilter.isSelEmpty = function(s) {
  if (s == undefined || s == '' || s == '0') {
    return true;
  }
  return false;
}

// Validate is an integer
FormFilter.isInt = function(s) {
  var re = /(^-?\d\d*$)/;
  return re.test(s);
}

// Validate is a number
FormFilter.isNumeric = function(s) {
  var re = new RegExp("(^-?\\d\\d*\.\\d*$)|(^-?\\d\\d*$)|(^-?\\.\\d\\d*$)");
  return re.test(s);
}

// Is str like smith
FormFilter.isTextEquals = function(s) {
  var re = new RegExp("^(?!\\*)(.*?[^\\*])$");
  var arr = s.match(re);
  if (arr != null) {
    return arr[1];
  }
}

// Is str like >=blah
FormFilter.isTextGreaterEquals = function(s) {
  var re = new RegExp("^>=(.*)");
  var arr = s.match(re);
  if (arr != null) {
    return arr[1];
  }
}

// Is str like <=blah
FormFilter.isTextLessEquals = function(s) {
  var re = new RegExp("^<=(.*)");
  var arr = s.match(re);
  if (arr != null) {
    return arr[1];
  }
}

// Is str like *smith*
FormFilter.isTextLike = function(s) {
  var re = new RegExp("^\\*(.*?)\\*$");
  var arr = s.match(re);
  if (arr != null) {
    return arr[1];
  }
}

// Is str like *smith
FormFilter.isTextLikeLeft = function(s) {
  var re = new RegExp("^\\*(.*?)$");
  var arr = s.match(re);
  if (arr != null) {
    return arr[1];
  }
}

// Is str like smith*
FormFilter.isTextLikeRight = function(s) {
  var re = new RegExp("^(.*?)\\*$");
  var arr = s.match(re);
  if (arr != null) {
    return arr[1];
  }
}

// Strip a date str
FormFilter.stripDate = function(s) {
  s = s.replace(/>/g, "");
  s = s.replace(/</g, "");
  s = s.replace(/=/g, "");
  s = s.replace(/ /g, "");
  s = s.replace(/:/g, "");
  s = s.replace(/\//g, "");
  s = s.replace(/-/g, "");
  return s;
}



/////////////////////////////////////////////////////////////////////////////////////
// Instance functions
/////////////////////////////////////////////////////////////////////////////////////


