/** 
 * @file jquery.ds.checkbox.js
 * @ver 0.1
 *
 * Copyright (c) 2010 Dániel Sólyom (DS)
 *
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * 2010-03-14
 */

(function($) {
    /* true or false (browser compatibility for attr) */
    $.isTrue = function(value)
    {
        return (value == 'true' || value === true);
    }
    /* change checkbox skin */
    $.fn.skinCheckbox = function(settings)
    {
		var settings = $.extend({}, $.fn.skinCheckbox.defaults, settings);
    
        me = $(this);

        me.each(function() {
            var me = $(this);
            me.hide();

            me.before(
                me.get(0).chkSubstitute = substitute =
                /* span to be inline like input */
                $('<span></span>').addClass(settings.skinClass)
                                .addClass(me.attr('checked') ? 'chk-subst-checked' : '')
                                .addClass('chk-subst')
                                .attr('checked', me.attr('checked'))
                                            /* prevent text selection */
                                .css({ 'MozUserSelect' : 'none' })
                                .bind('selectstart', function() {
                                    return false;
                                })
                                .mousedown(function() {
                                    return false;
                                })
                                            /* select, unselect */
                                .extend({
                                    mycheckbox: me,
                                    toggleChk: function() {
                                        $(this).toggleClass('chk-subst-checked')
                                               .attr('checked', !me.attr('checked'));
                                        me.attr('checked', !me.attr('checked'));
                                        /* call change event */
                                        me.change();
                                    },
                                    selectChk: function() {
                                        $(this).addClass('chk-subst-checked')
                                               .attr('checked' , true);
                                        checked = me.attr('checked');
                                        me.attr('checked', true);
                                        /* call change event if changed */
                                        if (!$.isTrue(checked)) {
											me.change();
										}
                                    },
                                    unselectChk: function() {
                                        $(this).removeClass('chk-subst-checked')
                                               .attr('checked', false);
                                        checked = me.attr('checked');
                                        me.attr('checked', false);
                                        /* call change event */
                                        if ($.isTrue(checked)) {
											me.change();
										}
                                    }
                                })
            );

                /* handle click */
            substitute.click(substitute.toggleChk);
        });

        return this;
    }
    
    $.fn.skinCheckbox.defaults = {
        skinClass: 'default-checkbox-skin'
    }
    
    /* master checkbox to toggle all */
    $.fn.checkboxMaster = function(slaves)
    {
        master = $(this).checkboxInit();

        if (master == undefined) {
			return false;
		}

        for(var i = 0; i < slaves.length; ++i) {
            slaves[i] = $(slaves[i]).checkboxInit();
        }

        master.click(function() {
            if ($.isTrue(master.attr('checked'))) {
                for(var i = 0; i < slaves.length; ++i) {
                    slaves[i].selectChk();
                }
            } else {
                for(var i = 0; i < slaves.length; ++i) {
                    slaves[i].unselectChk();
                }
            }
        })
    }

    /**
     *  set a checkbox which if checked is equal with all checked 
     *
     *  @param array or $ slaves
     */
    $.fn.checkboxActAll = function(slaves)
    {
        var master = $(this).checkboxInit();
        if (master == undefined) {
			return false;
		}
        if (master == undefined) {
			return false;
		}
        
        var slaveCnt;
        var checkedCnt = 0;

        var sL = (slaves = this.visibleCheckboxes($(slaves))).length;

        master.click(function() {
            for(var i = 0; i < slaves.length; ++i) {
				slaves[i].unselectChk();
            }
            checkedCnt = 0;
            master.selectChk();
        })

        for(var i = 0; i < sL; ++i) {
            if (slaves[i][0] == master[0]) {
				slaves.splice(i, 1);
				--i;
				--sL;
                continue;
            }
            slaves[i].click(function() {    /* all or none checked? */
                ((checkedCnt += $.isTrue($(this).attr('checked')) ? 1 : -1) > 0)
//                                && checkedCnt != slaveCnt) - want to deselect all if everything is selected ?
                    ? master.unselectChk() : master.click();
            })
            checkedCnt += $.isTrue(slaves[i].attr('checked')) ? 1 : 0;
        }

        if (checkedCnt == 0) {
            /* check master but prevent change event firing */
			if (master.mycheckbox) {
				master.addClass('chk-subst-checked').attr('checked', true);
				master.mycheckbox.attr('checked', true);
			} else {
				master.attr('checked', true);
			}
        }

        return this;
    }

    /** 
     *  init one checkbox (first in $)
     *
     *  @return $           - $(checkbox substitute) || $(checkbox)
     */
    $.fn.checkboxInit = function()
    {
		var box = $(this)[0];
		
		if (box == undefined) {
			return box;
		}
		
        var me = box.chkSubstitute;

        if (me === undefined) { /* no checkbox skin */
            me = $(box).extend({
                    toggleChk: function() {
                        me.attr('checked', !me.attr('checked'));
                    },
                    selectChk: function() {
                        me.attr('checked', true);
                    },
                    unselectChk: function() {
                        me.attr('checked', false);
                    }
                 });
        }

        return me;
    }

    /**
     *  visibleCheckboxes - the skin element if skin , checkbox if no skin
     *
     *  @param $ or array boxes
     *
     *  @return $
     */
    $.fn.visibleCheckboxes = function(boxes)
    {
        boxes = $(boxes);

        for(var i = 0; i < boxes.length; ++i) {
            boxes[i] = $(boxes[i]).checkboxInit();
        }
        return boxes;
    }
    
})(jQuery)
