﻿(function ($) {

  function TinyGrid(grid, opts) {
    // private variables
    var self = this, fire = grid.add(self);

    // handle filter text changes
    grid.find('thead>tr.filter input[type=text]').bind('textchange', function () { self.load(1); });

    // API methods  
    $.extend(self, {

      init: function () {
        // set the sort links to auto reload grid
        grid.find('thead>tr a').click(function (e) {
          e.preventDefault();
          self.load(null, $(this).attr("data-orderColumn"), $(this).attr("data-orderDescending"));
        });

        // set the paging links to auto reload grid
        grid.find('.pagination a').click(function (e) {
          e.preventDefault();
          if ($(this).parent().hasClass('disabled')) return;
          $.get($(this).attr('href'), function (data) { self.refresh(data) });
        });
      },

      load: function (page, orderCol, orderDesc) {
        // set data
        var data = "page=" + (page == undefined ? grid.attr('data-page') : page);
        data += "&orderColumn=" + (orderCol == undefined ? grid.attr('data-orderColumn') : orderCol);
        data += "&orderDescending=" + (orderDesc == undefined ? grid.attr('data-orderDescending') : orderDesc);
        data += "&" + grid.find(':input').serialize();

        $.ajax(grid.attr('data-action') || grid.attr('action'), { data: data, success: function (data, status) {
						self.refresh(data);
					}
        });
      },

      refresh: function (data) {
        var $d = $(data);

        // update everything except for filter rows with real-time text filters
        // make sure parent table ids match before replacing
        var skip = 0;
        grid.find('thead tr').each(function (i) {
          if ($(this).find('input[type=text]').length > 0) { skip++; }
          else $(this).replaceWith($d.find('thead tr').eq(skip));
        });
        grid.find('tbody').each(function (i) { $(this).replaceWith($d.find('tbody').eq(0)); })

        // should only be one pager
        grid.find('.pagination').replaceWith($d.find('.pagination'));

        // rewire (can't use live() because of IE7 bug)
        self.init();

        var e = $.Event();
        e.type = "onLoad";
        fire.trigger(e);
        return self;
      }
    });

    // callbacks TODO: understand what this code is doing
    $.each("onLoad".split(","), function (i, name) {

      // configuration
      if ($.isFunction(opts[name])) {
        $(self).bind(name, opts[name]);
      }

      // API
      self[name] = function (fn) {
        if (fn) { $(self).bind(name, fn); }
        return self;
      };
    });

  }

  // jQuery plugin initialization
  $.fn.tinygrid = function (opts) {

    // already constructed --> return object
    var el = this.data("tinygrid");
    if (el) { return el; }

    opts = $.extend(true, {}, $.fn.tinygrid.defaults, opts);

    this.each(function () {
      el = new TinyGrid($(this), opts);
      el.init();
      $(this).data("tinygrid", el);
    });

    return opts.api ? el : this;
  };

  $.fn.tinygrid.defaults = {
    onLoad: null,
    api: false
  }

  $.event.special.textchange = {

    setup: function (data, namespaces) {
      $(this).data('lastValue', this.contentEditable === 'true' ? $(this).html() : $(this).val());
      $(this).bind('keyup.textchange', $.event.special.textchange.handler);
      $(this).bind('cut.textchange paste.textchange input.textchange', $.event.special.textchange.delayedHandler);
    },

    teardown: function (namespaces) {
      $(this).unbind('.textchange');
    },

    handler: function (event) {
      $.event.special.textchange.triggerIfChanged($(this));
    },

    delayedHandler: function (event) {
      var element = $(this);
      setTimeout(function () {
        $.event.special.textchange.triggerIfChanged(element);
      }, 25);
    },

    triggerIfChanged: function (element) {
      var current = element[0].contentEditable === 'true' ? element.html() : element.val();
      if (current !== element.data('lastValue')) {
        element.trigger('textchange', element.data('lastValue'));
        element.data('lastValue', current);
      }
    }
  };

})(jQuery);
