/*******************************************************************************
 * Script to handle filtering of tables.
 * This script relies on two elements:
 *  - a select input. This one must have the class 'filter'. It's 'rel'
 *    attribute must define two elements: the value used for the 'All values'
 *    options and the key used to recognize the objects to filter.
 *    For example, the department filter rel is "all_value[all_dep] key[dep]".
 *    It means that when the option having the value 'all_dep' is selected, we
 *    do not filter on departments anymore. It also means that the class used
 *    to filter on  department will all start with 'dep_'.
 *
 *  - The second element is the table to filter. This one must have the
 *    'filtered' class. Each item to filter (tr basically) must have class
 *    related to a filter (for example 'dep_somevalue' to be filtered on
 *    departments) and the class 'filtered_item'.
 *    You can also define objects that will only be displayed with a specific
 *    filter , using the 'rel' attribute. If you specify rel="filter_on[filter]"
 *    where filter is the key of you filter, other filters will not be applied on
 *    this item.
 *    In the rel attribute, you can also specify 'hide_on_all[filter]' so an
 *    item do not appear when selecting the 'All ...' value of the filter.
 *
 * It's also possible to use this filter system on something else than tables,
 * as long as you use 'filtered' and 'filtered_item' classes.
 *******************************************************************************/

(function($) {

    /* Options - can be set using the 'options' argument of $.tablefilter.*/
    var debug_mode = false;
    var filter_class = '.filter';
    var container_class = '.filtered';
    var item_class = '.filtered_item';
    var cookie_prefix = 'filter_';

    var filters = [];

    debug = function(msg) {
	if (debug_mode) {
	    console.log(msg);
	}
    }


    filter_treat_options = function(options) {
	if (typeof(options) == 'undefined') {
	    return;
	}

	keys = ['debug_mode',
		'filter_class',
		'container_class',
		'item_class',
		'cookie_prefix']

	for (i = 0; i < keys.length; i++) {
	    key = keys[i];
	    if (typeof(options[key]) != 'undefined') {
		eval(key + ' =  options[\'' + key + '\']');
	    }
	}
    }

    /* This functions gets the list of filters defined in the page and
       updates
    */
    get_filters = function() {
	f = $('select' + filter_class);
	debug('Found ' + f.length + ' filters');

	/* Simple regezp to find values stored in the rel attribute.*/
	reg = new RegExp(".*all_value\\\[(.*)\\\] key\\\[(.*)\\\].*");
	f.each(function() {
		values = reg.exec($(this).attr('rel'));
		if (values.length == 3) {	
		    filters[filters.length] = {id: this.id,
					       all_value: values[1],
					       key: values[2]}
		    debug('Added filter ' + this.id);
		    debug(filters[filters.length -1]);
		}		
	    });	
    }

    /* This function sets a cookie for each filter to store the last
     saved value.*/
    set_cookies = function() {
	for (i=0; i < filters.length; i++) {
	    filter = filters[i];
	    cookie_name = cookie_prefix + filter.id;
	    cookie_value = $('#' + filter.id).val();
	    $.cookie(cookie_name, cookie_value);
	    debug('Cookie set: ' + cookie_name + ':' + cookie_value);
	}

	apply_filters();
    }

    /* This function reads cookies for each filter and updates the value
     for each filter and reapplys filtering. */
    read_cookies = function() {
	for (i=0; i < filters.length; i++) {
	    filter = filters[i];
	    cookie_name = cookie_prefix + filter.id;
	    cookie_value = $.cookie(cookie_name);
	    debug('Cookie read: ' + cookie_name + ':' + cookie_value);

	    if (cookie_value != null) {
		if (jq('#' + filter.id).find('[value=' + cookie_value + ']').length == 1) {
		    jq('#' + filter.id).val(cookie_value);
		}
	    }
	}

	apply_filters();
    }

    /* This function applies filters on the table.
     */
    apply_filters = function() {
	$(container_class + ' ' + item_class).hide();
	/* We build the list of classes that will be used to filter. */
	classes = [];
	for (i=0; i < filters.length; i++) {
	    filter = filters[i];
	    value = $('#' + filter.id).val();

	    /* If the 'All ...' value is selected, we do not add
	       it to the list. */
	    if (value != filter.all_value) {
		classes[classes.length] = filter.key + '_' + value;
	    }
	}

	selector = ''
	for (i = 0; i < classes.length; i ++) {
	    selector += '.' + classes[i];
	}
	debug(selector);

	if (selector.length > 0) {
	    debug('Filtering items');
	    $(container_class + ' ' + item_class + selector).show()
	}
	else {
	    debug('Showing all items');
	    $(container_class + ' ' + item_class).show();
	}

	/* We reapply the filters for the special keywords. */
	for (i=0; i < filters.length; i++) {
	    filter = filters[i];
	    value = $('#' + filter.id).val();

	    /* We show again element that should only be affected by this filter*/
	    $(item_class + '[rel*=filter_on]').each(function(){
		    reg = new RegExp(".*(filter_on\\\[(\\\w* +)*" + filter.key + "( +\\\w*)*\\\]).*");
		    if (reg.exec($(this).attr('rel')) != null) {
			debug('Match');
			if ($(this).hasClass(filter.key + '_' + value)) {
			    $(this).show()
				}
		    }
		});

	    /* We hide the ones that should not appear on the 'Show all' for this filter */
	    if (value == filter.all_value) {
		$(item_class + '[rel*=hide_on_all]').each(function(){
			reg = new RegExp(".*(hide_on_all\\\[(\\\w* +)*" + filter.key + "( +\\\w*)*\\\]).*");
			if (reg.exec($(this).attr('rel')) != null) {
			    $(this).hide();
			}
		    });
	    }
	}

    }    

    /* Registers the $.tablefilter function.
     */
    $.tablefilter = function(options) {
	filter_treat_options(options);

	get_filters();
	read_cookies();

	$('select' + filter_class).change(set_cookies);
    }
}
    )(jQuery);


