var tblSort = {

    that: false,
    isOdd: false,
    isParentRow: false,
    isLastJoined: false,
    isJoinedRow: false,
    lLink: false,
    sortColumnIndex: -1,
    lastAssignedId: 0,
    newRows: -1,
    lastSortedTable: -1,
    lastOrder: "",
    isRawjQuerySort: false,
    msg: "",

    /**
    * Initialises the Standardista Table Sorting module
    **/
    init: function() {
        // first, check whether this web browser is capable of running this script
        if (!document.getElementsByTagName) {
            return;
        }

        this.that = this;
        //this.run();        
    },

    /**
    * Runs over each table in the document, making it sortable if it has a class
    * assigned named "sortable" and an id assigned.
    **/
    run: function() {
        var tables = document.getElementsByTagName("table");

        for (var i = 0; i < tables.length; i++) {
            var thisTable = tables[i];

            if (css.elementHasClass(thisTable, 'scrollTable')) {
                this.makeSortable(thisTable);
            }

            /*if (css.elementHasClass(thisTable, 'sortable')) {
            this.makeSortable(thisTable);
            }*/
        }
    },

    /**
    * Makes the given table sortable.
    **/
    makeSortable: function(table) {

        // first, check if the table has an id.  if it doesn't, give it one
        if (!table.id) {
            table.id = 'sortableTable' + this.lastAssignedId++;
        }

        // if this table does not have a thead, we don't want to know about it
        if (!table.tHead || !table.tHead.rows || 0 == table.tHead.rows.length) {
            return;
        }

        // we'll assume that the last row of headings in the thead is the row that 
        // wants to become clickable
        var row = table.tHead.rows[table.tHead.rows.length - 1];

        for (var i = 0; i < row.cells.length; i++) {

            // create a link with an onClick event which will 
            // control the sorting of the table
            var linkEl = createElement('a');
            linkEl.href = '#';
            linkEl.onclick = this.headingClicked;
            linkEl.setAttribute('columnId', i);
            linkEl.title = 'Click to sort';

            // move the current contents of the cell that we're 
            // hyperlinking into the hyperlink
            var innerEls = row.cells[i].childNodes;
            for (var j = 0; j < innerEls.length; j++) {
                linkEl.appendChild(innerEls[j]);
            }

            // and finally add the new link back into the cell
            row.cells[i].appendChild(linkEl);

            var spanEl = createElement('span');
            spanEl.className = 'tableSortArrow';
            spanEl.appendChild(document.createTextNode('\u00A0\u00A0'));
            row.cells[i].appendChild(spanEl);

        }

        if (css.elementHasClass(table, 'autostripe')) {
            this.isOdd = false;
            var rows = table.tBodies[0].rows;

            // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
            for (var i = 0; i < rows.length; i++) {
                this.doStripe(rows[i]);
            }
        }
    },


    removeSorted: function(tArray, tTableName) {
        var len = tArray.length;
        var i;
        var lItem;
        var lArray = [];

        for (i = 0; i < len; i++) {
            lItem = tArray[i].split('=');
            if (lItem[0] != tTableName)
                lArray.push(tArray[i]);
        }

        return lArray;
    },


    showMSG: function(tMsg, tColor, e, f) {

        this.that = this;
        if (f) {
            lLink = f;
        }
        else {
            lLink = getEventTarget(e);
        }
        if (tMsg != "") {
            _showProgress(tMsg);
        }
        this.msg = tMsg;
        setTimeout(tblSort.headingClicked, 100, tblSort);

    },


    killMSG: function() {
        if (this.msg != "") {
            _hideProgress();
        }
    },



    headingClicked: function(e) {
        this.sortArray = SortArray._GetSortArray();


        this.that = this;
        var that = tblSort.that;
        var linkEl;
        // linkEl is the hyperlink that was clicked on which caused
        // this method to be called
        if (e == undefined)
            linkEl = lLink;
        else
            linkEl = getEventTarget(e);

        try {
            // directly outside it is a td, tr, thead and table
            var td = linkEl.parentNode;     //ez nálunk a TH0..THx
            var tr = td.parentNode;
            var thead = tr.parentNode;
            var table = thead.parentNode;   //az a tábla, amit sorbarendezünk
            var lSortOrder;
            var txtSorted = $(_prefix + "txtSorted");
            var lArrSorted;                 //amik alapján rendez(zük/tük)
            var lDiv = table.parentNode;    //overDiv            

            /* 
            ha a rendezendő oszlop részletezett adatokat tartalmaz, akkor
            meg kell jeleníteni a rejtett főadatokat 
            (főadat oszlopának választásakor ismét elrejthetőek)
            */
            if (css.elementHasClass(td, "detailed")) {
                css.removeClassFromElement(table, "detailshide");
                css.addClassToElement(table, "detailsshow");
            }
            else if (css.elementHasClass(table, "detailsshow")) {
                css.removeClassFromElement(table, "detailsshow");
                css.addClassToElement(table, "detailshide");
            }

            /*var img = document.createElement('img');
            img.src='images/design/inprogress.gif';
            td.appendChild(img);*/

            if (txtSorted != null && txtSorted.value != "")
                lArrSorted = txtSorted.value.split(',');
            else
                lArrSorted = [];

            lArrSorted = that.removeSorted(lArrSorted, table.id);

            //function.js
            setHeaderPos(tr.getElementsByTagName("TH"), lDiv);

            // if the table we're looking at doesn't have any rows
            // (or only has one) then there's no point trying to sort it
            if (!table.tBodies || table.tBodies[0].rows.length <= 1) {
                that.killMSG();
                return false;
            }

            // the column we want is indicated by td.cellIndex
            var column = linkEl.getAttribute('columnId') || td.cellIndex;

            /*
            másodlagos és harmadlagos, stb. oszlopok index-e tömbként
            */
            var order2Name = td.children[1].sortOrder2;
            var columnOrder2Name;
            if (order2Name != null)
                columnOrder2Name = order2Name.split(",");   //span sortOrder2 tulajdonsága tömbként
            // th CSS keresés eredménye indexként
            var columnOrder2 = [];
            var arrtd = tr.children;
            var order2index;
            var hasOrder2CSS;

            if (columnOrder2Name != undefined) {
                //columnOrder2Name neveihez fejlécindex keresése
                for (var ii = 0; ii < columnOrder2Name.length; ii++) {
                    for (var jj = 0; jj < arrtd.length; jj++) {
                        //fejlécben index keresése
                        hasOrder2CSS = css.elementHasClass(arrtd[jj], columnOrder2Name[ii]);
                        if (hasOrder2CSS) {
                            order2index = jj;
                            break;
                        }
                        else
                            order2index = -1;
                    }
                    if (order2index > -1) {
                        //ha szerepel fejlécben, akkor columnOrder2 tömbhöz adás
                        columnOrder2.push(order2index);
                    }
                }
            }


            // find out what the current sort order of this column is
            var arrows = jQuery.art.getElementsByClass(td, 'tableSortArrow', 'span');      //megkeressük a nyilat
            var previousSortOrder = '';
            if (arrows.length > 0) {
                previousSortOrder = arrows[0].getAttribute('sortOrder');            //ennek sortOrder tulajdonsága ASC/DESC

            }


            // work out how we want to sort this column using the data in the first cell
            // but just getting the first cell is no good if it contains no data
            // so if the first cell just contains white space then we need to track
            // down until we find a cell which does contain some actual data
            //azaz megkeressük a legfelső olyan cellát a kiválaszott oszlopban, amiben van 'adat'
            var itm = '';
            var rowNum = 0;
            var sortfn;

            // jQuery raw rendezés szükségességének vizsgálata
            if (linkEl.sortRawjQuery) {
                sortfn = that.sortRawjQuery;
                that.isRawjQuerySort = true;
            }
            else {
                while (!itm || rowNum < table.tBodies[0].rows.length) {
                    itm = that.getInnerText(table.tBodies[0].rows[rowNum].cells[column]);
                    rowNum++;
                }
                that.isRawjQuerySort = false;
                sortfn = that.determineSortFunction(itm);
            }

            if (sortfn == false) {
                that.killMSG();
                return false;
            }
            // if the last column that was sorted was this one, then all we need to 
            // do is reverse the sorting on this column

            //különgyűjtjük a sorokat, és a kiegészítő sorokat
            var newRows = [];          //rendezedő row-ok
            var subRows = [];          //azok kapcsolt sorai
            var attachNormToSub = [];  //melyik kapcsolt sor melyik rendezendőhöz tartozik att.NormToSub[kapcs.index]==norm.index
            var normrow = 0;                    //rendezendő sorok száma
            var subrow = 0;                     //kapcsolt sorok száma
            var actRow, cn;

            for (var j = 0; j < table.tBodies[0].rows.length; j++) {
                actRow = table.tBodies[0].rows[j];  //aktuális sor
                if (/listitemfocus/.test(actRow.className)) {
                    actRow.className = actRow.className.replace(/listitemfocus/g, "listitemout");
                }
                cn = actRow.className;

                //kapcsolt?
                if (/joinedrow/.test(cn)) {
                    subRows[subrow] = actRow;
                    attachNormToSub[subrow] = normrow - 1;  //normrow=darabszám, az index 1-gyel kisebb
                    subrow++;
                } else {
                    newRows[normrow] = actRow;
                    normrow++;
                }
            }


            if ((table.id == that.lastSortedTable && column == that.sortColumnIndex) || previousSortOrder) {
                newRows.reverse();
            }
            else {
                if (td.children[1] && td.children[1].className == 'tableSortArrow') {
                    //newRows.reverse();
                    that.sortColumnIndex = column;
                    newRows = that.sortOrder2(newRows, that.sortColumnIndex, columnOrder2);
                }
                else {
                    that.sortColumnIndex = column;
                    /*
                    egyszeri rendezés rekurzióval (belépéskor már rendez ...)
                    */
                    newRows = that.sortOrder2(newRows, that.sortColumnIndex, columnOrder2);
                    //            newRows.sort(sortfn);
                    //            if (columnOrder2.length > 0 && newRows.length > 2) {
                    //                // másodlagos rendezés
                    //                newRows = that.sortOrder2(newRows, that.sortColumnIndex, columnOrder2);
                    //            }
                }
            }
            //visszatesszük newRows sorai közé az oda tartozó subrow-okat
            //ez lesz a kiegészített tömb
            var attachedRows = [];
            var attrowi = 0;
            var srowi, nrowi, eredetiindex;
            //attrowi elvileg mindig nrowi+srowi összege (az összefésült tömbben hol tartunk)
            for (srowi = 0; srowi < subrow; srowi++) {
                if (attachedRows[srowi] == -1) {
                    attachedRows[attrowi] = subRows[srowi];
                    attrowi++;
                }
            }
            for (nrowi = 0; nrowi < normrow; nrowi++) {
                eredetiindex = nrowi;
                //newRows[nrowi].deleteCell(newRows[nrowi].cells.length - 1);
                attachedRows[attrowi] = newRows[nrowi];           //következő NORMÁL az összefésültbe
                attrowi++;
                for (srowi = 0; srowi < subrow; srowi++) {        //amíg az aktuális NORMÁLhoz tartoznak a SUB-ok:
                    if (attachNormToSub[srowi] == eredetiindex) {
                        attachedRows[attrowi] = subRows[srowi];   //összefésültbe a SUB
                        attrowi++;
                    }
                }
            }
            newRows = attachedRows;

            that.moveRows(table, newRows);
            that.newRows = newRows;
            that.lastSortedTable = table.id;

            // now, give the user some feedback about which way the column is sorted

            // first, get rid of any arrows in any heading cells - összes nyilat eltűnteti, span-t tesz a helyére?
            var arrows = jQuery.art.getElementsByClass(tr, 'tableSortArrow', 'span');
            for (var j = 0; j < arrows.length; j++) {
                var arrowParent = arrows[j].parentNode;
                arrowParent.removeChild(arrows[j]);
                arrowParent.style.fontStyle = "normal";
                //tr.getElementsByTagName("SPAN");
                if (arrowParent != td) {
                    spanEl = createElement('span');
                    spanEl.className = 'tableSortArrow';
                    //Töröltem, mert 2 db &nbsp;-t rakott bele, ami nagyon zavaró volt,
                    //ha a jobbra igazított oszlopokról lekeült a rendezettség
                    //spanEl.appendChild(document.createTextNode('\u00A0\u00A0'));
                    arrowParent.appendChild(spanEl);
                }
                else {
                    arrowParent.style.fontStyle = "italic";
                }
            }

            // now, add back in some feedback 
            var spanEl = createElement('span');
            spanEl.className = 'tableSortArrow';
            if ('ASC' == previousSortOrder) {
                //if (!previousSortOrder || ('ASC' == previousSortOrder)) {
                lSortOrder = 'DESC';
                //spanEl.appendChild(document.createTextNode(' \u2191'));
                spanEl.appendChild(document.createTextNode(' \u2193'));
                spanEl.setAttribute('sortOrder', lSortOrder);
            }
            else {
                lSortOrder = 'ASC';
                //spanEl.appendChild(document.createTextNode(' \u2193'));
                spanEl.appendChild(document.createTextNode(' \u2191'));
                spanEl.setAttribute('sortOrder', lSortOrder);
            }

            td.appendChild(spanEl);

            if (txtSorted != null) {
                lArrSorted.push(table.id + "=" + column + "=" + lSortOrder);
                txtSorted.value = lArrSorted.toString();
            }

            table.children[1].children[0].className = table.children[1].children[0].className.replace(/listitemout/g, "listitemfocus");

            //Esmények panelen nem ugrik a tetejére rendezés után
            if (jQuery(".divEVENTSINDOCSpnlHeaderDiv.tableContainer")[0]) {
                jQuery(".zoomTextDiv.zoomeddiv").scrollTop(0);
            }

            //Lexikális adatoknál egy click eseményt generál, ami alapján újra kell generálni a lebegő fejléceket
            /*sortingEndedDiv = jQuery("#SortingEnded")
            if (sortingEndedDiv.length > 0) {
            sortingEndedDiv.click();
            }*/


        }
        catch (ex) {
        }

        //linkEl.focus();
        that.killMSG();
        return false;
    },


    showProgressLittle: function() {
        overwin("<img src='images/design/inprogress.gif' />", 'WIDTH', 32, 'HELP');
    },

    sortOrder2: function(tArrTr, tColumn, tOrder2) {
        /*
        Minden tColoumn szerint azonos sor kivágása egy új tömbbe, 
        és a tömbök újrarendezése másodlagos, stb. oszlop szerint.
                
        Minden csoport rekúrzív újrarendezése
        */
        var lastCell = "";
        var newCell = "";
        var unique = true;          //csoportrendezéshez új sor egyedisége 
        var lastunique = true;      //post tömbhöz adásnál az előző sor egyedisége
        var lOrder2Grp;             //csoportonként módosított másodlagos rendezés
        var lnewArrTr = [];
        var slArrTr;
        var slArrNewTr;
        var slStart;                //csoport kivágás kezdő index
        var slEnd;                  //csoport kivágás befejező index
        var shColumn;               //soron következő (shiftelt) tColumn
        var lastR;                  //utolsó sor, ami már nem ciklus alatti feldolgozást igényel

        // --------------------------------
        // rendezés belépéskor - 
        //  automatizált rekúrzív rendezés 
        //  (nem szükséges előre rendezni)
        var lGrpitm;                //rendezési methodus helyi változói
        var lGrprowNum;
        var lGrpsortfn;
        var prevThat;

        prevThat = this.that;       // globális determineSortFunction - állapot mentése

        this.that.sortColumnIndex = tColumn;
        lGrpitm = "";
        lGrprowNum = 0;

        if (this.isRawjQuerySort) {
            lGrpsortfn = this.sortRawjQuery;
        }
        else {
            while (!lGrpitm || lGrprowNum < tArrTr.length) {
                lGrpitm = this.getInnerText(tArrTr[lGrprowNum].cells[tColumn]);
                lGrprowNum++;
            }
            lGrpsortfn = this.determineSortFunction(lGrpitm);
        }

        var sortedArr = new Array();
        try {
            if (lGrpsortfn != false) {
                var tempArr;
                sortedArr[0] = tArrTr[0];

                var sorttype = "sortCaseInsensitive2";
                if (lGrpsortfn == this.sortCode) {
                    sorttype = "sortCode";
                }
                else if (lGrpsortfn == this.sortNumeric) {
                    sorttype = "sortNumeric";
                }

                for (var i = 1; i < tArrTr.length; i++) {
                    var newind = sortBinary(tArrTr[i], sortedArr, true, tColumn, sorttype);
                    if (newind < 1) {
                        sortedArr.unshift(tArrTr[i]);
                    }
                    else {
                        var spliced = sortedArr.splice(newind, sortedArr.length - newind);
                        sortedArr[newind] = tArrTr[i];
                        sortedArr = sortedArr.concat(spliced);
                    }
                }
            }
        }
        catch (ex) {
            var s = "";
        }
        tArrTr = sortedArr;

        this.that = prevThat;
        // --------------------------------

        if (tOrder2.length > 0) {
            //ha van előírt másodlagos rendezés, akkor az elsődleges oszlop soraiban azonosság keresése
            // (itt szükséges további rendezés)

            for (var nri = 0; nri < tArrTr.length; nri++) {
                newCell = tArrTr[nri].children[tColumn].innerText;
                if (nri > 0) {
                    unique = (newCell != lastCell);   //false, ha nem egyedi az új cella
                    if (!unique) {
                        //sorok kivágásának paraméterei
                        slStart = (slStart == undefined) ? nri - 1 : slStart;   // slice kezdő poz.
                        slEnd = nri;                                            // slice végső poz.
                    }
                    else {
                        //(csoport)első egyedi sor

                        //előző sor nem csoport eleme
                        if (lastunique) {
                            lnewArrTr.push(lastR);
                        }
                        //ha volt azonos sorokat tartalmazó csoport, akkor rendezése (előző csoport rendezése)
                        if (slStart != undefined) {
                            //csoport újrarendezése az új oszlopok szerint
                            lOrder2Grp = [];
                            lOrder2Grp = lOrder2Grp.concat(tOrder2);       // csoportonkénti másodlagos rendezés
                            shColumn = (lOrder2Grp != null && lOrder2Grp != undefined) ? lOrder2Grp.shift() : null;  // új oszlop a rendezéshez

                            slArrNewTr = tArrTr.slice(slStart, slEnd + 1);      // End paraméter eleme már nincs benne a visszaadott tömb-ben

                            if (shColumn != null) {
                                slArrTr = this.sortOrder2(slArrNewTr, shColumn, lOrder2Grp);
                                lnewArrTr = lnewArrTr.concat(slArrTr);
                            }
                            else
                                lnewArrTr = lnewArrTr.concat(slArrNewTr);
                        }
                        slStart = undefined;
                        slEnd = undefined;
                    }

                    lastunique = unique;
                }

                lastCell = newCell;
                lastR = tArrTr[nri];
            }

            if (lastunique)
                lnewArrTr.push(lastR);
            // -----------------
            //  függvényesíthető rész ???
            // utolsó csoport hozzáfűzése
            if (slStart != undefined) {
                //csoport újrarendezése az új oszlopok szerint
                lOrder2Grp = [];
                lOrder2Grp = lOrder2Grp.concat(tOrder2);       // csoportonkénti másodlagos rendezés
                shColumn = (lOrder2Grp != null && lOrder2Grp != undefined) ? lOrder2Grp.shift() : null;  // új oszlop a rendezéshez

                slArrNewTr = tArrTr.slice(slStart, slEnd + 1);

                if (shColumn != null) {
                    slArrTr = this.sortOrder2(slArrNewTr, shColumn, lOrder2Grp);
                    lnewArrTr = lnewArrTr.concat(slArrTr);
                }
                else
                    lnewArrTr = lnewArrTr.concat(slArrNewTr);
            }
            // -----------------


            return lnewArrTr;               // egyedi sorok, és rekúrzívan rendezett csoportok tömbje
        }
        else
            return tArrTr;                  // eredeti tömb
    },

    sortTable: function(tTableID, tColoumnID, tOrder) {


        this.that = this;

        var that = tblSort.that;

        // linkEl is the hyperlink that was clicked on which caused
        // this method to be called

        // directly outside it is a td, tr, thead and table
        var table = $(tTableID);
        var thead = table.children[0];
        var tr = thead.children[0];
        var td = tr.childNodes[tColoumnID];

        // the column we want is indicated by td.cellIndex
        var column = tColoumnID;

        // work out how we want to sort this column using the data in the first cell
        // but just getting the first cell is no good if it contains no data
        // so if the first cell just contains white space then we need to track
        // down until we find a cell which does contain some actual data
        var itm = ''
        var rowNum = 0;
        var sortfn;

        if (that.isRawjQuerySort) {
            sortfn = that.sortRawjQuery;
        }
        else {
            while (!itm || rowNum < table.tBodies[0].rows.length) {
                itm = that.getInnerText(table.tBodies[0].rows[rowNum].cells[column]);
                rowNum++;
            }
            sortfn = that.determineSortFunction(itm);
        }

        that.sortColumnIndex = column;
        var newRows = [];
        for (var j = 0; j < table.tBodies[0].rows.length; j++) {
            newRows[j] = table.tBodies[0].rows[j];
        }

        newRows.sort(sortfn);

        if (tOrder == "DESC")
            newRows.reverse();

        that.moveRows(table, newRows);

        // now, give the user some feedback about which way the column is sorted

        // first, get rid of any arrows in any heading cells
        var arrows = jQuery.art.getElementsByClass(tr, 'tableSortArrow', 'span');
        for (var j = 0; j < arrows.length; j++) {
            var arrowParent = arrows[j].parentNode;
            arrowParent.removeChild(arrows[j]);
            arrowParent.style.fontStyle = "normal";
            if (arrowParent != td) {
                spanEl = createElement('span');
                spanEl.className = 'tableSortArrow';
                spanEl.appendChild(document.createTextNode('\u00A0\u00A0'));
                arrowParent.appendChild(spanEl);
            }
            else {
                arrowParent.style.fontStyle = "italic";
            }
        }

        // now, add back in some feedback 
        var spanEl = createElement('span');
        spanEl.className = 'tableSortArrow';
        if (tOrder == "ASC")
            spanEl.appendChild(document.createTextNode(' \u2191'));
        else
            spanEl.appendChild(document.createTextNode(' \u2193'));

        spanEl.setAttribute('sortOrder', tOrder);

        td.appendChild(spanEl);

        return false;
    },

    getInnerText: function(el) {

        if ('string' == typeof el || 'undefined' == typeof el) {
            return el;
        }

        if (el.innerText) {
            return el.innerText;  // Not needed but it is faster
        }

        var str = el.getAttribute('tblSortInnerText');
        if (null != str && '' != str) {
            return str;
        }
        str = '';

        var cs = el.childNodes;
        var l = cs.length;
        for (var i = 0; i < l; i++) {
            // 'if' is considerably quicker than a 'switch' statement, 
            // in Internet Explorer which translates up to a good time 
            // reduction since this is a very often called recursive function
            if (1 == cs[i].nodeType) { // ELEMENT NODE
                str += this.getInnerText(cs[i]);
                break;
            } else if (3 == cs[i].nodeType) { //TEXT_NODE
                str += cs[i].nodeValue;
                break;
            }
        }

        // set the innertext for this element directly on the element
        // so that it can be retrieved early next time the innertext
        // is requested
        el.setAttribute('tblSortInnerText', str);

        return str;
    },

    determineSortFunction: function(itm) {

        var sortfn = this.sortCaseInsensitive2;

        if (itm == null)
            return false;

        if (itm.match(/^\d{1,5}-.-\d{3}$/)) {
            sortfn = this.sortCode;
        }

        if (itm.match(/^\d\d[\/-]\d\d[\/-]\d\d\d\d$/) || itm.match(/^\d\d[\/-]\d\d[\/-]\d\d$/)) {
            sortfn = this.sortDate;
        }
        if (itm.match(/^[£$]/)) {
            sortfn = this.sortCurrency;
        }
        if (itm.match(/^\d?\.?\d+$/) || itm.match(/^\d*[-]\d\d\d$/) || itm.match(/^\d\d\d\d$/)) {
            sortfn = this.sortNumeric;
        }
        if (itm.match(/^[+-]?\d*\.?\d+([eE]-?\d+)?$/)) {
            sortfn = this.sortNumeric;
        }
        if (itm.match(/^([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])\.([01]?\d\d?|2[0-4]\d|25[0-5])$/)) {
            sortfn = this.sortIP;
        }

        return sortfn;
    },

    sortCaseInsensitive: function(a, b) {
        var that = tblSort.that;

        if ((a.cells[that.sortColumnIndex] != undefined) && (b.cells[that.sortColumnIndex] != undefined)) {
            var aa = that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase();
            var bb = that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase();
        } else { return 0; }
        if (aa == bb) {
            return 0;
        } else if (aa < bb) {
            return -1;
        } else {
            return 1;
        }
    },

    sortCaseInsensitive2: function(a, b) {
        var that = tblSort.that;

        if ((a.cells[that.sortColumnIndex] != undefined) && (b.cells[that.sortColumnIndex] != undefined)) {
            var aa = that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase();
            var bb = that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase();

            aa = aa.replace(SortArray._GetTranslateRE(), function(match) { return SortArray._GetSortArray()[match]; });
            bb = bb.replace(SortArray._GetTranslateRE(), function(match) { return SortArray._GetSortArray()[match]; });
        } else { return 0; }
        if (aa == bb) {
            return 0;
        } else if (aa < bb) {
            return -1;
        } else {
            return 1;
        }
    },

    sortCode: function(a, b) {
        var that = tblSort.that;

        if ((a.cells[that.sortColumnIndex] != undefined) && (b.cells[that.sortColumnIndex] != undefined)) {
            var aa = that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase();
            var bb = that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase();

            var aaStr = aa;
            var bbStr = bb;
            while (aaStr.length < bb.length) {
                aaStr = "0" + aaStr;
            }
            while (bbStr.length < aa.length) {
                bbStr = "0" + bbStr;
            }
        } else { return 0; }
        if (aa == bb) {
            return 0;
        } else if (aaStr < bbStr) {
            return -1;
        } else {
            return 1;
        }
    },

    sortRawjQuery: function(a, b) {
        var that = tblSort.that;
        var trattrId = jQuery.expando;

        if ((a.cells[that.sortColumnIndex] != undefined) && (b.cells[that.sortColumnIndex] != undefined)) {
            var aa = a[trattrId];
            var bb = b[trattrId];
        } else { return 0; }

        if (aa == bb) {
            return 0;
        } else if (aa < bb) {
            return -1;
        } else {
            return 1;
        }
    },

    sortDate: function(a, b) {
        var that = tblSort.that;

        // y2k notes: two digit years less than 50 are treated as 20XX, greater than 50 are treated as 19XX
        var aa = that.getInnerText(a.cells[that.sortColumnIndex]);
        var bb = that.getInnerText(b.cells[that.sortColumnIndex]);

        var dt1, dt2, yr = -1;

        if (aa.length == 10) {
            dt1 = aa.substr(6, 4) + aa.substr(3, 2) + aa.substr(0, 2);
        } else {
            yr = aa.substr(6, 2);
            if (parseInt(yr) < 50) {
                yr = '20' + yr;
            } else {
                yr = '19' + yr;
            }
            dt1 = yr + aa.substr(3, 2) + aa.substr(0, 2);
        }

        if (bb.length == 10) {
            dt2 = bb.substr(6, 4) + bb.substr(3, 2) + bb.substr(0, 2);
        } else {
            yr = bb.substr(6, 2);
            if (parseInt(yr) < 50) {
                yr = '20' + yr;
            } else {
                yr = '19' + yr;
            }
            dt2 = yr + bb.substr(3, 2) + bb.substr(0, 2);
        }

        if (dt1 == dt2) {
            return 0;
        } else if (dt1 < dt2) {
            return -1;
        }
        return 1;
    },

    sortCurrency: function(a, b) {
        var that = tblSort.that;

        var aa = that.getInnerText(a.cells[that.sortColumnIndex]).replace(/[^0-9.]/g, '');
        var bb = that.getInnerText(b.cells[that.sortColumnIndex]).replace(/[^0-9.]/g, '');
        return parseFloat(aa) - parseFloat(bb);
    },

    sortNumeric: function(a, b) {
        var that = tblSort.that;

        var aa = parseFloat(that.getInnerText(a.cells[that.sortColumnIndex]));
        if (isNaN(aa)) {
            aa = 0;
        }
        var bb = parseFloat(that.getInnerText(b.cells[that.sortColumnIndex]));
        if (isNaN(bb)) {
            bb = 0;
        }
        return aa - bb;
    },

    makeStandardIPAddress: function(val) {
        var vals = val.split('.');

        for (x in vals) {
            val = vals[x];

            while (3 > val.length) {
                val = '0' + val;
            }
            vals[x] = val;
        }

        val = vals.join('.');

        return val;
    },

    sortIP: function(a, b) {
        var that = tblSort.that;

        var aa = that.makeStandardIPAddress(that.getInnerText(a.cells[that.sortColumnIndex]).toLowerCase());
        var bb = that.makeStandardIPAddress(that.getInnerText(b.cells[that.sortColumnIndex]).toLowerCase());
        if (aa == bb) {
            return 0;
        } else if (aa < bb) {
            return -1;
        } else {
            return 1;
        }
    },

    moveRows: function(table, newRows) {
        this.isOdd = false;

        // We appendChild rows that already exist to the tbody, so it moves them rather than creating new ones
        for (var i = 0; i < newRows.length; i++) {
            var rowItem = newRows[i];

            this.isJoinedRow = (rowItem.className.indexOf("joinedrow") > -1) ? true : false;          // összetartozó sorok csatolt sora
            this.isParentRow = (rowItem.className.indexOf("parentrow") > -1) ? true : false;        // összetartozó sorok első sora
            if (!this.isParentRow)
                this.isLastJoined = this.isJoinedRow;
            this.doStripe(rowItem);

            table.tBodies[0].appendChild(rowItem);
        }
    },

    doStripe: function(rowItem) {
        // összetartozó sorok "joinedrow" sorai a "parentrow" sorokkal azonosan formázottak
        if (this.isParentRow && this.isLastJoined)
            this.isOdd = !this.isOdd;            //váltás a következő sorcsoportnál
        if (this.isOdd) {
            css.addClassToElement(rowItem, 'odd');
        } else {
            css.removeClassFromElement(rowItem, 'odd');
        }

        if (!this.isParentRow && !this.isJoinedRow)
            this.isOdd = !this.isOdd;
    }

}

function tblSortInit() {
	tblSort.init();	
}
//addEvent(window, 'load', tblSortInit)

function sortBinary(needle, haystack, case_insensitive, column, sorttype) {
    if (typeof (haystack) === 'undefined' || !haystack.length) return -1;

    var high = haystack.length - 1;
    var low = 0;
    case_insensitive = (typeof (case_insensitive) === 'undefined' || case_insensitive) ? true : false;

    var lTdText = "", needletext = "";
    var needleclass = needle.children[column].className;
    var ehsort = needleclass.indexOf('EH_elol') > -1 || needleclass.indexOf('EH_hatul') > -1;
    if (needle.children[column].innerHTML == "&nbsp;") {
        if (needleclass.indexOf('EvTolField') > -1) {
            needletext = needle.children[parseInt(column) + 2].innerText;
        }
        else if (needleclass.indexOf('EvIgField') > -1) {
            needletext = needle.children[parseInt(column) + 1].innerText;
        }
    }
    else {
        needletext = needle.children[column].innerText;
        var lPrintDisabledDivs = jQuery(needle.children[column]).children(".printDisable");
        if (0 in lPrintDisabledDivs) {
            while (needletext.indexOf(lPrintDisabledDivs[0].innerText) > -1) {
                needletext = needletext.replace(lPrintDisabledDivs[0].innerText, "");
            }
            while (needletext.indexOf(String.fromCharCode(10)) > -1 || needletext.indexOf(String.fromCharCode(13)) > -1) {
                needletext = needletext.replace(String.fromCharCode(10), "");
                needletext = needletext.replace(String.fromCharCode(13), "");
            }
        }
    }
    needle = (case_insensitive) ? needletext.toLowerCase() : needletext;
    if (sorttype == "sortCaseInsensitive2") {
        needle = needle.replace(SortArray._GetTranslateRE(), function(match) { return SortArray._GetSortArray()[match]; });
    }

    var smaller = false;
    try {
        while (low <= high) {
            mid = parseInt((low + high) / 2)

            lTdText = haystack[mid].children[column].innerText;
            var haystackmidclass = haystack[mid].children[column].className;
            ehsort = ehsort || haystackmidclass.indexOf('EH_elol') > -1 || haystackmidclass.indexOf('EH_hatul') > -1;
            if (ehsort) {
                needle = 0;
                element = 0;
                if (needleclass.indexOf('EH_elol') > -1) {
                    needle = -parseInt(needleclass.substr(needleclass.indexOf('EH_elol') + 7, 3));
                }
                if (needleclass.indexOf('EH_hatul') > -1) {
                    needle = parseInt(needleclass.substr(needleclass.indexOf('EH_hatul') + 8, 3));
                }
                if (haystackmidclass.indexOf('EH_elol') > -1) {
                    element = -parseInt(haystackmidclass.substr(haystackmidclass.indexOf('EH_elol') + 7, 3));
                }
                if (haystackmidclass.indexOf('EH_hatul') > -1) {
                    element = parseInt(haystackmidclass.substr(haystackmidclass.indexOf('EH_hatul') + 8, 3));
                }
            }
            else if (haystack[mid].children[column].innerHTML == "") {
                if (haystackmidclass.indexOf('EvTolField') > -1) {
                    lTdText = haystack[mid].children[parseInt(column) + 2].innerText;
                }
                else if (haystackmidclass.indexOf('EvIgField') > -1) {
                    lTdText = haystack[mid].children[parseInt(column) + 1].innerText;
                }
                element = (case_insensitive) ? lTdText.toLowerCase() : lTdText;
                element = element.replace(SortArray._GetTranslateRE(), function(match) { return SortArray._GetSortArray()[match]; });
            }
            else {
                var lPrintDisabledDivs = jQuery(haystack[mid].children[column]).children(".printDisable");
                if (0 in lPrintDisabledDivs) {
                    while (lTdText.indexOf(lPrintDisabledDivs[0].innerText) > -1) {
                        lTdText = lTdText.replace(lPrintDisabledDivs[0].innerText, "");
                    }
                    while (lTdText.indexOf(String.fromCharCode(10)) > -1 || lTdText.indexOf(String.fromCharCode(13)) > -1) {
                        lTdText = lTdText.replace(String.fromCharCode(10), "");
                        lTdText = lTdText.replace(String.fromCharCode(13), "");
                    }
                }
                element = (case_insensitive) ? lTdText.toLowerCase() : lTdText;
                element = element.replace(SortArray._GetTranslateRE(), function(match) { return SortArray._GetSortArray()[match]; });
            }

            if (sorttype == "sortCaseInsensitive2") {
            }
            else if (sorttype == "sortNumeric") {
                element = parseFloat(lTdText);
                needle = parseFloat(needletext);
            }
            else if (sorttype == "sortCode") {
                var elementStr = lTdText;
                var needleStr = needletext;
                while (elementStr.length < needletext.length) {
                    elementStr = "0" + elementStr;
                }
                while (needleStr.length < lTdText.length) {
                    needleStr = "0" + needleStr;
                }
                element = elementStr;
                needle = needleStr;
            }

            if (element > needle) {
                high = mid - 1;
                smaller = true;
            } else if (element < needle) {
                low = mid + 1;
                smaller = false;
            } else {
                return mid;
            }
        }
    }
    catch (ex) {
        var v = "";
    }
    return mid + (smaller ? 0 : 1);


    //return -1;
}
