
$.fn.remoteValidate = function(conf) {
    var inputTypes = [
        'input[type=text]',        
        'input[type=checkbox]',
        'input[type=password]',
        'input[type=radio]',
        'input[type=hidden]',
        'select',
        'textarea'
    ].join(',')
    
    function showError(field, message) {
        var div = $(field.parentNode).children('.error')[0]
        if(!div) {
            div = $('<div class="error"></div>').appendTo(field.parentNode)
        }
        $(div).html(message).show()        
    }
    function hideError(field) {
        $(field.parentNode).children('.error').html('').hide()
    }    
    
    this.each(function() {
        var jform = $(this)
        var url = jform.attr('action')
        

        // Add onchange listener to all contained fields
        jform.find(inputTypes).change(function() {
            var field = this
            var data = {} 
            data[this.name] = this.value
            $.ajax({
                url: url,
                type: 'post',
                dataType: 'json',
                data: data,
                beforeSend: function(xmlhttp) {
                    xmlhttp.setRequestHeader('X-Validate', '1')
                },                
                error: function(xmlhttp, b, c) {
                    eval('var errors='+xmlhttp.responseText)
                    showError(field, errors[field.name])
                },
                success: function() {
                    hideError(field)
                }
            })
        })
        
        // Add an onsubmit listener posting the form using ajax
        var onsubmit = function() {
            var data = []
            var success = true
            var groups = {}
            
            jform.find(inputTypes).each(function() {    
                var type = this.type ? this.type.toLowerCase() : ''
                var is_text = ['text', 'password'].indexOf(type) !== -1
                var is_textarea = this.tagName.toLowerCase() == 'textarea'
                var is_select = this.tagName.toLowerCase() == 'select'
                var is_checkable = type == 'radio' || type == 'checkbox'
                
                if((is_text || is_textarea || is_select)) {
                    data.push([this.name, this.value.replace(/&/g, '&amp;')]) // escape(this.value)
                }
                else if(is_checkable) {
                    groups[this.name] = true
                    if(this.checked)
                        data.push([this.name, this.value.replace(/&/g, '&amp;')]) // escape(this.value)
                }
            })
            
            // Make sure even unchecked checkboxes etc are added
            // to the post body
            for(var name in groups) {
                var exists = false
                for(var tup in data) {
                    if(tup[0] == name) {
                        exists = true
                        break
                    }
                }
                if(!exists) {
                    data.push([name, ''])
                }
            }
            
            data = $.map(data, function(tup) { 
                return tup[0]+'='+tup[1].replace(/&/g, '&amp;') // escape(tup[1])
            }).join('&')
            
            $.ajax({
                url: url,
                type: 'post',
                dataType: 'json',
                // dataType: "application/x-www-form-urlencoded",
                data: data,
                beforeSend: function(xmlhttp) {
                    xmlhttp.setRequestHeader('X-Validate', '1')
                    // xmlhttp.setRequestHeader('Content-type', 'x-www-form-urlencoded')
                },
                error: function(xmlhttp, textStatus, errorThrown) {
                    eval('var errors=' +xmlhttp.responseText)
                    
                    var visited = {}
                    $(jform.find(inputTypes).get().reverse()).each(function() {
                        if(errors[this.name] && !visited[this.name]) {
                            showError(this, errors[this.name])
                        }
                        else {
                            hideError(this)
                        }
                        visited[this.name] = true
                    })
                    var pos = jform.find('.error:first').position()
                    $(window.document).scrollTop(pos.top-30)
                    return false
                },
                success: function(a,b,c,d) {
                    jform.unbind('submit', onsubmit)
                    jform.data('valid', true)
                    jform.submit()
                    jform.data('valid', false)                    
                    // prevent submitting twice 
                    // jform.submit(function() {return false})
                    jform.submit(onsubmit)                    
                }
                // complete: function(a,b,c,d) {
                // }
            })  
            return false
        }
        jform.submit(onsubmit)
    })
}
