(function($) {
$.fn.log = function(msg) {
   window.console && window.console.log && window.console.log('%s%s%o', msg||'', msg?': ':'', this);
   return this;
};
})(jQuery);

/**
 * .tablefilter - Table Filter Plugin
 *
 * Version: 0.5
 * Updated: 2007-11-17
 *
 * Copyright (c) 2007 James Dempster (letssurf@gmail.com, http://www.jdempster.com/category/jquery/tablefilter/)
 *
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 **/

/**
 * Requirements:
 * - jQuery (John Resig, http://www.jquery.com/)
 **/
(function($) {

$.extend({
    tablefilter: new function() {
        var self = this,
            filters = {},
            widgets = {}
        ;

        this.ui = {};

        this.addWidget = function(widget) {
            widgets[widget.id] = widget;
        };

        this.applyWidgets = function(event) {
            var myWidgets = event.data.settings.widgets;
            var widgetsLen = myWidgets.length;
            for(var i = 0; i < widgetsLen; i++) {
                widgets[myWidgets[i]].exec(event);
            }
        };

        this.addFilter = function(filter) {
            filters[filter.id.toString().toLowerCase()] = filter;
        };

        this.getFilter = function(id, filterText, event) {
            if (typeof filters[id.toString().toLowerCase()].filter == 'function') {
                return filters[id.toString().toLowerCase()].filter(filterText, event);
            } else {
                return false;
            }
        };

        this.detectFilter = function(filterText, event) {
            for (var i in filters) {
                if (filters[i].is(filterText, event) == true) {
                    return filters[i];
                }
            }
            return filters[event.data.settings.defaultFilter];
        };

        function log(s) {
            console.log(s);
        }

        function prepareSearchString(searchString) {
            var placeHolder = '__PLACE_HOLDER__';
            var aQuoted = [];
            var fnPlaceHolder = function (sPlaceHolder, aPlaceValues) {
                return function(str, p1, p2, offset, s) {
                    aQuoted.push(p1);
                    return sPlaceHolder;
                };
            };
            prepearedSearch = searchString
                .replace(/"(.*?)"/g, fnPlaceHolder(placeHolder, aQuoted))
                .replace(/\s*([<>=]+)\s+([0-9]+)/, '$1$2')
                .replace(/\bAND\b/gi, '')
                .replace(/\s+/g, ' ')
                .replace(/\s$/g, '')
                .replace(/^\s/g, '')
                .replace(/\s/g, ' AND ')
                .replace(/\sAND\sOR\sAND\s/gi, ' OR ')
                .split(' AND ')
            ;
            return {
                searchString:searchString,
                prepearedSearch:prepearedSearch,
                placeHolder:placeHolder,
                quotedText:aQuoted
            };
        }

        function buildFilterList(event, filterText) {
            var prepearedSearch = prepareSearchString(filterText);
            var queryCount = prepearedSearch.prepearedSearch.length;
            var filters = [];
            for(var i = 0; i < queryCount; i++) {
                var n = prepearedSearch.prepearedSearch[i];
                var filterList = [];
                var queryList = n.split(' OR ');
                for (var iQueryList in queryList) {
                    if (queryList[iQueryList] == prepearedSearch.placeHolder) {
                        var searchText = prepearedSearch.quotedText.shift();
                        var filter = $.tablefilter.getFilter(event.data.settings.quotedFilter, searchText, event);
                    } else {
                        if (queryList[iQueryList].indexOf(prepearedSearch.placeHolder) >= 0) {
                            var quotedText = prepearedSearch.quotedText.shift();
                            var searchText = queryList[iQueryList].replace(prepearedSearch.placeHolder, quotedText);
                        } else {
                            var searchText = queryList[iQueryList];
                        }
                        var filterId = $.tablefilter.detectFilter(searchText, event).id;
                        var filter = $.tablefilter.getFilter(filterId, searchText, event);
                    }
                    filterList.push(filter);
                }
                filters.push(filterList);
            }
            return filters;
        }

        function getRowFilter(event, filterText) {
            var filterList = buildFilterList(event, filterText);
            return function(rowText) {
                var filterCount = filterList.length;
                for(var iFilter = 0; iFilter < filterCount; iFilter++) {
                    var filterOr = filterList[iFilter];
                    if (!filterOr instanceof Array) {
                        filterOr = [filterOr];
                    }
                    var filterOrCount = filterOr.length;
                    var pass = false;
                    for(var iFilterOr = 0; iFilterOr < filterOrCount; iFilterOr++) {
                        var filter = filterOr[iFilterOr];
                        if (typeof filter == 'function' && filter(rowText)) {
                            pass = true;
                            break;
                        }
                    }
                    if (pass == false) {
                        return false;
                    }
                }
                return true;
            }
        }

        function filterCheck(event, filterText, callback) {
            if (this.filterText == filterText) return;
            filter.call(this, event, filterText, callback);
        }

        function filter(event, filterText, callback) {
            var startTime = new Date(),
                $this = $(this),
                settings = event.data.settings,
                isTable = $this.is('table'),
                table = event.data.table,
                columni = parseInt(this.column, 10),
                filtered = false
            ;
            this.filterText = filterText;
            if (isTable === true) {
                $('>thead th', this).removeClass(settings.filteredClass);
                $('>thead th', this).each(function() {
                    if(typeof this.filterText != 'undefined') this.filterText = null;
                });
            } else {
                if(typeof table.filterText != 'undefined') table.filterText = null;
            }
            if (filterText == '' || filterText == '*') {
                var rowFilter = function() { return true; }
            } else {
                var rowFilter = getRowFilter(event, filterText);
            }
            $('>tbody>tr', table).each(function() {
                if (isTable === true || typeof this.filterRow != 'object') {
                    this.filterRow = { count: 0 };
                }
                if (isTable) {
                    var rowText = $(this).text();
                    if (rowFilter(rowText)) {
                        $(this).show();
                    } else {
                        $(this).hide();
                    }
                } else {
                    var columnText = $(this.cells[columni]).text();
                    if (rowFilter(columnText)) {
                        if (typeof this.filterRow['column_'+columni] != 'undefined') {
                            delete(this.filterRow['column_'+columni]);
                            this.filterRow.count--;
                        }
                    } else {
                        filtered = true;
                        if (typeof this.filterRow['column_'+columni] == 'undefined') {
                            this.filterRow['column_'+columni] = true;
                            this.filterRow.count++;
                        }
                    }
                    if (this.filterRow.count > 0) {
                        $(this).hide();
                    } else {
                        $(this).show();
                    }
                }
            });
            if (filtered == true) {
                $this.addClass(settings.filteredClass);
            } else {
                $this.removeClass(settings.filteredClass);
            }
            //console.log( 'filter took ' + (new Date().getTime() - startTime.getTime()) + 'ms' );
            self.applyWidgets(event);
            if (typeof settings.callback == 'function') {
                settings.callback.call(this, event);
            }
            if (typeof callback == 'function') {
                callback.call(this, event);
            }
        }

        function refreshFilters(event) {
            if (typeof this.filterText != 'undefined') {
                filter.call(this, event, this.filterText);
            } else {
                $('>thead tr:first th', this).each(function() {
                    if (typeof this.filterText != 'undefined') {
                        event.target = this;
                        filter.call(this, event, this.filterText);
                    }
                });
            }
        }

        this.construct = function(options) {
            var settings = $.extend(self.defaults, options);
            return this.each(function() {
                var $this = $(this);
                if (this.filterEnabled === true || $this.is('table') === false) {
                    return;
                }
                $this.bind('filter.tablefilter', {table:this, settings:settings}, filterCheck);
                $this.bind('filter-refresh.tablefilter', {table:this, settings:settings}, refreshFilters);
                for(var rowi = 0; rowi < this.tHead.rows.length; rowi++) {
                    var tableHeadersRow = this.tHead.rows[rowi];
                    for(var celli = 0; celli < tableHeadersRow.cells.length; celli++) {
                        tableHeadersRow.cells[celli].column = celli;
                        $(tableHeadersRow.cells[celli]).bind('filter.tablefilter', {table:this, settings:settings}, filterCheck);
                    }
                }
                this.filterEnabled = true;
                self.applyWidgets({startup:true, data:{table:this, settings:settings}});
                settings.ui($this, settings);
            });
        };

    }
});

$.fn.extend({
    tablefilter: $.tablefilter.construct
});

$.tablefilter.addFilter({
    id: 'texti',
    is: function(filterText) {
        return false;
    },
    filter: function(filterText) {
        filterText = filterText.toLowerCase();
        return function(text) {
           return text.toLowerCase().indexOf(filterText) >= 0;
        };
    }
});

$.tablefilter.addFilter({
    id: 'text',
    is: function(filterText) {
       return false;
    },
    filter: function(filterText) {
        return function(text) {
            return text.indexOf(filterText) >= 0;
        };
    }
});

$.tablefilter.addFilter({
    id: 'regex',
    is: function(filterText) {
        return /^\/.*\/$/.test(filterText);
    },
    filter: function(filterText) {
        filterText = filterText.replace(/^\//, '').replace(/\/$/, '');
        var regex = new RegExp(filterText);
        return function(text) {
            return regex.test(text);
        };
    }
});

$.tablefilter.addFilter({
    id: 'numeric',
    is: function(filterText) {
        return /^[<>]?=?[0-9]+$/.test(filterText);
    },
    filter: function(filterText) {
        var condition = filterText.toString().match(/^([<>]?=?)([+-]?)([\d.]+)(.*)$/);
        if (condition === null || condition.length < 1 || condition[1] === '' || condition[1] === '=') {
            condition[1] = '==';
        }
        return function(number) {
            return eval('(' + parseFloat(number) + condition[1] + condition[2] + condition[3] + ')');
        };
    }
});

$.tablefilter.addFilter({
    id: 'date-iso',
    is: function(filterText) {
        return /^[<>]?=?\d{4}[-\/]\d{1,2}[-\/]\d{1,2}$/.test(filterText);
    },
    filter: function(filterText) {
        var condition = filterText.toString().match(/^([<>]?=?)(\d{4}[-\/]\d{1,2}[-\/]\d{1,2})$/);
        if (condition === null || condition.length < 1 || condition[1] === '' || condition[1] === '=') {
            condition[1] = '==';
        }
        var filterDate = new Date(condition[2].replace(/[-]/g, '/'));
        return function(text) {
            foundDate = text.match(/\d{4}[-\/]\d{1,2}[-\/]\d{1,2}/);
            if (foundDate !== null) {
                var checkDate = new Date(foundDate[0].replace(/[-]/g, '/'));
                return eval('(' + (checkDate - filterDate) + condition[1] + ' 0)');
            }
            return false;
        }
    }
});

$.tablefilter.addFilter({
    id: 'avg',
    is: function(filterText) {
        return /^[<>]?=?AVG$/.test(filterText);
    },
    filter: function(filterText, event) {
        var columni = event.target.column;
        var totalValue = 0, rowCount = 0;
        $('>tbody>tr', event.data.table).each(function() {
            var columnValue = $(this.cells[columni]).text();
            totalValue += parseInt(columnValue, 10);
            rowCount++;
        });
        var avgValue = Math.round(totalValue / rowCount);
        var condition = filterText.toString().match(/^([<>]?=?)AVG$/);
        if (condition === null || condition.length < 1 || condition[1] === '' || condition[1] === '=') {
            condition[1] = '==';
        }
        return function(number) {
            return eval('(' + parseFloat(number) + condition[1] + avgValue + ')');
        };
    }
});

$.tablefilter.addFilter({
    id: 'date:prefixed',
    is: function(filterText) {
        return /^date:/.test(filterText);
    },
    filter: function(filterText) {
        filterText = filterText.replace(/^date:/, '');
        var condition = filterText.toString().match(/^([<>]?=?)(.*)/);
        if (condition === null || condition.length < 1 || condition[1] === '' || condition[1] === '=') {
            condition[1] = '==';
        }
        var filterDate = Date.parse(condition[2]);
        return function(text) {
            var checkDate = Date.parse(text);
            if (checkDate !== null) {
                return eval('(' + (checkDate - filterDate) + condition[1] + ' 0)');
            }
            return false;
        }
    }
});

$.tablefilter.ui.basic = function(table, settings) {
    var $tablefilterField = $([
            '<div id="tablefilter-field">',
                '<fieldset>',
                    '<legend>Filter</legend>',
                    '<span id="tablefilter-clear">clear</span>',
                    '<span id="tablefilter-close">close</span>',
                    '<input id="tablefilter-input" type="text" />',
                '</fieldset>',
            '</div>'].join(''))
        .appendTo('body')
        .hide()
        .css({
            border:'1px solid black',
            background:'#D4D0C8',
            position:'absolute'
        })
        .click(function(e) {
            e.stopPropagation();
        })
    ;
    $('#tablefilter-clear').click(function() {
        $('#tablefilter-input').val('').trigger('keyup', [false]).focus();
    });
    $('#tablefilter-close').click(function() {
        hideFilterField();
    });

    var hideFilterField = function() {
        $tablefilterField.hide();
    };


    var $table = $(table);
    //$table.find('>thead>tr:first>th').wrapInner('<div class="tablefilter-column"></div>');
    $table.find('.tablefilter-column').click(function(e) {
        e.stopPropagation();
        $(document).one('click', function() {
            hideFilterField();
        });
        var $columnHeader = $(this);

        var showFilterField = function() {
            repositionFilterField();
            $tablefilterField.show();
        };
        var repositionFilterField = function() {
            var offset = $columnHeader.offset();
            $tablefilterField.css({
                    top:offset.top + $columnHeader.height(),
                    left:offset.left
                })
            ;
        };

        showFilterField();
        var filterDelay = null;
        $('#tablefilter-input')
            .val($columnHeader.parents('th:first').get(0).filterText || '')
            .unbind('keyup')
            .bind('keyup', function(e, delay) {
                if (e.which == 13) {
                    hideFilterField();
                    return true;
                }
                if ((e.which >= 37 && e.which <= 40) || e.which == 9) return true;
                var delay = (delay == null) ? true : delay;
                var filterText = $(this).val();
                var triggerFilter = function() {
                    $columnHeader.parents('th:first').trigger('filter', [filterText, repositionFilterField]);
                };
                clearTimeout(filterDelay);
                if (delay === true) {
                    filterDelay = setTimeout(triggerFilter, 500);
                } else {
                    triggerFilter();
                }
            })
            .focus()
        ;
    });
};

$.tablefilter.addWidget({
    id: 'cookie',
    exec : function(event) {
        var settings = event.data.settings;
        var $table = $(event.data.table);
        if (event.startup == true) {
            var saveString = $.cookie('tablefilter_'+$table.attr('id')) || '';
            if (saveString == '') return;
            var $tableColumns = $table.find('>thead>tr:first>th');
            $(saveString.split('&')).each(function(i, n) {
                var filterData = n.match(/th_(\d+)=(.*)/);
                $tableColumns.get(filterData[1]).filterText = unescape(filterData[2])   ;
            });
            $table.trigger('filter-refresh');
            return true;
        }
        if (typeof $table.get(0).filterText != 'undefined') {
            console.log('store table filter');
        } else {
            var aFilterText = [];
            $table.find('>thead>tr:first>th').each(function(i, n) {
                if (typeof n.filterText != 'undefined' && n.filterText != '') {
                    aFilterText.push('th_'+i+'='+escape(n.filterText));
                }
            });
        }
        saveString = aFilterText.join('&');
        $.cookie('tablefilter_'+$table.attr('id'), saveString);
    }
});

$.tablefilter.defaults = {
    ui:             $.tablefilter.ui.basic,
    debug:          false,
    callback:       function() {},
    defaultFilter:  'texti',
    quotedFilter:   'text',
    filteredClass:  'filtered',
    widgets:        []
};

})(jQuery);