/**
 * jQuery Graphic Checkboxes and Radio boxes Plugin
 * 
 * Moves checkboxes and radioboxes to a hidden container and replaces them with fancy elements of your choice.
 * Triggers custom 'check' and 'uncheck' events on these elements, instead of the default (and more vague) 'click' event.
 * Version 0.8
 * Date: 04-25-2011
 ************************************************************************************************************************
 *
 * Example:
 *
 * $(document).ready(function{
 *     
 *     $('.mycheckbox').fancyCheckboxes();
 *     
 *      //or
 *      $('.myradiobox').fancyCheckboxes({
 *          'on':  'on.png',
 *          'off': 'off.png',
 *          'path':      'images/' 
 *      });
 *      
 *      //listening to the custom events
 *      $('.mycheckbox').bind('check', function(){
 *          console.log('element has been checked');
 *      });
 *      
 *      $('.mycheckbox').bind('uncheck', function(){
 *          console.log('element has been UNchecked');
 *      });
 *      
 * });
 *
 */
(function($){
    $.fn.fancyCheckbox = function(options){
        
        //defaults array
        var settings = {
            'on':   'checkbox-checked.png',
            'off':  'checkbox.jpg',
            'path': '/skin/frontend/default/inpink/images/'
        };
        
        //parent element that the hidden inputs container will be attached to
        var form = null;
        
       /* Checked elements replacements
        * @param {Object} item - Object with info about the replaced element
        * @return null
        */
        var check = function(item){
            var id = item.attr('id');
            var name = item.attr('name');
            
            // assign a random id to the original element and to the replacement if the original has none
            if (id == '') {
                id = Math.round(Math.random() * 10000);
            }
            
            item.attr('id', id);
            
            var type = item.attr('type');
            var parent = item.parent();
            
            if (type == 'checkbox') {
                item.replaceWith('<img id="fancyCheckboxes-' + id + '" class="checkboxes" src="' + settings.path + settings.on + '" />');
            }
            if (type == 'radio') {
                item.replaceWith('<img id="fancyCheckboxes-' + id + '" class="radio" rel="' + item.attr('name') + '" src="' + settings.path + settings.on + '" />');
            }
            
            // alter the actual inputs
            formCheck({
                id: id,
                name: name,
                parent: parent,
                type: type,
                className: item.attr('class')
            });
        }
        
        /* Unchecked elements replacements
        *  @param {Object} item - Object with info about the replaced element
        *  @return null
        */
        var uncheck = function(item){
            var id = item.attr('id');
            var type = item.attr('type');
            var parent = item.parent();
            var name = item.attr('name');
            
            if (type == 'checkbox') {
                
                item.replaceWith('<img id="fancyCheckboxes-' + id + '" class="checkboxes" src="' + settings.path + settings.off + '" />');
            }
            if (type == 'radio') {
                
                item.replaceWith('<img id="fancyCheckboxes-' + id + '" class="radio" rel="' + item.attr('name') + '" src="' + settings.path + settings.off + '" />');
            }
            
            // alter the actual inputs
            formUncheck({
                id: id,
                name: name,
                parent: parent,
                type: type,
                className: item.attr('class')
            });
        }
        
        /* Gets or creates the container for the old inputs
        *  @return null
        */
        var getInputContainer = function(){
            if (!$('#fancyInputContainer').length) {
                var c = $('<div id="fancyInputContainer"></div>');
                c.hide();
                c.appendTo(form);
            }
            return $('#fancyInputContainer');
        }
        
        /* Checks or moves the actual hidden inputs that were replaced
        *  @param {Object} item - Object with info about the replaced element
        *  @param {Boolean} click - When click is true this happens because the user has clicked a mock checkbox or radio box. If it's a radio input, unchecks the others in the same group.
        *  @return null
        */
        var formCheck = function(item, click){
        
            var container = getInputContainer();
            
            if (container.find('input[type="' + item.type + '"]#' + item.id).length == 0) {
                
                container.prepend('<input class="'+ item.className +'" type="' + item.type + '" name="' + item.name + '" id="' + item.id + '" ' + (item.value != undefined ? ' value="' + item.value + '"' : ' checked="checked"') + ' />');
            }
            else {
                
                container.find('input[type="' + item.type + '"]#' + item.id).attr('checked', 'checked');
            }
            
            if(click && item.type == 'radio'){
                container.find('input[type="radio"]').filter(function(){
                
                    if($(this).attr('id') != item.id && $(this).attr('name') == item.name) return true;
                    
                }).each(function(i,item){
                
                    $(item).attr('checked', '');
                    $('#fancyCheckboxes-' + $(item).attr('id')).attr('src', settings.path + settings.off);
                });
            }
            
            //trigger the custom 'check' event for this element
            $('#' + item.id).trigger('check');
        }
        
        /* Unchecks or moves the actual hidden inputs that were replaced
        *  @param {Object} item - Object with info about the replaced element
        *  @return null
        */
        var formUncheck = function(item){
        
            var container = getInputContainer();
            
            if (container.find('input[type="' + item.type + '"]#' + item.id).length == 0) {
                
                container.prepend('<input class="'+ item.className +'" type="' + item.type + '" name="' + item.name + '" id="' + item.id + '" ' + (item.value != undefined ? ' value="' + item.value + '"' : '') + ' />');
            }
            else {
                
                container.find('input[type="' + item.type + '"]#' + item.id).removeAttr('checked');
            }
            
            //trigger the custom 'uncheck' event for this element
            $('#' + item.id).trigger('uncheck');
        }
        
        /* Small abstracted replacement logic, only dispatches to corresponding methods, based on wether the element has to appear checked or unchecked.
        *  @param {Object} item - The element to be replaced.
        *  @return null
        */
        var replaceWithImages = function(item){
            
            item.is(':checked') ? check(item) : uncheck(item);
        }
        
        // jquery plugin dispatching
        return this.each(function(){
        
            // If options exist, lets merge them
            // with our default settings
            if (options) {
                $.extend(settings, options);
            }
            
            //get parent form -  if element is not inside a form just return the body. The hidden inputs container will be placed at the end of the body.
            form = $(this).parents('form');
            if( !form.length ){
                form = $('body');
            }
            
            //replace with images at startup
            replaceWithImages($(this));
            
            //add click behaviour
            var id = $(this).attr('id');
            var that = $(this);
            
            $('#fancyCheckboxes-' + $(this).attr('id')).live('click', function(){
            
                var img = $(this);
                
                if ($('#' + id).is(':checked')) {
                    
                    if ($('#' + id).attr('type') == 'radio') {
                        //nothing, radioboxes can't be UN-checked by clicking on them
                    }
                    else {
                        img.attr('src', settings.path + settings.off);
                        
                        formUncheck({
                            id: id,
                            type: that.attr('type'),
                            name: that.attr('name'),
                            parent: that.parent()
                        });
                    }
                    
                }
                else {
                
                    if ($('#' + id).attr('type') == 'radio') {
                        img.attr('src', settings.path + settings.on);
                    } else {
                        img.attr('src', settings.path + settings.on);
                    }
                    
                    formCheck({
                        id: id,
                        parent: img.parent(),
                        type: that.attr('type'),
                        name: that.attr('name')
                    }, true);
                }
                
                return false;
            });
            
            
        });
    };
})(jQuery)

