/*
        TableFilter v1.2 by frequency-decoder.com

        Released under a creative commons Attribution-ShareAlike 2.5 license (http://creativecommons.org/licenses/by-sa/2.5/)

        Please credit frequency decoder in any derivative work - thanks

        You are free:

        * to copy, distribute, display, and perform the work
        * to make derivative works
        * to make commercial use of the work

        Under the following conditions:

                by Attribution.
                --------------
                You must attribute the work in the manner specified by the author or licensor.

                sa
                --
                Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one.

        * For any reuse or distribution, you must make clear to others the license terms of this work.
        * Any of these conditions can be waived if you get permission from the copyright holder.
*/

var fdTableFilter = {

        tableCache:{},
        uniqueHash:0,
        colRangeStart:null,
        colRangeFinish:null,
        currentTableId:null,
        thNode:null,
        imageLoc:"",
        timer:null,
        
        init:function(tableId) {

                if (!document.getElementsByTagName || !document.createElement || !document.getElementById) return;

                var colspan = "colspan";
                var rowspan = "rowspan";
                /*@cc_on
                /*@if(@_win32)
                colspan = "colSpan";
                rowspan = "rowSpan";
                /*@end
                @*/
                
                var tables = tableId && document.getElementById(tableId) ? [document.getElementById(tableId)] : document.getElementsByTagName("table");

                var maxLength, dataType, useList, colData, txt, tr, innerText, popup, comparison, comparisonType, rowData, rowArr, rowList, colObj, elem, rowLength, aClone, imgClone, rowStock, workArr, filterList, filterType, filterPrep, celCount, ths, filterable;

                var a           = document.createElement("a");
                a.href          = "#";
                a.title         = "Show column filter";
                a.className     = "fdFilterTrigger";
                
                var img         = document.createElement("img");
                img.alt         = "";
                img.src         = fdTableFilter.imageLoc;

                var buildScaffold = false;
                
                for(var k = 0, tbl; tbl = tables[k]; k++) {

                        // Remove any old dataObj for this table (tables created from an ajax callback require this)
                        if(tbl.id) { fdTableFilter.removeTableCache(tbl); };
                        
                        ths = tbl.getElementsByTagName('th');
                        filterable = false;
                        
                        // Check we have a required className
                        for(var i = 0, th; th = ths[i]; i++) {
                                if(th.className.search(/datatype-([a-zA-Z]{1}[0-9a-zA-Z\_]+)/) == -1) continue;
                                filterable = true;
                                break;
                        };

                        if(!filterable) continue;

                        if(!tbl.id) tbl.id = "fd-table-filter-" + fdTableFilter.uniqueHash++;
                        
                        popup           = tbl.className.search(/popup-filter/) != -1;
                        rowArr          = [];
                        rowList         = tbl.getElementsByTagName('tr');

                        for(var i = 0;i < rowList.length;i++){
                                rowList[i].className = rowList[i].className.replace(/(^|\b)invisibleRow($|\b)/, "");
                                
                                colObj = [];
                                elem = rowList[i].firstChild;
                                do {
                                        if(elem.tagName && elem.tagName.toLowerCase().search(/td|th/) != -1) {
                                                colObj[colObj.length] = elem;
                                        };
                                        elem = elem.nextSibling;
                                } while(elem);
                                rowArr.push(colObj);
                        };
                        
                        if(!rowArr.length) { continue; };
                        
                        rowLength = rowArr[0].length;
                        
                        for(var c = 0;c < rowArr[0].length;c++){
                                if(rowArr[0][c].getAttribute(colspan) > 1){
                                        rowLength = rowLength + (rowArr[0][c].getAttribute(colspan) - 1);
                                };
                        };

                        workArr = new Array(rowArr.length);
                        for(var c = rowArr.length;c--;){
                                workArr[c]  = new Array(rowLength);
                        };

                        filterList = {};
                        filterType = {};
                        filterPrep = {};

                        for(var c = 0;c < workArr.length;c++) {
                                celCount = 0;
                                for(var i = 0;i < rowLength;i++) {
                                        if(!workArr[c][i]) {
                                                cel     = rowArr[c][celCount];
                                                colSpan = (cel.getAttribute(colspan) && cel.getAttribute(colspan) > 1) ? cel.getAttribute(colspan) : 1;
                                                rowSpan = (cel.getAttribute(rowspan) && cel.getAttribute(rowspan) > 1) ? cel.getAttribute(rowspan) : 1;
                                                if(cel.tagName == "TH" && cel.className.search(/datatype-([a-zA-Z]{1}[0-9a-zA-Z\_]+)/) != -1) {

                                                        dataType        = cel.className.match(/datatype-([a-zA-Z]{1}[0-9a-zA-Z\_]+)/)[1];
                                                        useList         = cel.className.search(/create-list/) != -1;

                                                        if(dataType.search(/^(datedmy|date|numeric|text)$/) == -1 && !(dataType in window && typeof(window[dataType]) == "function")) {
                                                                continue;
                                                        };

                                                        switch(dataType) {
                                                                case "datedmy":
                                                                case "date":
                                                                case "numeric":
                                                                        comparison = "numeric";
                                                                        break;
                                                                case "text":
                                                                        comparison = "text";
                                                                        break;
                                                                default:
                                                                        comparison = cel.className.search(/comparison-numeric/) != -1 ? "numeric" : "text";
                                                        };
                                                        
                                                        for(f = i; f < (i + Number(colSpan)); f++) {
                                                                filterType[f]   = { "dataType":dataType, "useList":useList, "comparison":comparison };
                                                                filterList[f]   = "";
                                                                filterPrep[f]   = "";
                                                                
                                                                if(f == i && !popup) {
                                                                        filterType[f].colspan = colSpan;
                                                                };
                                                        };
                                                        
                                                        cel.className = cel.className.replace(/fdFilterProcessed-([\d]*)-([\d]*)/, "");
                                                        fdTableFilter.addClass(cel, " fdFilterProcessed-" + i + "-" + (i + Number(colSpan)));
                                                        
                                                        if(popup) {
                                                                aClone          = a.cloneNode(true);
                                                                imgClone        = img.cloneNode(true);
                                                        
                                                                aClone.appendChild(imgClone);
                                                                aClone.onclick = aClone.onkeypress = fdTableFilter.showFilter;
                                                                cel.insertBefore(aClone, cel.firstChild);
                                                        };
                                                };
                                                
                                                for(var t = 0;((t < colSpan)&&((i+t) < rowLength));t++){
                                                        for(var n = 0;((n < rowSpan)&&((c+n) < workArr.length));n++){
                                                                workArr[(c+n)][(i+t)] = cel;
                                                        };
                                                };
                                                if(++celCount == rowArr[c].length) { break; };
                                        };
                                };

                                workArr[c].push(workArr[c][0].parentNode);
                        };
                        
                        rowData         = [];
                        maxLength       = new Array(workArr[0].length);
                        
                        // For each row...
                        for(var r = 0;r < workArr.length;r++) {
                                tr = workArr[r][workArr[r].length - 1];

                                if(tr.getElementsByTagName("th").length || tr.parentNode.tagName.toLowerCase() == "tfoot") {
                                        continue;
                                };
                                
                                colData = [];
                                
                                for(var c = 0; c < workArr[r].length - 1; c++) {
                                        if(c in filterList) {
                                                innerText = fdTableFilter.getInnerText(workArr[r][c]);
                                                if(!maxLength[c] || innerText.replace(/^[\s\s\xA0]*/, '').replace(/[\s\s\xA0]*$/g, '').length > maxLength[c]) {
                                                        maxLength[c] = innerText.replace(/^[\s\xA0]*/, '').replace(/^[\s\xA0]*$/g, '').length;
                                                };
                                                if(filterType[c].dataType.search(/^(date|datedmy)$/) != -1) {
                                                        colData.push([fdTableFilter.dateFormat(innerText.replace(/^\s\s*/, '').replace(/\s\s*$/, ''), filterType[c].dataType.indexOf("dmy") != -1), innerText]);
                                                } else if(filterType[c].dataType == "numeric") {
                                                        colData.push([parseFloat(innerText.replace(/[^0-9\.\-]/g,'')), innerText]);
                                                } else if(filterType[c].dataType in window && typeof(window[filterType[c].dataType]) == "function"){
                                                        colData.push([window[filterType[c].dataType](workArr[r][c], innerText), innerText]);
                                                } else {
                                                        colData.push([innerText.replace(/^[\s\s\xA0]*/, '').replace(/[\s\s\xA0]*$/g, ''), innerText]);
                                                };

                                        } else {
                                                colData.push([" ", " "]);
                                        };
                                };

                                rowData.push({ "columnData":colData, "trNode":tr });
                        };
                                
                        fdTableFilter.tableCache[tbl.id] = {
                                "filterList":filterList,
                                "filterType":filterType,
                                "filterPrep":{},
                                "filterMath":{},
                                "maxLength":maxLength,
                                "rowData":rowData,
                                "rowStyle":tbl.className.search(/rowstyle-([\S]+)/) != -1 ? tbl.className.match(/rowstyle-([\S]+)/)[1] : false
                        };
                        
                        if(popup) {
                                buildScaffold = true;
                        } else {
                                var tr          = document.createElement("tr");
                                tr.className    = "fdFilterTableRow";

                                var th          = document.createElement("th");
                                
                                var form        = document.createElement("form");
                                form.method     ="post";
                                form.action     = "";

                                var p           = document.createElement("p");
                                
                                var inp         = document.createElement("input");
                                inp.type        = "text";
                                
                                var sel         = document.createElement("select");
                                
                                var nbsp        = String.fromCharCode(160);
                                var thC, pC;
                                var cellCnt     = 0;

                                for(var i = 0;((i < rowLength) && (cellCnt < rowLength));i++) {
                                        thC = th.cloneNode(true);

                                        if(i in filterType && "colspan" in filterType[i]) {
                                                pC  = p.cloneNode(false);
                                                if(filterType[i].colspan > 1) { thC.colspan = filterType[i].colspan; }
                                                formC = form.cloneNode(true);
                                                formC.name = formC.id = "form-" + tbl.id + "-" + i + "-" + (i + filterType[i].colspan);
                                                if(!filterType[i].useList) {
                                                        inpC = inp.cloneNode(true);
                                                        inpC.id = inpC.name = tbl.id + "-" + i + "-" + (i + filterType[i].colspan);
                                                        formC.onsubmit = fdTableFilter.embeddedFilter;
                                                        inpC.setAttribute("maxlength", Number(maxLength[i]) + 2);
                                                        pC.className = "fdInpContainer";
                                                } else {
                                                        inpC = sel.cloneNode(true);
                                                        inpC.name = inpC.id = tbl.id + "-" + i + "-" + (i + filterType[i].colspan);
                                                        fdTableFilter.buildSelectList(inpC, tbl.id, cellCnt, cellCnt + filterType[i].colspan);
                                                        inpC.onchange = fdTableFilter.embeddedFilter;
                                                };
                                                inpC.className = "fdFilter-" + i;
                                                pC.appendChild(inpC);
                                                formC.appendChild(pC);
                                                thC.appendChild(formC);
                                                
                                                cellCnt += filterType[i].colspan;
                                        } else {
                                                thC.appendChild(document.createTextNode(nbsp));
                                                cellCnt++;
                                        };

                                        tr.appendChild(thC);
                                };

                                if(tbl.getElementsByTagName('thead').length > 0) {
                                        tbl.getElementsByTagName("thead")[0].appendChild(tr);
                                } else {
                                        var trs = tbl.getElementsByTagName('tr');
                                        var inserted = false;
                                        for(var i = 0, thCheck; thCheck = trs[i]; i++) {
                                                if(!thCheck.getElementsByTagName('th').length) {
                                                        thCheck.parentNode.insertBefore(tr, thCheck);
                                                        inserted = true;
                                                        break;
                                                };
                                        };
                                        
                                        if(!inserted) {
                                                tbl.insertBefore(tr, trs[0]);
                                        };
                                };
                        };
                };

                if(buildScaffold) {
                        fdTableFilter.buildScaffold();
                };
                
                colHead = null;
        },
        buildSelectList:function(select, tableId, start, end) {
                var comparison          = fdTableFilter.tableCache[tableId].filterType[start].comparison;
                var dataType            = fdTableFilter.tableCache[tableId].filterType[start].dataType;
                var currentFilter       = String(fdTableFilter.tableCache[tableId].filterList[start]);
                var dataObj             = fdTableFilter.tableCache[tableId].rowData;
                var newArray            = [];
                var txtObj              = {};
                var data;
                
                for(var i = 0, row; row = dataObj[i]; i++) {
                        for(var r = start; r < end; r++) {
                                data = row.columnData[r];
                                if(data[1] != "" && !(data[1] in txtObj)) {
                                        newArray.push(data);
                                        txtObj[data[1]] = data[0];
                                };
                        };
                };

                newArray.sort(fdTableFilter[comparison == "numeric" ? "sortNumeric" : "sortText"]);

                select.options.length = 0;

                opt = new Option("","");
                select.options[0] = opt;
                
                for(var i = 0, txt; txt = newArray[i]; i++) {
                        opt = new Option(txt[1],txt[0]);
                        if((i+1) & 1) { opt.className = "alternative"; };
                        if(currentFilter === String(txt[0])) { opt.selected = "selected"; };
                        select.options[i+1] = opt;
                };
        },

        popUpFilter:function(e) {
                fdTableFilter.filterData = this.tagName == "FORM" ? this.getElementsByTagName("input")[0].value : this.options[this.selectedIndex].value;
                fdTableFilter.filter();
                fdTableFilter.removeDocumentEvent();
                return fdTableFilter.stopEvent(e || window.event);
        },
        customFilter:function(filterData, tableId, colRangeStart, colRangeEnd) {

				fdTableFilter.clearFilter(tableId);
		
				fdTableFilter.currentTableId = tableId;
                fdTableFilter.colRangeStart  = colRangeStart;
                fdTableFilter.colRangeFinish = colRangeEnd;
				fdTableFilter.filterData = filterData;

                //fdTableFilter.currentTableId = 'test1';
                //fdTableFilter.colRangeStart  = '3';
                //fdTableFilter.colRangeFinish = '4';
				//fdTableFilter.filterData = 'abc';
				
                fdTableFilter.filter();
                return true;
        },
        embeddedFilter:function(e) {
                var parts = this.id.replace(/^form-/, "").split("-");
                fdTableFilter.currentTableId = parts[0];
                fdTableFilter.colRangeStart  = parts[1];
                fdTableFilter.colRangeFinish = parts[2];
                fdTableFilter.filterData     = this.tagName == "FORM" ? this.getElementsByTagName("input")[0].value : this.options[this.selectedIndex].value;
                fdTableFilter.filter();
                return fdTableFilter.stopEvent(e || window.event);
        },
        jsFilter:function(tableId, start, finish, filter) {
                if(!tableId || !(tableId in fdTableFilter.tableCache)) { return; };
                fdTableFilter.currentTableId = tableId;
                fdTableFilter.colRangeStart  = start;
                fdTableFilter.colRangeFinish = finish;
                fdTableFilter.filterData     = filter;
                fdTableFilter.filter();
        },
        clearFilter:function(tableId) {
                if(!tableId || !(tableId in fdTableFilter.tableCache) || !document.getElementById(tableId)) { return; };
                fdTableFilter.currentTableId = tableId;
                fdTableFilter.filterData     = "";

                var m;
                var cnt         = 0;
                var popup       = document.getElementById(tableId).className.search(/popup-filter/) != -1;
                var colStart    = false;
                
                for(f in fdTableFilter.tableCache[tableId].filterList) {
                        if(fdTableFilter.tableCache[tableId].filterList[f]) {
                                fdTableFilter.tableCache[tableId].filterList[f] = "";
                                if(colStart === false) { colStart = f; };
                        };
                };
                
                if(colStart === false) { return; };
                
                if(popup) {
                        var thNodes = document.getElementById(tableId).getElementsByTagName('th');
                        for(var i = 0, thNode; thNode = thNodes[i]; i++) {
                                m = thNode.className.match(/fdFilterProcessed-([\d]+)-([\d]+)/);
                                if(!m) continue;

                                var lnks = thNode.getElementsByTagName('a');
                                for(var z = 0, a; a = lnks[z];z++) {
                                        if(a.className.search("fdFilterUsed") != -1) {
                                                fdTableFilter.removeClass(a, "fdFilterUsed");
                                                break;
                                        };
                                };
                        };
                } else {
                        var inputs = document.getElementById(tableId).getElementsByTagName('input');
                        var selects = document.getElementById(tableId).getElementsByTagName('select');
                        for(var i = 0, elem; elem = inputs[i]; i++) {
                                if(elem.className.search(/fdFilter-/) == -1) { continue; };
                                elem.value = "";
                        };
                        for(var i = 0, elem; elem = selects[i]; i++) {
                                if(elem.className.search(/fdFilter-/) == -1) { continue; };
                                elem.selectedIndex = 0;
                        };
                };
                
                fdTableFilter.colRangeStart     = colStart || 0;
                fdTableFilter.colRangeFinish    = parseInt(colStart, 10) + 1;
                fdTableFilter.filter(true);
        },
        filter:function(force) {

                if(!fdTableFilter.currentTableId) { return; };
                
                function testValue(operator, value1, value2) {
                        if(operator == "<=") {
                                if(!(value1 <= value2)) {
                                        return true;
                                };
                        } else if(operator == ">=") {
                                if(!(value1 >= value2)) {
                                        return true;
                                };
                        } else if(operator == "<") {
                                if(!(value1 < value2)) {
                                        return true;
                                };
                        } else if(operator == ">") {
                                if(!(value1 > value2)) {
                                       return true;
                                };
                        } else if(operator == "!") {
                                if(value1 == value2) {
                                       return true;
                                };
                        } else if(String(value1) != String(value2)) {
                                return true;
                        };
                        
                        return false;
                };
                
                function testRegExp(testValue, cellData) {
                        var regexp = new RegExp(fdTableFilter.regExpEscape(testValue),"gi");
                        return (!regexp.test(cellData)) ? true : false;
                };
                
                var dataType    = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterType[fdTableFilter.colRangeStart].dataType;
                var comparison  = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterType[fdTableFilter.colRangeStart].comparison;
                var useList     = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterType[fdTableFilter.colRangeStart].useList;
                var dataObj     = fdTableFilter.tableCache[fdTableFilter.currentTableId].rowData;
                var rowStyle    = fdTableFilter.tableCache[fdTableFilter.currentTableId].rowStyle;
                var rowLen      = dataObj.length;
                var origVal     = fdTableFilter.filterData;
                var val         = origVal;
                var operator    = !useList && val.search(/^(<=|>=|<|>|!)/) != -1 ? val.match(/^(<=|>=|<|>|!)/)[1] : "";

                if(operator && !useList) {
                        val = val.replace(/^(<=|>=|<|>|!)/, "").replace(/^\s\s*/, "");
                };
                
                var preparedVal = "";
                
                if(val && !useList) {
                        if(dataType.search(/^(date|datedmy)$/) != -1) {
                                preparedVal = fdTableFilter.dateFormat(val, dataType.indexOf("dmy") != -1);
                                if(preparedVal == 0) { preparedVal = ""; };
                        } else if(dataType == "numeric") {
                                preparedVal = parseFloat(val.replace(/[^0-9\.\-]/g,''));
                        } else if(dataType in window && typeof(window[dataType]) == "function") {
                                preparedVal = window[dataType](null, val);
                        } else {
                                preparedVal = val.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
                        };
                } else if(useList) {
                        preparedVal = val;
                };

                if(fdTableFilter.a) {
                        if(val.replace(/^\s\s*/, '').replace(/\s\s*$/, '') != "") {
                                fdTableFilter.addClass(fdTableFilter.a, "fdFilterUsed");
                        } else {
                                fdTableFilter.removeClass(fdTableFilter.a, "fdFilterUsed");
                        };
                };

                for(var i = fdTableFilter.colRangeStart; i < fdTableFilter.colRangeFinish; i++) {
                        fdTableFilter.tableCache[fdTableFilter.currentTableId].filterList[i] = origVal;
                        fdTableFilter.tableCache[fdTableFilter.currentTableId].filterPrep[i] = preparedVal;
                        fdTableFilter.tableCache[fdTableFilter.currentTableId].filterMath[i] = operator;
                };

                var hideRow, f, cellData, regexp, filter;
                
                for(var i = 0, row; row = dataObj[i]; i++) {
                        hideRow = false;

                        if(!force) {
                                for(f in fdTableFilter.tableCache[fdTableFilter.currentTableId].filterList) {
                                        origValue       = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterList[f];
                                        if(origValue == "" ) { continue; };
                                
                                        prepValue       = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterPrep[f];
                                        mathOperator    = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterMath[f];
                                        dataType        = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterType[f].dataType;
                                        comparison      = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterType[f].comparison;
                                        useList         = fdTableFilter.tableCache[fdTableFilter.currentTableId].filterType[f].useList;
                                        cellData        = row.columnData[f][0];

                                        if(useList) {
                                                if(cellData != origValue) {
                                                        hideRow = true;
                                                 break;
                                                };
                                                continue;
                                        };

                                        if(dataType.search(/^(datedmy|date)$/) != -1 && /^\d\d\d\d$/.test(prepValue)) {
                                                cellData = String(cellData).substr(0,4);
                                        };

                                        if(comparison == "numeric" && (isNaN(prepValue) || String(prepValue) == "" || isNaN(cellData) || String(cellData) == "")) {
                                                continue;
                                        };
                                
                                        if(comparison == "numeric" || mathOperator) {
                                                if(testValue(mathOperator, cellData, prepValue)) {
                                                        hideRow = true;
                                                        break;
                                                };
                                        } else if(testRegExp(prepValue, cellData)) {
                                                hideRow = true;
                                                break;
                                        };
                                };
                        };
                        
                        if(hideRow) {
                                fdTableFilter.addClass(row.trNode, "invisibleRow");
                        } else {
                                if(rowStyle) { fdTableFilter.removeClass(row.trNode, rowStyle); };
                                fdTableFilter.removeClass(row.trNode, "invisibleRow");
                        };
                };
                
                if("tablePaginater" in window && fdTableFilter.currentTableId in tablePaginater.tableInfo) {
                        tablePaginater.init(fdTableFilter.currentTableId);
                } else if(rowStyle) {
                        fdTableFilter.zebraStripe(fdTableFilter.currentTableId,rowStyle);
                };
        },
        zebraStripe:function(tableId, rowStyle) {
                var tbl         = document.getElementById(tableId);
                var tbody       = tbl.getElementsByTagName("tbody");
                var hook        = tbody && tbody.length ? tbody[0] : tbl;
                var trs         = hook.rows;
                var len         = trs.length;
                var rowCnt      = 0;
                var reg         = /(^|\s)invisibleRow(\s|$)/;
                
                for(var i = 0; i < len; i++) {
                        if(trs[i].className.search(reg) != -1 || trs[i].parentNode.tagName == "TFOOT") { continue; };
                        if(rowCnt++ & 1) {
                                fdTableFilter.addClass(trs[i], rowStyle);
                        } else {
                                fdTableFilter.removeClass(trs[i], rowStyle);
                        };
                };
        },
        showFilter:function(e) {

                fdTableFilter.timer = null;
                
                e = e || window.event;
                var kc = e.type == "keypress" ? e.keyCode != null ? e.keyCode : e.charCode : -1;

                if(e.type == "keypress" && kc != 13) {
                        return true;
                };
        
                var targ = this;
                while(targ.tagName.toLowerCase() != "a") { targ = targ.parentNode; };
                var a = targ;
                while(targ.tagName.toLowerCase() != "th") { targ = targ.parentNode; };
                var thNode = targ;
                while(targ.tagName.toLowerCase() != "table") { targ = targ.parentNode; };
                var table = targ;

                var m = thNode.className.match(/fdFilterProcessed-([\d]+)-([\d]+)/);
                
                fdTableFilter.colRangeStart     = Number(m[1]);
                fdTableFilter.colRangeFinish    = Number(m[2]);
                fdTableFilter.currentTableId    = table.id;
                fdTableFilter.thNode            = thNode;
                fdTableFilter.a                 = a;
                
                var useList                     = fdTableFilter.tableCache[table.id].filterType[m[1]].useList;
                var currentFilter               = fdTableFilter.tableCache[table.id].filterList[m[1]];
                var dataObj                     = fdTableFilter.tableCache[table.id].rowData;
                var wrapper                     = document.getElementById("fdTablefilterWrapper");
                var input                       = wrapper.getElementsByTagName("input")[0];
                var select                      = wrapper.getElementsByTagName("select")[0];
                var tlc                         = document.getElementById("fdtl");
                var dongle                      = document.getElementById("fddongle");

                if(useList) {
                        select.options.length   = 0;
                        fdTableFilter.buildSelectList(select, fdTableFilter.currentTableId, fdTableFilter.colRangeStart, fdTableFilter.colRangeFinish);
                        select.style.display    = "";
                        input.style.display     = "none";
                } else {
                        input.value             = currentFilter || "";
                        select.style.display    = "none";
                        input.setAttribute("maxlength", fdTableFilter.tableCache[table.id].maxLength[m[1]] + 2);
                        input.style.display     = "";
                };
                
                wrapper.style.visibility        = "hidden";
                wrapper.style.display           = "block";

                var cw = tlc.offsetWidth;
                var w  = Math.max(thNode.offsetWidth, 100);

                wrapper.style.width     = (w + (2 * cw)) + "px";
                
                var pos           = fdTableFilter.truePosition(fdTableFilter.thNode);
                pos[0] -= (((w + (2 * cw)) - fdTableFilter.thNode.offsetWidth) / 2);
                
                var trueBody      = (document.compatMode && document.compatMode!="BackCompat") ? document.documentElement : document.body;
                var scrollTop     = window.devicePixelRatio || window.opera ? 0 : trueBody.scrollTop;
                var scrollLeft    = window.devicePixelRatio || window.opera ? 0 : trueBody.scrollLeft;

                if(parseInt(trueBody.clientWidth+scrollLeft) < parseInt(w+pos[0])) {
                        wrapper.style.left = Math.abs(parseInt((trueBody.clientWidth+scrollLeft) - w)) + "px";
                } else {
                        wrapper.style.left  = pos[0] + "px";
                };

                wrapper.style.top   = Math.abs(parseInt(pos[1] + fdTableFilter.thNode.offsetHeight - 4)) + "px";
                
                fdTableFilter.addDocumentEvent();

                wrapper.style.visibility = "visible";

                dongle.style.left = (w / 2) + "px";
                
                try { useList ? select.focus() : input.focus(); } catch(err) {};
                
                return fdTableFilter.stopEvent(e || window.event);
        },
        checkDocumentEvent:function(e) {
                e = e || document.parentWindow.event;
                var el = e.target != null ? e.target : e.srcElement;
                var found = false;
                while(el.parentNode) {
                        if(el.id && el.id == "fdTablefilterWrapper") {
                                found = true;
                                break;
                        };
                        try { el = el.parentNode; } catch(err) { break; };
                };
                if(!found) {
                        fdTableFilter.removeDocumentEvent();
                        return fdTableFilter.stopEvent(e);
                };
        },
        addDocumentEvent:function() {
                fdTableFilter.addEvent(document, "mousedown", fdTableFilter.checkDocumentEvent);
        },
        removeDocumentEvent:function() {
                fdTableFilter.removeEvent(document, "mousedown", fdTableFilter.checkDocumentEvent);
                var wrap                = document.getElementById("fdTablefilterWrapper");
                wrap.style.visibility   = "hidden";
                wrap.style.display      = "none";
                fdTableFilter.colRangeStart = fdTableFilter.colRangeFinish = fdTableFilter.currentTableId = fdTableFilter.thNode = fdTableFilter.a = null;
        },
        removeTableCache: function(table) {
                if(!(table.id in fdTableFilter.tableCache)) return;

                fdTableFilter.tableCache[table.id] = null;
                delete fdTableFilter.tableCache[table.id];

                if(table.className.search(/popup-filter/) != -1) {
                        var ths = table.getElementsByTagName("th");
                        var lnks;
                        for(var i = ths.length; i--;) {
                                lnks = ths[i].getElementsByTagName("a");
                                for(var z = lnks.length; z--;) {
                                        if(lnks[z].className.search(/fdFilterTrigger|fdFilterUsed/) != -1) {
                                                lnks[z].onkeypress = lnks[z].onclick = null;
                                        };
                                };
                        };
                        ths = lnks = null;
                } else {
                        var forms = table.getElementsByTagName("form");
                        var select;
                        for(var i = 0, form; form = forms[i]; i++) {
                                form.onsubmit = null;
                                select = form.getElementsByTagName("select");
                                if(select.length) select[0].onchange = null;
                        };
                        forms = select = null;
                };
        },
        regExpEscape: function(s){
                function escape(e) {
                        a = new RegExp('\\'+e,'g');
                        s = s.replace(a,'\\'+e);
                };
                var chars = ['\\','[','^','$','.','|','?','*','+','(',')'];
                for(e in chars) { escape(chars[e]); };
                escape = null;
                return s;
        },
        getInnerText: function(el) {
                if (typeof el == "string" || typeof el == "undefined") return el;
                if(el.innerText) return el.innerText;
                var txt = '', i;
                for(i = el.firstChild; i; i = i.nextSibling) {
                        if(i.nodeType == 3)            txt += i.nodeValue;
                        else if(i.nodeType == 1)       txt += fdTableFilter.getInnerText(i);
                };
                return txt;
        },
        unLoad:function(e) {
                for(tbl in fdTableFilter.tableCache) {
                        fdTableFilter.removeTableCache(document.getElementById(tbl));
                };
                delete(fdTableFilter.tableCache);
                
                var wrapper = document.getElementById("fdTablefilterWrapper");
                wrapper.parentNode.removeChild(wrapper);
        },
        buildScaffold:function() {
                if(document.getElementById("fdTablefilterWrapper")) { return; };
                
                var w, h, m, wrap, corner, bar;

                var div         = document.createElement("div");
                var form        = document.createElement("form");
                var p           = document.createElement("p");
                var inp         = document.createElement("input");
                var sel         = document.createElement("select");
                var c           = ["fdtl","fdtr","fdbl","fdbr"];
                var bs1         = ["fdlb", "fdrb"];
                var bs2         = ["fdtb", "fdbb"];

                wrap = div.cloneNode(false);
                wrap.id = "fdTablefilterWrapper";
                
                form.action     = "";
                form.method     = "post";
                form.onsubmit   = fdTableFilter.popUpFilter;

                var input = inp.cloneNode(true);
                input.type = "text";
                input.name = input.id = "fdFilterInp";
                
                sel.name = sel.id = "fdFilterSel";
                sel.onchange = fdTableFilter.popUpFilter;

                p.appendChild(sel);
                p.appendChild(input);
                
                form.appendChild(p);
                
                wrap.appendChild(form);
                
                for(var i = 0; i < 4; i++) {
                        corner = div.cloneNode(false);
                        corner.id = c[i];
                        wrap.appendChild(corner);
                        corner = null;
                };

                for(i = 0; i < 2; i++) {
                        bar = div.cloneNode(false);
                        bar.id = bs1[i];
                        wrap.appendChild(bar);
                        bar = null;
                };

                for(i = 0; i < 2; i++) {
                        bar = div.cloneNode(false);
                        bar.id = bs2[i];
                        wrap.appendChild(bar);
                        bar = null;
                };
                
                var dongle = div.cloneNode(false);
                dongle.id = "fddongle";
                wrap.appendChild(dongle);
                
                wrap.style.left = wrap.style.top = "-1000em";

                wrap.style.visibility = "visible";
                wrap.style.display = "";
                
                fdTableFilter.timer = setTimeout(fdTableFilter.removeDocumentEvent, 200);
                
                document.getElementsByTagName("body")[0].appendChild(wrap);
        },
        addEvent: function(obj, type, fn) {
                if( obj.attachEvent ) {
                        obj["e"+type+fn] = fn;
                        obj[type+fn] = function(){obj["e"+type+fn]( window.event );};
                        obj.attachEvent( "on"+type, obj[type+fn] );
                } else {
                        obj.addEventListener( type, fn, true );
                };
        },
        removeEvent: function(obj, type, fn) {
                try {
                        if( obj.detachEvent ) {
                                obj.detachEvent( "on"+type, obj[type+fn] );
                                obj[type+fn] = null;
                        } else {
                                obj.removeEventListener( type, fn, true );
                        };
                } catch(err) {};
        },
        stopEvent: function(e) {
                e = e || window.event;
                if(e.stopPropagation) {
                        e.stopPropagation();
                        e.preventDefault();
                };
                /*@cc_on@*/
                /*@if(@_win32)
                e.cancelBubble = true;
                e.returnValue  = false;
                /*@end@*/
                return false;
        },
        dateFormat: function(dateIn, favourDMY) {
                if(/^(\d\d\d\d)$/.test(dateIn)) return String(dateIn);
                
                var dateTest = [
                        { regExp:/^(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])([- \/.])((\d\d)?\d\d)$/, d:3, m:1, y:5 },  // mdy
                        { regExp:/^(0?[1-9]|[12][0-9]|3[01])([- \/.])(0?[1-9]|1[012])([- \/.])((\d\d)?\d\d)$/, d:1, m:3, y:5 },  // dmy
                        { regExp:/^(\d\d\d\d)([- \/.])(0?[1-9]|1[012])([- \/.])(0?[1-9]|[12][0-9]|3[01])$/, d:5, m:3, y:1 }      // ymd
                        ];
                var start;
                var cnt = 0;
                var numFormats = dateTest.length;
                while(cnt < numFormats) {
                        start = (cnt + (favourDMY ? numFormats + 1 : numFormats)) % numFormats;
                        if(dateIn.match(dateTest[start].regExp)) {
                                res = dateIn.match(dateTest[start].regExp);
                                y = res[dateTest[start].y];
                                m = res[dateTest[start].m];
                                d = res[dateTest[start].d];
                                if(m.length == 1) m = "0" + String(m);
                                if(d.length == 1) d = "0" + String(d);
                                if(y.length != 4) y = (parseInt(y) < 50) ? "20" + String(y) : "19" + String(y);

                                return y+String(m)+d;
                        };
                        cnt++;
                };
                return 0;
        },
        sortNumeric:function(a,b) {
                var aa = a[0];
                var bb = b[0];
                if(aa == bb) return 0;
                if(aa === "" && !isNaN(bb)) return -1;
                if(bb === "" && !isNaN(aa)) return 1;
                return aa - bb;
        },
        sortText:function(a,b) {
                var aa = a[0];
                var bb = b[0];
                if(aa == bb) return 0;
                if(aa < bb)  return -1;
                return 1;
        },
        truePosition:function(element) {
                var pos = fdTableFilter.cumulativeOffset(element);
                if(window.opera) { return pos; }
                var iebody      = (document.compatMode && document.compatMode != "BackCompat")? document.documentElement : document.body;
                var dsocleft    = document.all ? iebody.scrollLeft : window.pageXOffset;
                var dsoctop     = document.all ? iebody.scrollTop  : window.pageYOffset;
                var posReal     = fdTableFilter.realOffset(element);
                return [pos[0] - posReal[0] + dsocleft, pos[1] - posReal[1] + dsoctop];
        },
        realOffset:function(element) {
                var t = 0, l = 0;
                do {
                        t += element.scrollTop  || 0;
                        l += element.scrollLeft || 0;
                        element = element.parentNode;
                } while (element);
                return [l, t];
        },
        cumulativeOffset:function(element) {
                var t = 0, l = 0;
                do {
                        t += element.offsetTop  || 0;
                        l += element.offsetLeft || 0;
                        element = element.offsetParent;
                } while (element);
                return [l, t];
        },
        
        addClass: function(e,c) {
                if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) return;
                e.className += ( e.className ? " " : "" ) + c;
        },

        /*@cc_on
        /*@if (@_win32)
        removeClass: function(e,c) {
                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s*((?:[\S\s]*\S)?)\s*$/, '$1');
        }
        @else @*/
        removeClass: function(e,c) {
                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s)" + c + "(\\s|$)"), " ").replace(/^\s\s*/, '').replace(/\s\s*$/, '');
        }
        /*@end
        @*/
};

fdTableFilter.fdScriptFiles     = document.getElementsByTagName('script');
fdTableFilter.imageLoc          = fdTableFilter.fdScriptFiles[fdTableFilter.fdScriptFiles.length - 1].src.substr(0, fdTableFilter.fdScriptFiles[fdTableFilter.fdScriptFiles.length - 1].src.lastIndexOf("/")) + "/blank.gif",
fdTableFilter.fdScriptFiles     = null;
delete(fdTableFilter.fdScriptFiles);

fdTableFilter.addEvent(window, "load", fdTableFilter.init);
fdTableFilter.addEvent(window, "unload", fdTableFilter.unLoad);
