/*
#
# jquery.greatforms.js
#
# by Ludwig Pettersson
# <http://luddep.se>
#
 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
 
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
*/
(function() {

    // settings
    var default_settings = {
        sprite: false,
        checkbox: {
            size: {
                width: 14,
                height: 14
            },
            position: {
                selected: {
                    normal: { x: 14, y: 0},
                    clicked: { x: 42, y: 0}
                },
                normal: {
                    normal: { x: 0, y: 0},
                    clicked: { x: 28, y: 0}
                }
            }
        },
        radio: {
            size: {
                width: 12,
                height: 12
            },
            position: {
                selected: {
                    normal: { x: 14, y: 16},
                    clicked: { x: 42, y: 16}
                },
                normal: {
                    normal: { x: 0, y: 16},
                    clicked: { x: 28, y: 16}
                }
            }
        },
        select: {
            size: {
                height: 22
            },
            label: {
                padding: { left: 7, top: 4 }
            },
            left: {
                width: 5,
                position: {
                    normal: { x: 0, y: 28 },
                    clicked: { x: 0, y: 28 }
                }
            },
            middle: {
                position: {
                    normal: { x: 0, y: 50 },
                    clicked: { x: 0, y: 50 }
                }
            },
            right: {
                width: 21,
                position: {
                    normal: { x: 0, y: 72 },
                    clicked: { x: 21, y: 72 }
                }
            }
        },
        submit: {
            size: {
                height: 22
            },
            padding: {
                left: 15,
                top: 2
            },
            left: {
                width: 12,
                position: {
                    normal: { x: 0, y: 94 },
                    clicked: { x: 24, y: 94 }
                }
            },
            middle: {
                position: {
                    normal: { x: 0, y: 116 },
                    clicked: { x: 0, y: 138  }
                }
            },
            right: {
                width: 12,
                position: {
                    normal: { x: 12, y: 94 },
                    clicked: { x: 34, y: 94 }
                }
            }
        },
        file: {
            size: {
                height: 22
            },
            labels: {
                button: 'Choose file',
                _default: 'no file selected'
            }
        }
    };
        
    
    /*
    ** function: getElementType()
    ** Returns the form type of the element passed in
    * ie: select, checkbox, text, textarea etc
    *
    */
    function getElementType(element) {
        if(typeof(element) == 'object') {
            element = $(element);
            var type = element.attr('type');
            if(type) {
                if(type == 'select-one')
                    type = 'select'
                
                return type;
            } else {
                return element.tagName;
            }
        } else {
            return element;
        }
    }
    
    /*
    ** function: getSize()
    ** Returns the size of the replacement element
    */
    function getSize(element, settings) {
        return settings[getElementType(element)]['size'];
    }
    
    /*
    ** function: getReplacementPosition()
    ** Finds the correct image position for the element
    */
    function getReplacementPosition(element, element_state, mousedown_state, settings) {
        var type = getElementType(element);
        
        if(type == 'checkbox' || type == 'radio') {
            var position = settings[type]['position'][element_state][mousedown_state];
            return '-'+position.x+'px -'+position.y+'px';
        } else if(type == 'select' || type == 'submit') {
            var left = settings[type]['left']['position'][mousedown_state];
            var middle = settings[type]['middle']['position'][mousedown_state];
            var right = settings[type]['right']['position'][mousedown_state];
            
            return {
                left: '-'+left.x+'px -'+left.y+'px',
                middle: '-'+middle.x+'px -'+middle.y+'px',
                right: '-'+right.x+'px -'+right.y+'px',
            }
        
        }
    }
    
    /*
    ** function: getLabelForElement()
    ** Finds the correct image position for the element
    */
    function getLabelForElement(element) {
        var id = $(element).attr('id');
        return $('label[for='+id+']');
    }
    
    /*
    ** function: replaceCheckAndRadio()
    ** Creates and returns replacement element for checkboxes and radiobuttons
    */
    function replaceCheckAndRadio(element, settings) {
        var invert = false;
        var label = getLabelForElement(element);
        var replacement = $('<div></div>');
        var type = getElementType(element);
        var size = getSize(element, settings);
        var position = getReplacementPosition(type, 'normal', 'normal', settings);
        
        if(element.attr('checked') || element.attr('selected'))
            position = getReplacementPosition(type, 'selected', 'normal', settings)
        
        replacement.css({
            'background': 'url('+settings.sprite+') '+position,
            'width': size.width+'px',
            'height': size.height+'px',
            'display': 'inline-block'
        });
        
        // ##
        // Checkbox & Radiobutton
        // ##
        if(type == 'checkbox' || type == 'radio') {
            element.hide(0);
            
            var click = function() {
            
                if(type == 'radio') {
                    var group = $('input[type=radio][name='+element.attr('name')+']');
                    group.each(function() {
                        // This is not a good solution.. fix it!
                        $(this).prev().css('background-position', getReplacementPosition(type, 'normal', 'normal', settings));
                    });
                }
            
                selected = $(this).attr('checked') ? $(this).attr('checked') : $(this).attr('selected');
                if(invert)
                    selected = !selected
                
                replacement.css({
                    'background-position': getReplacementPosition(type, selected ? 'selected' : 'normal', 'normal', settings),
                });
            };
            
            var mousedown = function() {
                elem = $(this);
                if(this.tagName == 'LABEL') {
                    var original_elem = $('input#'+elem.attr('for'));
                    var replacement_elem = original_elem.prev();
                } else {
                    var original_elem = elem.next();
                    var replacement_elem = elem;
                }
                selected = original_elem.attr('checked') ? original_elem.attr('checked') : original_elem.attr('selected');
                replacement_elem.css({
                    'background-position': getReplacementPosition(type, selected ? 'selected' : 'normal', 'clicked', settings),
                });
            };
            
            // Attach events
            element.click(click);
            replacement.mousedown(mousedown);
            label.mousedown(mousedown);
        
            replacement.click(function() {
                invert = true;
                element.click();
                invert = false;
            });
        }
        
        return replacement;
    }
    
    /*
    ** function: createSideElement()
    ** Creates and returns an element for a side
    */
    function createSideElement(side, width, height, position, settings) {
        var className = side;
        if(side == 'left') {
            var left = 0;
            var right = false;
        } else {
            var left = false;
            var right = 0;
        }
        
        return $('<div></div>').css({
                        'width': width,
                        'height': height,
                        'background': 'url('+settings.sprite+') '+position,
                        'position': 'absolute',
                        'top': 0,
                        'left': left,
                        'right': right,
                        'z-index': '100'
                    }).addClass(className);
    }

    /*
    ** function: createMiddleElement()
    ** Creates and returns an element for a side
    */
    function createMiddleElement(left, right, height, position, settings) {
        return $('<div></div>').css({
                        'height': height,
                        'background': 'url('+settings.sprite+') '+position,
                        'position': 'absolute',
                        'top': 0,
                        'left': left,
                        'right': right,
                        'z-index': '100',
                    }).addClass('middle');
    }

    /*
    ** function: createWrapElement()
    ** Creates and returns an element to wrap an element
    */
    function createWrapElement(height) {
        return $('<div></div>').css({
                        'display': 'inline-block',
                        'position': 'relative',
                        'height': height,
                    });
    }

    /*
    ** function: replaceSelect()
    ** Replaces select element
    */
    function replaceSelect(element, settings) {
        var type = getElementType(element);
        var height = getSize(element, settings).height;
        var position = getReplacementPosition(type, false, 'normal', settings);
        
        element.fadeTo(0,0);
        element.wrap(createWrapElement(height));
        
        var label = $('<div></div>').css({
                        'z-index': '120',
                        'position': 'absolute',
                        'top': 0,
                        'padding-top': settings[type].label.padding.top+'px',
                        'padding-left': settings[type].label.padding.left+'px',
                    });
        
        var left = createSideElement('left', settings[type]['left']['width'], height, position.left, settings);
        var right = createSideElement('right', settings[type]['right']['width'], height, position.right, settings);
        var middle = createMiddleElement(settings[type]['left']['width'], settings[type]['right']['width'], height, position.middle, settings);
        
        element.after(right);
        element.after(middle);
        element.after(left);
        element.after(label);
        
        element.change(function(){
            label.text($(':selected', this).text());
        });
        
        element.mousedown(function(){
            right.css('background-position', getReplacementPosition($(this), false, 'clicked', settings).right);
        });
        
        element.mouseup(function(){
            right.css('background-position', position.right);
        });
        
        label.text($('option[value='+element.val()+']', element).text());
        
    }

    /*
    ** function: replaceFile()
    ** Replaces a file input
    */
    function replaceFile(element, settings) {
        var height = getSize(element, settings).height;
        var type = getElementType(element);
        var label = $('<div>'+settings[type]['labels']['_default']+'</div>').css({display: 'inline-block', 'padding-left': '5px'});

        var wrap = createWrapElement(height);
        element.wrap(wrap);
        element.after(label);
        
        var button = $('<button>'+settings[type]['labels']['button']+'</button>');

        element.css({
            position: 'absolute',
            'z-index': '9999',
            height: height,
            cursor: 'default'
        })
        .fadeTo(0, 0)
        .after(button);
        replaceButton(button, settings);

        var mouseup = function(){ button.mouseup(); }
        element.mousedown(function(){ button.mousedown(); });
        element.mouseup(mouseup);
        element.blur(mouseup);
        element.change(function(){ label.html($(this).val()); });
    }


    /*
    ** function: replaceButton()
    ** Replaces a button
    */
    function replaceButton(element, settings) {
        var type = getElementType(element);
        var position = getReplacementPosition(type, false, 'normal', settings);
        var height = getSize(element, settings).height;
        
        element.css({
            background: 'none',
            'z-index': '200',
            'position': 'relative',
            'padding-top': settings[type].padding.top+'px',
            'padding-left': settings[type].padding.left+'px',
            'padding-right': settings[type].padding.left+'px',
            border: '0',
        });

        var left = createSideElement('left', settings[type]['left']['width'], height, position.left, settings);
        var right = createSideElement('right', settings[type]['right']['width'], height, position.right, settings);
        var middle = createMiddleElement(settings[type]['left']['width'], settings[type]['right']['width'], height, position.middle, settings);

        element.wrap(createWrapElement(height));
        element.before(middle);
        element.before(left);
        element.before(right);
        
        element.mousedown(function(){
            var position_clicked = getReplacementPosition(type, false, 'clicked', settings);
            left.css('background-position', position_clicked.left);
            middle.css('background-position', position_clicked.middle);
            right.css('background-position', position_clicked.right);
        });
        
        var deselected = function() {
            left.css('background-position', position.left);
            middle.css('background-position', position.middle);
            right.css('background-position', position.right);
        }
        
        element.mouseup(deselected);
        element.blur(deselected);
        
    }
    
    /*
    ** function: replace()
    ** Replaces the form element with the custom
    */
    function replace(element, settings) {
        element = $(element);
        type = getElementType(element);

        if(type == 'checkbox' || type == 'radio')
            element.before(replaceCheckAndRadio(element, settings));
        else if(type == 'select')
            replaceSelect(element, settings)
        else if(type == 'file')
            replaceFile(element, settings)
        else if(type == 'submit')
            replaceButton(element, settings)
    }
    
    
    jQuery.fn.formize = function(settings) {
        var settings = jQuery.extend(default_settings, settings);
        
        $('input, select, button', this).each(function(i, element){
            replace(element, settings);
        });
    };

})();