
(function(jQuery) {
    jQuery.fn.checkTree = function(settings) {

        settings = jQuery.extend({
            /* Callbacks
            The callbacks should be functions that take one argument. The checkbox tree
            will return the jQuery wrapped LI element of the item that was checked/expanded.
            */
            onExpand: null,
            onCollapse: null,
            onCheck: null,
            onUnCheck: null,
            onHalfCheck: null,
            onLabelHoverOver: null,
            onLabelHoverOut: null,

            /* Valid choices: 'expand', 'check' */
            labelAction: "expand",

            // Debug (currently does nothing)
            debug: false
        }, settings);

        var $tree = this;

        $tree.find("li")

        // Hide all of the sub-trees
        .find("ul")
            .hide()
        .end()

        // Hide all checkbox inputs
        .find(":checkbox")
            .change(function() {
                // Fired when the children of this checkbox have changed.
                // Children can change the state of a parent based on what they do as a group.
                var $all = jQuery(this).siblings("ul").find(":checkbox");
                var $checked = $all.filter(":checked");

                // All children are checked
                if ($all.length == $checked.length) {
                    jQuery(this)
                        .attr("checked", "checked")
                        .siblings(".checkbox")
                            .removeClass("half_checked")
                            .addClass("checked")
                    ;
                    // Fire parent's onCheck callback
                    if (settings.onCheck) settings.onCheck(jQuery(this).parent());
                }

                // All children are unchecked
                else if ($checked.length == 0) {
                    jQuery(this)
                        .attr("checked", "")
                        .siblings(".checkbox")
                            .removeClass("checked")
                            .removeClass("half_checked")
                    ;
                    // Fire parent's onUnCheck callback
                    if (settings.onUnCheck) settings.onUnCheck(jQuery(this).parent());
                }

                // Some children are checked, makes the parent in a half checked state.
                else {
                    // Fire parent's onHalfCheck callback only if it's going to change
                    if (settings.onHalfCheck && !jQuery(this).siblings(".checkbox").hasClass("half_checked"))
                        settings.onHalfCheck(jQuery(this).parent());

                    jQuery(this)
                        .attr("checked", "")
                        .siblings(".checkbox")
                            .removeClass("checked")
                            .addClass("half_checked")
                    ;
                }
            })
            .attr("checked", "")
            .hide()
        .end()


        .find("label")
        // Clicking the labels should expand the children
            .click(function() {
                var action = settings.labelAction;
                switch (settings.labelAction) {
                    case 'expand':
                        jQuery(this).siblings(".arrow").click();
                        
                        if (!jQuery(this).parent("li").is(":has(li)")) {
                            jQuery(this).siblings(".checkbox").click();
                        }
                        break;
                    case 'check':
                        jQuery(this).siblings(".checkbox").click();
                        break;
                }
            })

        // Add a hover class to the labels when hovering
            .hover(
                function() {
                    jQuery(this).addClass("hover");
                    if (settings.onLabelHoverOver) settings.onLabelHoverOver(jQuery(this).parent());
                },
                function() {
                    jQuery(this).removeClass("hover");
                    if (settings.onLabelHoverOut) settings.onLabelHoverOut(jQuery(this).parent());
                }
            )
        .end()

        .each(function() {

            // Create the image for the arrow (to expand and collapse the hidden trees)
            var $arrow = jQuery('<div class="arrow"></div>');

            // If it has children:
            if (jQuery(this).is(":has(ul)")) {
                $arrow.addClass("collapsed"); // Should start collapsed

                // When you click the image, toggle the child list
                $arrow.click(function() {
                    jQuery(this).siblings("ul").toggle();
                    //jQuery(this).siblings("ul").addClass("submenu")
                    jQuery(this).parent().toggleClass("hover1")

                    if (jQuery(this).hasClass("collapsed")) {
                        //toggled = settings.expandedarrow;
                        jQuery(this)
                            .addClass("expanded")
                            .removeClass("collapsed")
                        ;
                        if (settings.onExpand) settings.onExpand(jQuery(this).parent());
                    }
                    else {
                        //toggled = settings.collapsedarrow;
                        jQuery(this)
                            .addClass("collapsed")
                            .removeClass("expanded")
                        ;
                        if (settings.onCollapse) settings.onCollapse(jQuery(this).parent());
                    }
                });
            }

            // Create the image for the checkbox next to the label
            var $checkbox = jQuery('<div class="checkbox"></div>');

            // When you click the checkbox, it should do the checking/unchecking
            $checkbox.click(function() {
                // Make the current class checked
                jQuery(this)
                // if it's half checked, its now either checked or unchecked
                    .removeClass("half_checked")
                    .toggleClass("checked")

                // Send a click event to the checkbox to toggle it as well
                    .siblings(":checkbox").click()
                ;

                // Check/uncheck children depending on our status.
                if (jQuery(this).hasClass("checked")) {
                    // Fire the check callback for this parent
                    if (settings.onCheck) settings.onCheck(jQuery(this).parent());

                    jQuery(this).siblings("ul").find(".checkbox").not(".checked")
                        .removeClass("half_checked")
                        .addClass("checked")
                        .each(function() {
                            if (settings.onCheck) settings.onCheck(jQuery(this).parent());
                        })
                        .siblings(":checkbox")
                            .attr("checked", "checked")
                    ;
                }
                else {
                    // Fire the uncheck callback for this parent
                    if (settings.onUnCheck) settings.onUnCheck(jQuery(this).parent());

                    jQuery(this).siblings("ul").find(".checkbox").filter(".checked")
                        .removeClass("half_checked")
                        .removeClass("checked")
                        .each(function() {
                            if (settings.onUnCheck) settings.onUnCheck(jQuery(this).parent());
                        })
                        .siblings(":checkbox")
                            .attr("checked", "")
                    ;
                }
                // Tell our parent checkbox that we've changed
                jQuery(this).parents("ul").siblings(":checkbox").change();
            });

            // Prepend the arrow and checkbox images to the front of the LI
            jQuery(this)
                .prepend($checkbox)
                .prepend($arrow)
            // Add a hover li when hovering
            .hover(
                function() {
                    jQuery(this).addClass("hover");
                },
                function() {
                    jQuery(this).removeClass("hover");
                }
            )
            .end()
            ;
        })
    ;

        return $tree;
    };
})(jQuery);



