(function($) {
    $.widget("qusion.table", {
        options: {
            data: [],
            selection: true,
            definition: null,
            showHeader: true,
            selectedClass: 'q-state-selected',
            checkedClass: 'q-state-checked',
            priority: 10
        },
        _create: function() {
            var self = this, options = self.options, element = this.element;

            // hash table for keys
            self.keyIndex = { };
            self.keyField = null;

            element
                .uniqueId()
                .addClass("q-table")
                .attr({
                    role: "table",
                    tabIndex: 0
                });

            var table = self.table = $('<table />')
                .addClass('priority-' + options.priority)
                .appendTo(element);

            var header = $('<thead />')
                .appendTo(table);

            var body = $('<tbody />')
                .appendTo(table);

            // generate header
            if (options.showHeader === true)
                self._generateHeader(header);

            self.items = options.data || [];

            this.refresh();


            //events
            self._on(element, {
                "click thead :checkbox": function(e) {
                    var target = $(e.target).closest(":checkbox");
                    self.toggleCheckAll(target.is(':checked'));
                },
                "click tbody :checkbox": function(e) {
                    e.stopPropagation();
                    var target = $(e.target).closest(":checkbox");
                    self._toggleCheck(e, target);
                },
                "click tbody tr": function(e) {
                    e.stopPropagation();
                    var target = $(e.target).closest("tr");
                    self.select(target.data('item'));
                },
                "click tbody .q-type-checkbox label": function(e) {
                    e.stopPropagation();
                },
                "click tbody input": function(e) {
                    e.stopPropagation();
                },
                "click tbody button": function(e) {
                    e.stopPropagation();
                }
            });
        },
        toggleCheckAll: function(checked) {
            var self = this, element = self.element, options = self.options;
            var body = element.find('tbody');

            body.find(':checkbox')
                .attr('checked', checked)
                .parents('tr')
                .addClass(options.checkedClass);

            body.find('input:not(:checked)')
                .parents('tr').removeClass(options.checkedClass);
        },
        _toggleCheck: function(e, checkbox) {
            var self = this, element = self.element, options = self.options;
            var body = element.find('tbody');
            var head = element.find('thead');

            body.find('input:checked')
                .parents('tr')
                .addClass(options.checkedClass);

            var unchecked = body.find('input:not(:checked)');
            unchecked.parents('tr').removeClass(options.checkedClass);

            head.find(':checkbox').attr('checked', (unchecked.length == 0));

            var tr = checkbox.parents('tr');
            if (tr)
                self._trigger("check", null, { item: tr.data('item'), element: tr });
        },
        _generateHeader: function(container) {
            var self = this, options = self.options;
            // no need to generate anything if definition is not set
            if (!options.definition) return;

            var tr = $('<tr />').appendTo(container);
            for (var i = 0; i < options.definition.length; i++) {
                var def = options.definition[i];
                var th = $('<th />').appendTo(tr);

                // title
                if (def.title !== false)
                    th.html(def.title);

                // type
                if (def.type)
                    th.addClass("q-type-" + def.type);


                // checkbox
                if (def.type == 'checkbox') {
                    var cb = $('<label><input type="checkbox" /></label>');
                    th.append(cb).find(':checkbox');
                }

                // priority
                if (def.priority && !isNaN(def.priority))
                    th.addClass('priority-' + def.priority);
            }
        },
        _generateBodyRows: function(container) {
            var self = this, options = self.options, element = self.element;

            container.empty();

            // no need to generate anything if definition is not set
            if (!options.definition) return;

            for (var i = 0; i < self.items.length; i++) {
                var item = self.items[i];
                var tr = $('<tr />')
                    .data('item', item)
                    .appendTo(container);

                // key
                self.keyIndex[item[options.key]] = tr;

                for (var j = 0; j < options.definition.length; j++) {
                    var def = options.definition[j];
                    var td = $('<td />')
                        .appendTo(tr);

                    // generate basic cell html
                    if (def.template)
                        td.append(def.template(item, def, td));
                    else if (def.format)
                        td.append(self._format(item, def));
                    else if (def.field) {
                        var defItem = self._field(def.field, item);
                        if (jQuery.isFunction(defItem))
                            td.append(defItem());
                        else
                            td.append(defItem);
                    }

                    // checkbox
                    if (def.type == 'checkbox') {
                        var cb = $('<label><input type="checkbox" /></label>');
                        td.append(cb);
                    }

                    // type
                    if (def.type)
                        td.addClass("q-type-" + def.type);

                    // priority
                    if (def.priority && !isNaN(def.priority))
                        td.addClass('priority-' + def.priority);
                }
            }
        },
        _format: function(item, def) {
            if (def.type == 'date') {
                if ($.format && $.format.date)
                    return $.format.date(new Date(item[def.field]), def.format);
            }
            return item[def.field];
        },
        _field: function(name, item) {
            //"Radnik.FullName"
            if (name.indexOf('.') == -1) return item[name];
            var newItem = item;
            var arr = name.split('.');
            for (var i = 0; i < arr.length; i++) {
                if (newItem != null)
                    newItem = newItem[arr[i]];
            }
            return newItem;
        },
        _toggle: function(item, selected) {
            var self = this, element = self.element, options = self.options;
            var key = (item === Object(item)) ? item[options.key] : item;
            var tr = self.keyIndex[key];

            element.find('.' + options.selectedClass)
                .removeClass(options.selectedClass);

            if (tr) {

                selected ? tr.addClass(options.selectedClass) : tr.removeClass(options.selectedClass);

                if (selected)
                    this._trigger("select", null, { item: tr.data('item'), element: tr });
                else
                    this._trigger("deselect", null, { item: tr.data('item'), element: tr });
            }
        },
        priority: function(priority) {
            if (isNaN(priority)) return;
            var priorities = 'priority-1 priority-2 priority-3 priority-4 priority-5 priority-6  priority-7  priority-8  priority-9  priority-10';
            this.table.removeClass(priorities).addClass("priority-" + priority);
        },
        refresh: function(data) {
            var self = this, element = self.element;
            if (data)
                self.items = data;

            // generate rows
            var body = self.element.find('tbody');
            self._generateBodyRows(body);

            //self._trigger("refresh", null, {});
        },
        select: function(item) {
            this._toggle(item, true);
        },
        deselect: function(item) {
            this._toggle(item, false);
        },
        get: function(key) {
            var tr = this.keyIndex[key];
            return { item: tr.data('item'), element: tr };
        }
    });
})(jQuery);