(function($) {
    //Enables to select rows in a table.
    //Write chosen attribute of selected rows to any other element. hidden or textbox to handle postbacks.

    //Creating namespace for rowselect
    jQuery.rowSelect = {};

    //Namespace for settings
    jQuery.rowSelect.settings =
    {
        tableClassName: 'rowSelect',
        rowSelectedClassName: 'selected'
    }

    //Default values for a rowSelect table
    jQuery.rowSelect.defaults = function() {
        this.tableId = '';
        this.attachTo = '';
        this.attrName = '';
        this.allowMulti = false;
        this.onSelect = function(tr) { };


    }

    //an array to hold settings for individual tables
    jQuery.rowSelect.allSettings = new Array();

    //Namespace for functions
    jQuery.rowSelect.api = {};

    //return all selected rows    
    jQuery.rowSelect.api.getSelected = function(selector) {
        var t = $(selector)[0];
        if (!t) return;
        return $("tr.selected", t)
    }

    //Find settings object for TR    
    jQuery.rowSelect.api.getSetting = function(tr) {
        //Find table....
        table = $(tr).parents('table:first');

        //if the table is not found.. Something is wrong 'aborting'
        if (table.length == 0) return;

        //Getting the settings object for this table.
        //There is a possible 'hickup' here if the table does't have an id. 

        return $.rowSelect.allSettings[table[0].id];


    }

    //select the row...
    jQuery.rowSelect.api.selectRow = function(tr) {

        //Get settings object for this TR
        var tSettings = jQuery.rowSelect.api.getSetting(tr);

        //no settings object found. Somthing is wrong.. Aborting.
        if (!tSettings) return;

        //Trigger callback of onSelectEvent
        tSettings.onSelect(tr);
        var $tr = $(tr);

        //Check if it is multi or single select and handle accordingly...
        if (tSettings.allowMulti) {
            //toggle the class for this line
            $tr.toggleClass($.rowSelect.settings.rowSelectedClassName);

            var vals = new Array;
            var selected = jQuery.rowSelect.api.getSelected("#" + tSettings.tableId);

            for (var x = 0; x < selected.length; x++) {
                vals[x] = $(selected[x]).attr(tSettings.attrName);
            }
            $(tSettings.attachTo).val(vals.join(','));
        }

        else {
            $("tr", table).removeClass($.rowSelect.settings.rowSelectedClassName);
            $tr.addClass($.rowSelect.settings.rowSelectedClassName);

            //If current line is selected set the value to the attached input
            if ($tr.hasClass($.rowSelect.settings.rowSelectedClassName)) {
                var thisVal = $tr.attr(tSettings.attrName);
                $(tSettings.attachTo).val(thisVal);
            }
        }

    }

    //The main plugin..
    jQuery.fn.rowSelect = function(settings) {

        this.each(function(i) {
            //Only tables is allowed to be selected..
            if (this.tagName.toUpperCase() != 'TABLE') return;

            //Creating settings object for this call
            var s = new $.rowSelect.defaults();
            $.extend(s, settings);
            s.tableId = this.id;

            //Adding the classname to the tbody of the table.
            //Maybe change this to table?
            $("tbody", this).addClass($.rowSelect.settings.tableClassName);

            //Storing the values for this table in then allSettings array
            $.rowSelect.allSettings[this.id] = s;

            //Reading values from then attached input. In case of someone sending a string of ',' seperated values to indicate wiche rows to initially show as selected.
            //Looing trough all tr of the table, to check if it should be selected
            var vals = $(s.attachTo).val().split(',');
            $("tbody tr", this).each(function() {
                for (var x = 0; x < vals.length; x++) {
                    if ($(this).attr(s.attrName) == vals[x]) {
                        $(this).addClass($.rowSelect.settings.rowSelectedClassName)
                    }
                }
            })
            //End of init check.


            //Attaching keyDown to handle using the arrows for selecting...
            $("tbody", this).bind("keydown",
                function(e) {

                    //Getting the tr and not anything else the user might have clicked...
                    if (e.target.tagName != 'tr') {
                        tr = $(e.target).parents('tr:first');
                    } else {
                        tr = e.target;
                    }
                    var tSettings = jQuery.rowSelect.api.getSetting(tr);

                    var tr = jQuery.rowSelect.api.getSelected("#" + tSettings.tableId)[0];
                    var newTr;

                    switch (e.which) {
                        case 38: //Up arrow
                            newTr = $(tr).prev();
                            break;
                        case 40: //Down arrow
                            newTr = $(tr).next();
                            break;
                    }
                    if (newTr) jQuery.rowSelect.api.selectRow(newTr);
                })


            //Attaching the click event to the tbody of the table. 
            $("tbody", this).bind("click",
                function(e) {
                    var tr, $tr;
                    var table;

                    //Getting the tr and not anything else the user might have clicked...
                    if (e.target.tagName != 'tr') {
                        tr = $(e.target).parents('tr:first');
                    } else {
                        tr = e.target;
                    }
                    ///////////////////////////////


                    jQuery.rowSelect.api.selectRow(tr);

                })
        }
        )
        return this;
    }
})(jQuery);
