jQuery.fn.quickform = function(opts) {
    var self = this;
    var currentSectionIndex = 0;
    var sectionWidth   =-1;
    var sectionHeight  =-1;        
    var isAnimating = false;
    var form = this;
    
    opts = opts || {};
    
    var validateFunc = opts["validate"] || function() { return true; }
    var submitFunc = opts["submit"] || function() { return true; }

    var state = {
        form: function() { return form; },
        
        authenticityToken : function() {
            return opts["authenticityToken"]
        },

        validatePath : function() {
            return opts["validatePath"]
        },
        
        submitPath: function() {
            return opts["submitPath"] || form.attr("action")
        },
        
        validateMethod : function() {
            return opts["validateMethod"] || "post"
        },
                
        submitMethod : function() {
            return opts["submitMethod"] || "post"
        }        

    }
    
    function hideAll() {
      $(".quickform_section").children().hide();          
    }

    function hideSection(i)  {
      $($(".quickform_section")[i]).children().hide();          
    }

    function showSection(i) {
      $($(".quickform_section")[i]).children().show();
    }

    function sectionCount() {
      return $(".quickform_section").length
    }
    
    function currentSection() {
        return $(allSections[currentSectionIndex]);
    }
    
    function updateButtons() {
        $(opts["previous"]).attr("disabled", currentSectionIndex == 0 )
        $(opts["next"]).attr("disabled", 
                              currentSectionIndex >= (allSections.length-1) )
    }
    

    
    function moveTo(target) {
      if( isAnimating || 
          target == currentSectionIndex ||
          target >= sectionCount() ||
          target < 0 ) { 
          return; 
      }

      isAnimating = true
      var lastSection = currentSectionIndex;
      showSection(target);
      form.animate({
        scrollLeft : target*sectionWidth
      }, function() {
        hideSection(lastSection)
        isAnimating = false; 
        currentSectionIndex = target;
        updateButtons();
        var selector = (currentSectionIndex > lastSection ) 
            ? "input:first" : "input:last";
        currentSection().find(selector).focus();

      })
  
    }
    
    function next() {
      moveTo(currentSectionIndex+1)
    }

    function previous() {
      moveTo(currentSectionIndex-1)
    }
    
    this.children().wrapAll("<div class='quickform_scrollarea'></div>")
    var scrollArea = this.find(".quickform_scrollarea")
    
    this.find(".quickform_previous").click(function() {
        previous();
        return false;
    })
    this.bind( "nextSection", next );
    this.bind( "previousSection", previous);
    
    this.submit(function(){
        if(currentSectionIndex >= (allSections.length-1)) {
            if( submitFunc(self) != false) {
                return jQuery.quickform.submit.call(state, currentSection());
            } else {
                return false;
            }
        } else {
            if( jQuery.quickform.validateSection.call( state, 
                                                       currentSection() ) ) {
                next();                
            }
            return false;            
        }
    })

    if( jQuery.browser.msie ) {
        form.find("input").keydown(function(e){
            if(e.keyCode == 13 ) {
                jQuery(form).submit();
            }
        })
    }
    
    var allSections = this.find(".quickform_section");
    if( allSections.length < 2 ) {
        return;
    }
    var firstSection = $(allSections[0]);
    allSections.css("float", "left");
    this.css("overflow-x", "hidden")
    sectionWidth = firstSection.width();
    sectionHeight = firstSection.height();
    allSections.width(sectionWidth).height(sectionHeight);
    var containerWidth = allSections.length * sectionWidth;
    scrollArea.width(containerWidth).height(sectionHeight);
    this.width(sectionWidth).height(sectionHeight+50);
    this.css("overflow-y", "hidden" );
    hideAll();
    showSection(0);
    updateButtons();
}


jQuery.quickform = {
    options : {
    },
    
    config : {
        
    },
    assertResponseObject : function(response) {
        if(typeof(response)=='string') {
            if(response[0]!='(') {
                response = "("+response+")";
            }
            response = eval(response);
        }
        return response;
    },
    
    next : function(form) {
        $(form).trigger("nextSection");
    },

    previous : function(form) {
        $(form).trigger("previousSection");
    },
    
    fieldFailedValidation : function(id, msg) {
       var field = $("#"+id)
       field.addClass("quickform_field_with_error")      
       var correctedHeight = field.parent().height()+5;
       
       field.parent().animate( { height : correctedHeight })
       field
          .after( "<div class='quickform_error_message'>"+
                  msg+ 
                  "</div>")
    },

    removeValidationMessages : function() {
       $(".quickform_error_message").remove();
  	   var field =  $(".quickform_field_with_error");
	   field.parent().css("height", field.parent().height() - 5);
       field.removeClass("quickform_field_with_error");
    },
    
    submit: function() {
       jQuery.quickform.removeValidationMessages();        
        var data = $.param( $(this.form()).serializeArray()) + 
                            '&authenticity_token=' + 
                            encodeURIComponent(this.authenticityToken());
        var form = this.form();
        $.ajax({
            data: data, 
            dataType:'script',
              success: function(res) {
                  res = jQuery.quickform.assertResponseObject(res);
                  var errorCount = 0
                  jQuery.each(res["errors"], function(k,v) {
                      errorCount++;
                      jQuery.quickform.fieldFailedValidation(
                          k,v);
                  })
                  if(errorCount == 0 ) {
                      res["onsuccess"]();
                  }
              },
            type:this.submitMethod(), 
            url:this.submitPath()
        })
        return false;
    },
    
    validateSection : function(currentSection) {
       jQuery.quickform.removeValidationMessages();
       var validationFields = []
       var form = this.form();
       
       currentSection.find("input").each(function(){
          var inputField = $(this)
          validationFields.push(inputField.attr("id"))
       })

       $.ajax({
          data:$.param($(this.form()).serializeArray()) + 
                '&authenticity_token=' + 
                encodeURIComponent(this.authenticityToken()), 
          dataType:'script', 
          success: function(res) {
              res = jQuery.quickform.assertResponseObject(res);
              var errorCount = 0
              jQuery.each(res["errors"], function(k,v) {
                  if( jQuery.inArray(k, validationFields) != -1 ) {
                      errorCount++;
                      jQuery.quickform.fieldFailedValidation(
                          k,v);
                  }
              })
              if(errorCount == 0 ) {
                  jQuery.quickform.next(form)
              }
          },
          type:this.validateMethod(), 
          url:this.validatePath() });
    }    
}
