/****
*
*   A set of javascript functions to do row filtering in a table given a 
*   form containing search parameters.
*
*  Compatibility : IE4+
*  	
*  Author  : Sidney Chong
*  Date    : 19/6/2007
*  Version : 1.0e
*
*
*  Features
*  ========
*  This script offers the following set of features:
*
*  #search criteria can be a text input, hidden input, single or multi-select list input.
*  #allows a combination of search criteria (as an AND operation).
*  #4 types of matching strategies are available:
*     1) substring1 - substring search (from 1st char) (default)
*        eg. man will match "manhood" and "man is evil" NOT "superman" and "he is a man"
*     2) substring - substring search (anywhere within)
*        eg. man will match "manhood" and "woman" and "superman" and "he is a man"
*     3) full - full string search
*        eg. man will match "man" NOT "manhood", "superman", "man is evil" and "he is a man"
*     4) item - search for a word/phrase in a comma seperated string
*        eg. man will match "man,woman,child" NOT "superman,superwoman,kid" and "boy,girl,dog"
*  #performs full string match (in substring1 mode) if last char in search string is a whitespace.
*  #allows search to be turned off/on.
*  #NEW - allow filtering by checkbox status in the table. search criteria can be expressed as
*         either a checkbox or a single select dropdown list.
*
*  Usage
*  =====
*  Give the table and search form a handle (using the attribute id or name).
*
*  In the cell elements of the table, include a custom atrribute called 
*  "TF_colKey" and give it a value to identify the column. Note that you only
*  need to do this for columns that will take part in the search.
*
*  In the form input elements, include also a custom attribute called 
*  "TF_colKey" whose value will reference the column on which this search 
*  parameter is applicable. Again, as in the table, you will only need to do this
*  if this input field should take part in the search. Also, an optional custom 
*  attribute called "TF_searchType" can be specified to use another search strategy 
*  for a particular field. NOTE: "TF_searchType" _must_ be set to "checkbox" for
*  filtering by checkbox status.
*
*  In an option tag for a select input, use the custom attribute "TF_not_used"
*  to exclude the particular option from the search. (Very useful in drop down
*  selection list box)
*
*  Call TF_filterTable passing in the handles to the table and form to 
*  perform the filtering.
*
*  NOTE that the value of TF_colKey & TF_searchType are case-insensitive.
*
*  ChangeLog cum Version History
*  =============================
*  19/6/2007 - version 1.0e release. 
*  19/6/2007 - Added convenience function TF_check_uncheck_all_rows to help 
*              check/uncheck all rows in the table. 
*  19/6/2007 - Added feature to allow filtering by checkbox status via checkbox 
*              OR single select dropdown list.
*  19/6/2007 - Added feature to allow filtering by checkbox status.
*  24/8/2001 - version 1.0d release.
*  23/8/2001 - Added functions _TF_get_value and TF_concat_and_set.
*  23/8/2001 - hidden input can now be used as a search field.
*  22/8/2001 - implemented "substring" search mode.
*  22/8/2001 - improve robustness/flexibility: if a cell <td> in the table or input 
*              <input>/<select> in the search form does not take part in the search 
*              (hence do not have the attribute "TF_colKey"), the script will 
*              gracefully ignore it. Previously, it will generate a script error.
*  22/8/2001 - reintroduced "TF_not_used" custom attribute to the option element.
*              I've apparently managed to loose it in the v1.0 pre-release *DUH!*
*
*  16/8/2001 - version 1.0c release.
*  16/8/2001 - modified _TF_trimWhitespace to trim the front as well.
*  16/8/2001 - fixed bug in _TF_filterTable that cause AND search combinations
*              not to work properly.
*
*   9/8/2001 - version 1.0b release.
*   8/8/2001 - added _TF_showAll function.
*   8/8/2001 - modified _TF_filterTable to use _TF_shouldShow function.
*   8/8/2001 - added TF_searchType attribute to define a search type.
*   8/8/2001 - implemented "item" search.
*   8/8/2001 - added _TF_shouldShow function.
*
*  26/7/2001 - version 1.0a release.
*  26/7/2001 - added _TF_trimWhitespace function.
*  26/7/2001 - modified _TF_filterTable single condition search to include 
*              full pattern search if the last char of the search string
*              is a whitespace.
*
*  14/6/2001 - version 1.0 initial release.
*
****/
var _TF_SHOW_COUNT=0;
/** PRIVATE FUNCTIONS **/
function _TF_trimWhitespace(txt) {
	var strTmp = txt;
	//trimming from the front
	for (counter=0; counter<strTmp.length; counter++)
		if (strTmp.charAt(counter) != " ")
			break;
	//trimming from the back
	strTmp = strTmp.substring(counter,strTmp.length);
	counter = strTmp.length - 1;
	for (counter; counter>=0; counter--)
		if (strTmp.charAt(counter) != " ")
			break;
	return strTmp.substring(0, counter+1);
}

function _TF_showAll(tb) {
	for (i=0;i<tb.rows.length;i++)
	{
		tb.rows[i].style.display = "";
	}
}

function _TF_shouldShow(type, con, cell) {
	var toshow=true;
	if (type != null) type = type.toLowerCase();
	switch (type)
	{
	    case "checkbox": //condition is for checkbox
	        //so lets find out if the cell contains a checkbox
	        var aInputs = cell.all.tags("INPUT");  //check for input tags
	        for (var i=0;i<aInputs.length;i++)
	        { //and look for the first checked item
	            if (aInputs[i].type == "checkbox") 
	            {
	                toshow = (con.toLowerCase() == (aInputs[i].checked?"true":"false"));
	                if (toshow) break;
	            }
	        }
	    break
		case "item":
			var strarray = cell.innerText.split(",");
			innershow = false;
			for (var ss=0;ss<strarray.length;ss++){
				if (con==_TF_trimWhitespace(strarray[ss])){
					innershow=true;
					break;
				}
			}
			if (innershow == false)
				toshow=false;
		break
		case "full":
			if (cell.innerText!=con)
				toshow = false;
		break
		case "substring":
			if (cell.innerText.indexOf(con)<0)
				toshow = false;
		break
		default: //is "substring1" search
			if (cell.innerText.indexOf(con)!=0) //pattern must start from 1st char
				toshow = false;
			if (con.charAt(con.length-1) == " ")
			{ //last char is a space, so lets do a full search as well
				if (_TF_trimWhitespace(con) != cell.innerText)
					toshow = false;
				else
					toshow = true;
			}
		break
	}
	return toshow;
}

function _TF_filterTable(tb, conditions) {
    for (var i = 0; i < tb.rows.length; i++) {
        var show = true;
        var rw = tb.rows[i];
        for (var j = 0; j < rw.cells.length; j++) {
            var cl = rw.cells[j];
            var tbVal = cl.innerHTML;
            for (var k = 0; k < conditions.length; k++) {
                var colKey = cl.getAttribute("TF_colKey");
                if (colKey == null)
                    continue;
                if (conditions[k].name.toUpperCase() == colKey.toUpperCase()) {
                    var conVals = conditions[k].value;

                    if (conVals.indexOf(tbVal) < 0 && conVals.indexOf('all') < 0) {
                        show = false;
                        break;
                    } else {
                        show = true
                    }
                }
            }

            if (!show)
                break;
        }
        if (show) {
            tb.rows[i].style.display = "";
            _TF_SHOW_COUNT++;
        } else {
            tb.rows[i].style.display = "none";
        }
    }
}

/** PUBLIC FUNCTIONS **/
//main function
function TF_filterTable(tb, frm) {
	_TF_SHOW_COUNT=0;
/*
	var conditions = new Array();
	if (frm.style.display == "none") //filtering is off
		return _TF_showAll(tb);

	//go thru each type of input elements to figure out the filter conditions
	var inputs = frm.tags("INPUT");
	for (var i=0;i<inputs.length;i++)
	{ //looping thru all INPUT elements
		if (inputs[i].getAttribute("TF_colKey") == null) //attribute not found
			continue; //we assume that this input field is not for us
		switch (inputs[i].type)
		{
			case "text":
			case "hidden":
				if(inputs[i].value != "")
				{
					index = conditions.length;
					conditions[index] = new Object;
					conditions[index].name = inputs[i].getAttribute("TF_colKey");
					conditions[index].type = inputs[i].getAttribute("TF_searchType");
					conditions[index].value = inputs[i].value;
					conditions[index].single = true;
				}
			break
            case "checkbox":
                if(inputs[i].isDisabled == false)
                {
                    index = conditions.length;
                    conditions[index] = new Object;
                    conditions[index].name = inputs[i].getAttribute("TF_colKey");
                    conditions[index].type = "checkbox";
                    conditions[index].value = inputs[i].checked?"true":"false";
                    conditions[index].single = true;
                    alert(index)
                }
			break
		}
	}

	var inputs = frm.tags("SELECT");
	//able to do multiple selection box
	for (var i=0;i<inputs.length;i++)
	{ //looping thru all SELECT elements
		if (inputs[i].getAttribute("TF_colKey") == null) //attribute not found
			continue; //we assume that this input field is not for us
		var opts = inputs[i].options;
		var optsSelected = new Array();
		for (intLoop=0; intLoop<opts.length; intLoop++)
		{ //looping thru all OPTIONS elements
			if (opts[intLoop].selected && (opts[intLoop].getAttribute("TF_not_used") == null))
			{
				index = optsSelected.length;
				optsSelected[index] = opts[intLoop].value;
			}
		}
		if (optsSelected.length > 0) //has selected items
		{
			index = conditions.length;
			conditions[index] = new Object;
			conditions[index].name = inputs[i].getAttribute("TF_colKey");
			conditions[index].type = inputs[i].getAttribute("TF_searchType");
			conditions[index].value = optsSelected;
			conditions[index].single = false;
		}
	}
*/


	var conditions = new Array();
	if (frm.style.display == "none") //filtering is off
		return _TF_showAll(tb);

	//alert(frm.elements.length);
	//alert(frm.elements[0].type)
	//var inputs = frm.tags("INPUT");
	var inputs = frm.elements;

	var TF_colKey = "";
	var TF_searchType = ""
	var valueList = "";

	for (var i=0;i<inputs.length;i++) {
		if (inputs[i].getAttribute("TF_colKey") == null) //attribute not found
			continue; //we assume that this input field is not for us
		if (i == 0)
			TF_colKey = inputs[i].getAttribute("TF_colKey");
		switch (inputs[i].type) {
			case "checkbox":
				//if(inputs[i].isDisabled == false) {
					index = conditions.length;
					//alert(TF_colKey +" abcde "+ inputs[i].getAttribute("TF_colKey"));
					if (TF_colKey != inputs[i].getAttribute("TF_colKey")) {
						//alert(index + "," + TF_colKey);
						conditions[index] = new Object;
						conditions[index].name = TF_colKey;
						conditions[index].type = inputs[i].getAttribute("TF_searchType");
						conditions[index].single = false;
						//alert(valueList.length);
						if (valueList.length > 0) {
							//alert(valueList.substring(0, valueList.length-1));
							//valueList = valueList.substring(0, valueList.length-1);
							//aryN = valueList.split(",");
							//conditions[index].value = aryN;
							conditions[index].value = valueList.substring(0, valueList.length-1);
						}
						else {
							conditions[index].value = "";
						}
						TF_colKey = inputs[i].getAttribute("TF_colKey");
						valueList = "";
					}
					if (inputs[i].checked) {
						//if (inputs[i].getAttribute("TF_colKey") != "Stop")
							valueList = valueList + inputs[i].value + ",";
						//else
						//	valueList = "no,";
					}

					//alert(valueList)

					//else {
					//	if (inputs[i].getAttribute("TF_colKey") == "Stop")
					//		valueList = "yes,";
					//}

					if (i == inputs.length-1) {
						//index = index + 1;
						conditions[index] = new Object;
						conditions[index].name = TF_colKey;
						conditions[index].type = inputs[i].getAttribute("TF_searchType");
						conditions[index].single = false;
						if (valueList.length > 0) {
							conditions[index].value = valueList.substring(0, valueList.length-1);
						}
						else {
							conditions[index].value = "";
						}
						TF_colKey = inputs[i].getAttribute("TF_colKey");
						valueList = "";
					}

				//}
			//break
		}
		//alert(valueList);
	}


/*
	for (var i=0;i<conditions.length;i++) {
		alert(conditions[i].value)
	}
*/
	//ok, now that we have all the conditions, lets do the filtering proper
	_TF_filterTable(tb, conditions);
	if(_TF_SHOW_COUNT==1){
		if(document.getElementById('_TF_SHOW_COUNT'))
			document.getElementById('_TF_SHOW_COUNT').style.display='';
	}else{
		if(document.getElementById('_TF_SHOW_COUNT'))
			document.getElementById('_TF_SHOW_COUNT').style.display='none';
	}
}

function TF_enableFilter(tb, frm, val) {
	if (val.checked) //filtering is on
	{
		frm.style.display = "";
	} else { //filtering is off
		frm.style.display = "none";
	}
	//refresh the table
	TF_filterTable(tb, frm);
}

function _TF_get_value(input) {
	switch (input.type)
	{
		case "text":
			 return input.value;
		break
		case "select-one":
			if (input.selectedIndex > -1) //has value
				return input.options(input.selectedIndex).value;
			else
				return "";
		break;
	}
}

//util function that concat two input fields and set the result in the third
function TF_concat_and_set(salText, salSelect, salHidden) {
	var valLeft = _TF_get_value(salText);
	var valRight = _TF_get_value(salSelect);
	salHidden.value = valLeft + valRight;
}

//util function that helps to check/uncheck rows in a table
function TF_check_uncheck_all_rows(tbl, bState, iColIdx, iRowStart) {
    for (var i=iRowStart;i<tbl.rows.length;i++)
    {
        var aInputs = tbl.rows[i].cells[iColIdx].all.tags("INPUT"); //check for input tags
        for (j=0;j<aInputs.length;j++)
        { //and look for the first checked item
            if (aInputs[j].type == "checkbox") 
            {
                aInputs[j].checked = bState;
                break;
            }
        }
    }
}


/* test */
function test(tb, frm) {
	alert('hello');
}
