/*
        TableSort revisited v2.9 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 fdTableSort = {

        regExp_Currency:        /^[£$€¥¤]/,
        regExp_Number:          /^(\-)?[0-9]+(\.[0-9]*)?$/,
        pos:                    -1,
        uniqueHash:             1,
        thNode:                 null,
        tableCache:             {},
        tableId:                null,

        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, false );
        },

        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;
        },

        init: function() {
                if (!document.getElementsByTagName) return;

                var tables = document.getElementsByTagName('table');
                var sortable, headers, thtext, aclone, a, span, columnNum, noArrow, reverseSortOnInit;

                a               = document.createElement("a");
                a.href          = "#";
                a.onkeypress    = fdTableSort.keyWrapper;

                span            = document.createElement("span");

                for(var t = 0, tbl; tbl = tables[t]; t++) {
                
                        headers = fdTableSort.getTableHeaders(tbl);
                        
                        sortable  = false;
                        columnNum = tbl.className.search(/sortable-onload-([0-9]+)/) != -1 ? parseInt(tbl.className.match(/sortable-onload-([0-9]+)/)[1]) - 1 : -1;
                        showArrow = tbl.className.search(/no-arrow/) == -1;
                        reverse   = tbl.className.search(/sortable-onload-([0-9]+)-reverse/) != -1;
                        
                        // Remove any old dataObj for this table (tables created from an ajax callback require this)
                        if(tbl.id && tbl.id in fdTableSort.tableCache) delete fdTableSort.tableCache[tbl.id];

                        var colCnt = -1;
                        
                        for (var z=0, th; th = headers[z]; z++) {
                        
                                colCnt += th.getAttribute("colspan") ? Number(th.getAttribute("colspan")) : 1;
                                
                                if(th.className && th.className.match('sortable') && (!th.getAttribute("colspan") || th.getAttribute("colspan") == 1)) {

                                        // Remove previously applied classes for the ajaxers also
                                        th.className = th.className.replace(/forwardSort|reverseSort/, "");

                                        if(colCnt == columnNum) sortable = th;
                                        thtext = fdTableSort.getInnerText(th);

                                        while(th.firstChild) th.removeChild(th.firstChild);

                                        // Create the link
                                        aclone = a.cloneNode(true);
                                        aclone.appendChild(document.createTextNode(thtext));
                                        aclone.title = "Sort on " + thtext;
                                        a.onclick = th.onclick = fdTableSort.clickWrapper;
                                        th.appendChild(aclone);

                                        // Add the span if needs be
                                        if(showArrow) th.appendChild(span.cloneNode(false));

                                        var cn = "fd-column-" + colCnt;
                                        th.className = th.className.replace(/fd-identical|fd-not-identical/, "").replace(/fd-column-([0-9]+)/, "") + " " + cn;
                                        fdTableSort.disableSelection(th);
                                };
                        };

                        if(sortable) {
                                fdTableSort.thNode = sortable;
                                fdTableSort.initSort();
                                if(reverse) {
                                        fdTableSort.thNode = sortable;
                                        fdTableSort.initSort();
                                };
                        };
                };
        },
        
        disableSelection: function(element) {
                element.onselectstart = function() {
                        return false;
                };
                element.unselectable = "on";
                element.style.MozUserSelect = "none";
        },
        
        getTableHeaders: function(tbl) {
                var headers;
                var thead = tbl.getElementsByTagName('thead');

                if(thead && thead.length) {
                        thead = thead[0];
                        headers = thead.getElementsByTagName('tr');
                        headers = headers[headers.length - 1].getElementsByTagName('th');
                } else {
                        headers = tbl.getElementsByTagName('th');
                }
                return headers;
        },
        
        countColumns: function(thList) {
                var colCnt = 0;
                for(var i = 0, th; th = thList[i]; i++) {
                        colCnt += th.getAttribute("colspan") ? Number(th.getAttribute("colspan")) : 1;
                };

                return colCnt;
        },
        
        getTH: function(thList, pos) {
                var thList = fdTableSort.thNode.parentNode.getElementsByTagName("th");

                for(var i = 0, th; th = thList[i]; i++) {
                        var re = new RegExp( "(fd-column-" + pos + ")([^0-9]+)" );
                        if(th.className.search(re) != -1) return th;
                };
        },
        
        clickWrapper: function(e) {
                e = e || window.event;
                if(fdTableSort.thNode == null) {
                        fdTableSort.thNode = this;
                        fdTableSort.addSortActiveClass();
                        setTimeout("fdTableSort.initSort()",5);

                };
                return fdTableSort.stopEvent(e);
        },

        keyWrapper: function(e) {
                e = e || window.event;
                var kc = e.keyCode != null ? e.keyCode : e.charCode;
                if(kc == 13) {
                        var targ = this;
                        while(targ.tagName.toLowerCase() != "th") targ = targ.parentNode;

                        fdTableSort.thNode = targ;
                        fdTableSort.addSortActiveClass();
                        setTimeout("fdTableSort.initSort()",5);

                        return fdTableSort.stopEvent(e);
                };
                return true;
        },

        jsWrapper: function(tableid, colNum) {
                var table = document.getElementById(tableid);
                fdTableSort.thNode = fdTableSort.getTH(table.getElementsByTagName('th'), colnum);
                if(!fdTableSort.thNode || fdTableSort.thNode.className.search(/fd-column/) == -1) return false;
                fdTableSort.addSortActiveClass();
                fdTableSort.initSort();
        },

        addSortActiveClass: function() {
                if(fdTableSort.thNode == null) return;
                fdTableSort.addClass(fdTableSort.thNode, "sort-active");
                fdTableSort.addClass(document.getElementsByTagName('body')[0], "sort-active");
                if("sortInitiatedCallback" in window) {
                        var tableElem   = fdTableSort.thNode;
                        while(tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
                                tableElem = tableElem.parentNode;
                        };
                        sortInitiatedCallback(tableElem.id);
                };
        },

        removeSortActiveClass: function() {
                fdTableSort.removeClass(fdTableSort.thNode, "sort-active");
                fdTableSort.removeClass(document.getElementsByTagName('body')[0], "sort-active");
                if("sortCompleteCallback" in window) {
                        var tableElem   = fdTableSort.thNode;
                        while(tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
                                tableElem = tableElem.parentNode;
                        };
                        sortCompleteCallback(tableElem.id);
                };
        },

        addClass: function(e,c) {
                if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) return;
                e.className += ( e.className ? " " : "" ) + c;
        },

        removeClass: function(e,c) {
                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), "");
        },

        prepareTableData: function(table) {
                // Create a table id if needs be
                if(!table.id) table.id = "fd-table-" + fdTableSort.uniqueHash++;

                var data = [];

                var start = table.getElementsByTagName('tbody');
                start = start.length ? start[0] : table;

                var trs = start.getElementsByTagName('tr');
                var ths = fdTableSort.getTableHeaders(table);

                var numberOfRows = trs.length;
                var numberOfCols = fdTableSort.countColumns(ths);

                var data = [];
                var identical = new Array(numberOfCols);
                var identVal  = new Array(numberOfCols);

                var tr, td, th, txt, tds, col, row;

                var rowCnt = 0;

                // Start to create the 2D matrix of data
                for(row = 0; row < numberOfRows; row++) {

                        tr              = trs[row];

                        // Have we any th tags or are we in a tfoot ?
                        if(tr.getElementsByTagName('th').length > 0 || (tr.parentNode && tr.parentNode.tagName.toLowerCase() == "tfoot")) continue;

                        data[rowCnt]    = [];
                        tds             = tr.getElementsByTagName('td');
                        col             = -1;

                        for(var tmp = 0, th; th = ths[tmp]; tmp++) {

                                col += th.getAttribute("colspan") ? Number(th.getAttribute("colspan")) : 1;

                                if(th.className.search(/sortable/) == -1 || (th.getAttribute("colspan") && Number(th.getAttribute("colspan")) > 1)) continue;

                                td  = tds[col];

                                txt = fdTableSort.getInnerText(td) + " ";

                                txt = txt.replace(/^\s+/,'').replace(/\s+$/,'');

                                if(th.className.search(/sortable-date/) != -1) {
                                        txt = fdTableSort.dateFormat(txt, th.className.search(/sortable-date-dmy/) != -1);
                                } else if(th.className.search(/sortable-numeric|sortable-currency/) != -1) {
                                        txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
                                        if(isNaN(txt)) txt = "";
                                } else if(th.className.search(/sortable-text/) != -1) {
                                        txt = txt.toLowerCase();
                                } else if(th.className.search(/sortable-([a-zA-Z\_]+)/) != -1) {
                                        if((th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData") in window) {
                                                txt = window[th.className.match(/sortable-([a-zA-Z\_]+)/)[1] + "PrepareData"](td, txt);
                                        };
                                } else {
                                        if(txt != "") {
                                                fdTableSort.removeClass(th, "sortable");
                                                if(fdTableSort.dateFormat(txt) != 0) {
                                                        fdTableSort.addClass(th, "sortable-date");
                                                        txt = fdTableSort.dateFormat(txt);
                                                } else if(txt.search(fdTableSort.regExp_Number) != -1 || txt.search(fdTableSort.regExp_Currency) != -1) {
                                                        fdTableSort.addClass(th, "sortable-numeric");
                                                        txt = parseFloat(txt.replace(/[^0-9\.\-]/g,''));
                                                        if(isNaN(txt)) txt = "";
                                                } else {
                                                        fdTableSort.addClass(th, "sortable-text");
                                                        txt = txt.toLowerCase();
                                                };
                                        };
                                };

                                if(rowCnt > 0 && identVal[col] != txt) {
                                        identical[col] = false;
                                };

                                identVal[col]     = txt;
                                data[rowCnt][col] = txt;
                        };

                        // Add the tr for this row
                        data[rowCnt][numberOfCols] = tr;

                        // Increment the row count
                        rowCnt++;
                }

                // Get the row and column styles
                var colStyle = table.className.search(/colstyle-([\S]+)/) != -1 ? table.className.match(/colstyle-([\S]+)/)[1] : false;
                var rowStyle = table.className.search(/rowstyle-([\S]+)/) != -1 ? table.className.match(/rowstyle-([\S]+)/)[1] : false;

                // Cache the data object for this table
                fdTableSort.tableCache[table.id] = { data:data, pos:-1, identical:identical, colStyle:colStyle, rowStyle:rowStyle, noArrow:table.className.search(/no-arrow/) != -1 };
        },

        initSort: function() {

                var span;
                var thNode      = fdTableSort.thNode;

                // Get the table
                var tableElem   = fdTableSort.thNode;
                while(tableElem.tagName.toLowerCase() != 'table' && tableElem.parentNode) {
                        tableElem = tableElem.parentNode;
                };

                // If this is the first time that this table has been sorted, create the data object
                if(!tableElem.id || !(tableElem.id in fdTableSort.tableCache)) {
                        fdTableSort.prepareTableData(tableElem);
                };

                // Cache the table id
                fdTableSort.tableId = tableElem.id;

                // Get the column position using the className added earlier
                fdTableSort.pos = thNode.className.match(/fd-column-([0-9]+)/)[1];

                // Grab the data object for this table
                var dataObj     = fdTableSort.tableCache[tableElem.id];

                // Get the position of the last column that was sorted
                var lastPos     = dataObj.pos;

                // Get the stored data object for this table
                var data        = dataObj.data;
                var colStyle    = dataObj.colStyle;
                var rowStyle    = dataObj.rowStyle;
                var len1        = data.length;
                var len2        = data[0].length - 1;
                var identical   = dataObj.identical[fdTableSort.pos] == false ? false : true;
                var noArrow     = dataObj.noArrow;

                if(lastPos != fdTableSort.pos && lastPos != -1) {
                        var th = fdTableSort.getTH(thNode.parentNode.getElementsByTagName('th'), lastPos);

                        fdTableSort.removeClass(th, "forwardSort");
                        fdTableSort.removeClass(th, "reverseSort");
                        if(!noArrow) {
                                // Remove arrow
                                span = th.getElementsByTagName('span')[0];
                                while(span.firstChild) span.removeChild(span.firstChild);
                        };
                };

                // If the same column is being sorted then just reverse the data object contents.
                var classToAdd = "forwardSort";

                if(lastPos == fdTableSort.pos && !identical) {
                        data.reverse();
                        classToAdd = thNode.className.search(/reverseSort/) != -1 ? "forwardSort" : "reverseSort";
                } else {
                        fdTableSort.tableCache[tableElem.id].pos = fdTableSort.pos;
                        if(!identical) {
                                if(thNode.className.match(/sortable-numeric|sortable-currency|sortable-date/)) {
                                        data.sort(fdTableSort.sortNumeric);
                                } else if(thNode.className.match('sortable-text')) {
                                        data.sort(fdTableSort.sortText);
                                } else if(thNode.className.search(/sortable-([a-zA-Z\_]+)/) != -1 && thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1] in window) {
                                        data.sort(window[thNode.className.match(/sortable-([a-zA-Z\_]+)/)[1]]);
                                };
                        };
                };

                fdTableSort.removeClass(thNode, "forwardSort");
                fdTableSort.removeClass(thNode, "reverseSort");
                fdTableSort.addClass(thNode, classToAdd);

                if(!noArrow) {
                        var arrow = thNode.className.search(/forwardSort/) != -1 ? " \u2193" : " \u2191";
                        span = thNode.getElementsByTagName('span')[0];
                        while(span.firstChild) span.removeChild(span.firstChild);
                        span.appendChild(document.createTextNode(arrow));
                };

                if(!rowStyle && !colStyle && identical) {
                        fdTableSort.removeSortActiveClass();
                        fdTableSort.thNode = null;
                        return;
                }

                var hook = tableElem.getElementsByTagName('tbody');
                hook = hook.length ? hook[0] : tableElem;

                var td, tr;

                for(var i = 0; i < len1; i++) {
                        tr = data[i][len2];
                        if(colStyle) {
                                if(lastPos != -1) {
                                        fdTableSort.removeClass(tr.getElementsByTagName('td')[lastPos], colStyle);
                                }
                                fdTableSort.addClass(tr.getElementsByTagName('td')[fdTableSort.pos], colStyle);
                        };
                        if(!identical) {

                                if(rowStyle) {
                                        if(i % 2) fdTableSort.addClass(tr, rowStyle);
                                        else fdTableSort.removeClass(tr, rowStyle);
                                };

                                hook.removeChild(tr); /* Netscape 8.1.2 requires the removeChild call */
                                hook.appendChild(tr);
                        };
                };
                fdTableSort.removeSortActiveClass();
                fdTableSort.thNode = null;
        },

        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 += fdTableSort.getInnerText(i);
                };

                return txt;
        },
        
        dateFormat: function(dateIn, favourDMY) {
                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;

                while(cnt < 3) {
                        start = (cnt + (favourDMY ? 4 : 3)) % 3;

                        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" + m;
                                if(d.length == 1) d = "0" + d;
                                if(y.length != 4) y = (parseInt(y) < 50) ? '20' + y : '19' + y;

                                return y+m+d;
                        }

                        cnt++;
                }

                return 0;
        },

        sortDate: function(a,b) {
                var aa = a[fdTableSort.pos];
                var bb = b[fdTableSort.pos];

                return aa - bb;
        },

        sortNumeric:function (a,b) {
                var aa = a[fdTableSort.pos];
                var bb = b[fdTableSort.pos];

                if(aa === "" && !isNaN(bb)) return -1;
                else if(bb === "" && !isNaN(aa)) return 1;
                else if(aa == bb) return 0;

                return aa - bb;
        },

        sortText:function (a,b) {
                var aa = a[fdTableSort.pos];
                var bb = b[fdTableSort.pos];

                if(aa == bb) return 0;
                if(aa < bb)  return -1;

                return 1;
        }
};

// fdTableSort.addEvent(window, "load", fdTableSort.init);
YAHOO.util.Event.onDOMReady(fdTableSort.init);

/*
   sortEnglishLonghandDateFormat
   -----------------------------
   
   This custom sort function sorts dates of the format:

   "12th April, 2006" or "12 April 2006" or "12-4-2006" or "12 April" or "12 4" or "12 Apr 2006" etc
   
   The function expects dates to be in the format day/month/year. Should no year be stipulated,
   the function treats the year as being the current year (which requires the users P.C. clock to be correctly set).
   
   The function is "safe" i.e. non-date data (like the word "Unknown") can be passed in and is sorted properly.
*/
function sortEnglishLonghandDateFormat(a, b) {
        // Get the innerText of the TD nodes
        var aa = a[fdTableSort.pos];
        var bb = b[fdTableSort.pos];

        return aa - bb;
}

function sortEnglishLonghandDateFormatPrepareData(tdNode, innerText) {
        var months = new Array('january','february','march','april','may','june','july','august','september','october','november','december');

        var aa = innerText;
        
        // Replace the longhand months with an integer equivalent
        for(var i = 0; i < 12; i++) {
                aa = aa.replace(months[i], i+1, "ig").replace(months[i].substring(0,3), i+1, "ig");
        }

        // If there are still alpha characters then return -1
        if(aa.search(/a-z/) != -1) return -1;

        // Replace multiple spaces and anything that is not alphanumeric
        aa = aa.replace(/\s+/g, " ").replace(/[^\d\s]/g, "");

        // If were left with nothing then return -1
        if(aa.replace(" ", "") == "") return -1;

        // Split on the (now) single spaces
        aa = aa.split(" ");

        // If something has gone terribly wrong then return -1
        if(aa.length < 2) return -1;

        // If no year stipulated, then add this year as default
        // Warning: requires the users clock to be set to the correct year!
        if(aa.length == 2) {
                aa[2] = String(new Date().getFullYear());
        }

        // Equalise the day and month
        if(aa[0].length < 2) aa[0] = "0" + aa[0];
        if(aa[1].length < 2) aa[1] = "0" + aa[1];

        // Deal with Y2K issues
        if(aa[2].length != 4) {
                aa[2] = (parseInt(aa[2]) < 50) ? '20' + aa[2] : '19' + aa[2];
        }

        // YMD (can be used as integer during comparison)
        return aa[2] + aa[1] + aa[0];
}

/* The sortCompleteCallback does nothing but call the pagination object below, passing in the table id */
function sortCompleteCallback(tableId) {
        tablePaginater.showPage(tableId);
}

/* This is the JS object that paginates the table (N.B: Tables do not have to be sortable to use this object) */
var tablePaginater = {
        tableInfo: {},
        
        init: function() {
                var tables = document.getElementsByTagName('table');
                
                for(var t = 0, tbl; tbl = tables[t]; t++) {
                        if(!tbl.id || tbl.id == "" || tbl.className.search(/paginate-([0-9]+)/) == -1) continue;

                        tablePaginater.tableInfo[tbl.id] = {
                                rowsPerPage:tbl.className.match(/paginate-([0-9]+)/)[1],
                                currentPage:0
                        };
                        
                        tablePaginater.showPage(tbl.id, 0);
                        tablePaginater.createPageinationList(tbl.id);
                };
        },
        
        addClass: function(e,c) {
                if(new RegExp("(^|\\s)" + c + "(\\s|$)").test(e.className)) return;
                e.className += ( e.className ? " " : "" ) + c;
        },

        removeClass: function(e,c) {
                e.className = !c ? "" : e.className.replace(new RegExp("(^|\\s*\\b[^-])"+c+"($|\\b(?=[^-]))", "g"), "");
        },
        
        /* I shall leave it as an excercise for the reader to create the next|prev links commonly
           found within such pagination systems. I'm just creating simple linked lists.       */
        createPageinationList: function(tableId) {
                // Get the table
                var tbl = document.getElementById(tableId);
        
                // Create the UL
                var ul = document.createElement("ul");
                ul.className = "tablePaginater";
                ul.id = "paginateList-" + tableId;
                
                // clone the UL
                var ulc = ul.cloneNode(true);
                ulc.id =  "paginateList-" + tableId + "-clone";
                
                var rows = tablePaginater.getTableRows(tableId);
                var total = rows.length;
                var rowsPerPage
                var pages = Math.max(1, Math.ceil(total / tablePaginater.tableInfo[tableId].rowsPerPage));
                
                // Create the li & a tags to clone within the loop
                var li = document.createElement("li");
                var a  = document.createElement("a");
                a.href = "#";
                
                var lic, ac;
                
                // For each page, create a pagination button
                for(var i = 0; i < pages; i++) {
                        lic = li.cloneNode(false);
                        ac  = a.cloneNode(true);
                        ac.title = "View page " + (i + 1);
                        ac.appendChild(document.createTextNode(i+1));
                        lic.onclick = a.onclick = tablePaginater.show;
                        lic.appendChild(ac);
                        
                        if(i == 0) lic.className = "currentPage";

                        ul.appendChild(lic);
                        
                        lic = lic.cloneNode(true);
                        lic.onclick = lic.getElementsByTagName("a")[0].onclick = tablePaginater.show;
                        
                        ulc.appendChild(lic);
                };
                
                // Add the list below the table
                if(tbl.nextSibling) {
                        tbl.parentNode.insertBefore(ul, tbl.nextSibling);
                } else {
                        tbl.parentNode.appendChild(ul);
                };

                // Add another list above the table
                tbl.parentNode.insertBefore(ulc, tbl);
        },
        
        getTableRows: function(tableId) {
                var rows = [];
                var tbl = document.getElementById(tableId);
                
                var tbody = tbl.getElementsByTagName('tbody');

                if(tbody && tbody.length) {
                        tbody = tbody[0];
                        rows = tbody.getElementsByTagName('tr');
                } else {
                        var tmp = tbl.getElementsByTagName('tr');
                        for(var i = tmp.length; i--;) {
                                if(tmp[i].getElementsByTagName('th') || tmp[i].parentNode.tagName == "TFOOT") continue;
                                rows[rows.length] = tmp[i];
                        };
                };
                return rows;
        },
        
        showPage: function(tableId, page) {
                if(!(tableId in tablePaginater.tableInfo)) return;
                
                var tbl = document.getElementById(tableId);
                var rowsPerPage = tablePaginater.tableInfo[tableId].rowsPerPage;
                var rows = tablePaginater.getTableRows(tableId);
                
                page = typeof page == "undefined" ? tablePaginater.tableInfo[tableId].currentPage : page;

                var min = rowsPerPage * page;
                var max = Number(min) + Number(rowsPerPage);
                var rowStyle = tbl.className.search(/rowstyle-([\S]+)/) != -1 ? tbl.className.match(/rowstyle-([\S]+)/)[1] : false;
                var cnt = 0;
                var len = rows.length;
                
                for(var i = 0; i < len; i++) {
                        rows[i].style.display = (i >= min && i < max) ? "" : "none";
                        if(rowsPerPage % 2 && rowStyle && i >= min && i < max) {
                                tablePaginater.removeClass(rows[i], rowStyle);
                                if(cnt++ % 2) tablePaginater.addClass(rows[i], rowStyle);
                        };
                };
                
                tablePaginater.tableInfo[tableId].currentPage = page;
        },

        /* Event handler for the li|a click event */
        show: function(e) {
                var li = (this.tagName && this.tagName == "A") ? this.parentNode : this;
                var tableId = li.parentNode.id.replace("paginateList-", "").replace("-clone", "");
                var cnt     = 0;

                while(li.previousSibling) {
                        li = li.previousSibling;
                        if(li.tagName && li.tagName.toLowerCase() == "li") cnt++;
                };
                
                tablePaginater.showPage(tableId, cnt);

                var ul  = document.getElementById("paginateList-" + tableId);
                var ulc = document.getElementById("paginateList-" + tableId + "-clone");
                var i   = 0;
                
                while(ul.childNodes[i]) {
                        ul.childNodes[i].className = ulc.childNodes[i].className = i == cnt ? "currentPage" : "";
                        i++;
                };
                
                return false;
        }
}


YAHOO.util.Event.onDOMReady(tablePaginater.init);
// fdTableSort.addEvent(window, "load", tablePaginater.init);


/*
   sortFileSize
        ------------
        
        1 Byte = 8 Bit
        1 Kilobyte = 1024 Bytes
        1 Megabyte = 1048576 Bytes
        1 Gigabyte = 1073741824 Bytes
*/
function sortFileSize(a, b) { return fdTableSort.sortNumeric(a, b); }

function sortFileSizePrepareData(td, innerText) {
        var regExp = /(kb|mb|gb)/i;

        var type = innerText.search(regExp) != -1 ? innerText.match(regExp)[0] : "";
        
        switch (type.toLowerCase()) {
                case "kb" :
                        mult = 1024;
                        break;
                case "mb" :
                        mult = 1048576;
                        break;
                case "gb" :
                        mult = 1073741824;
                        break;
                default :
                        mult = 1;
        }
        
        innerText = parseFloat(innerText.replace(/[^0-9\.\-]/g,''));
         return isNaN(innerText) ? "" : innerText * mult;
}