(function($){
  
  $.fn.filtering = function(options) {
    
    var opts = $.extend({}, $.fn.filtering.defaults, options);
    
    opts.inputs = features_of($(opts.sortControls).find('input:checkbox'));
    var sortables = $(opts.sortables);
    var selection = indexes_of_selected(opts.inputs);
    $.each(opts.inputs, create_input_handler);
    $(opts.showall).click(function() {
      selection = [];
      update();
    });
    
    /* list management code */
    function string_to_list(rel) {
      return $.map(rel.split(/,\s/), function(str){return Number(str)})
    }
    function item_has_feature(item, feature) {
      var list = string_to_list($(item).attr('data-features'));
      return $.inArray(feature, list) == -1 ? false : true;
    }
    function show_items_with_features(sortables, features) {
      $(sortables).hide();
      $.each(sortables, function(i, item) {
        $.each(features, function(j, feature) {
          if (item_has_feature(item, feature, sortables)) {
            $(item).show();
          }
        });
      });
    }

    /* listener for when checkboxes change */
    /* k = value of checkbox */
    /* v = feature id */
    function create_input_handler(k, v) {
      $(opts.sortControls).find('input:checkbox[name='+k+']').click(function() {
        if ($(this).attr('checked')) {
          selection.push(v);
        } else {
          selection.splice($.inArray(selection, v), 1);
        }
        update();
      });
    }

    /* return an array containing the input "key" (feature # id) for each selected checkbox */
    function indexes_of_selected(inputs) {
      var result = [];
      $.each(inputs, function(k, v) {
        if ($(opts.sortControls).find('input:checkbox[name='+k+']').attr('checked')) {
          result.push(v);
        }
      });
      return result;
    }

    /* update the view of sortables to reflect the values in the selection array */
    function update() {
      if (selection.length < 1) {

        $(opts.showall).attr('checked', 'true');
        $(opts.sortControls).find('input:checkbox').removeAttr('checked');

        var all = [];
        $.each(opts.inputs, function(k, v) { all.push(v) });
        show_items_with_features($(opts.sortables), all);

      } else {

        $(opts.showall).removeAttr('checked');
        show_items_with_features($(opts.sortables), selection);

      }
    }

    function features_of(collection) {
      var o = {};
      $.each(collection, function(index, el) {
        o[$(el).attr('name')] = Number($(el).attr('value'));
      });
      return o;
    }
    
  }
  
  
  $.fn.filtering.defaults = {
    inputs: {},
    sortControls: '.product-filtering',
    sortables: '#ProductList li',
    showall: '#showall'
  }
  
})(jQuery);