/*
 * jQuery wizard plug-in 0.9.2
 *
 *
 * Copyright (c) 2009 Jan Sundman (jan.sundman[at]aland.net)
 *
 * Licensed under the MIT licens:
 *   http://www.opensource.org/licenses/mit-license.php
 *   
 *
 * Changelog:
 * 
 * version 0.9.2 
 * - A check was added to see if there are multiple links on one step. In the
 * case there are we assume they are radio buttons or checkboxes. Only the
 * one that is checked is considered a valid link. This fixes a bug where links
 * in the form of radio buttons do not work. Credits to adnanshareef for 
 * reporting the bug.  
 * 
 * - Added initial functionality for doing server-side validation 
 * 
 * version 0.9.1 
 * -------------
 * - Addition of afterNext and afterBack callbacks, can be used to do stuff after
 * the rendering of a step has been completed
 * 
 * version 0.9.0 
 * -------------
 * - Initial release
 *
 */
   
(function($){
	

  $.fn.formwizard = function(wizardSettings, validationSettings, formOptions){
	
	/**
	 * Creates a wizard of all matched elements
	 *
	 * @constructor
	 * @name $.formwizard
	 * @param Hash wizardSettings A set of key/value pairs to set as configuration properties for the wizard plugin.
	 * @param Hash validationSettings A set of key/value pairs to set as configuration properties for the validation plugin.
	 * @param Hash formOptions A set of key/value pairs to set as configuration properties for the form plugin.
	 */	  	
	
	var settings = $.extend({
		historyEnabled	: false,
		validationEnabled : false,
		formPluginEnabled : false,
		linkClass	: ".link",
		submitStepClass : ".submit_step",
		back : ":reset",
		next : ":submit",
		textSubmit : 'Submit',
		textNext : 'Next',
		textBack : 'Back',
		afterNext: undefined,
		afterBack: undefined,
		serverSideValidationUrls : undefined
	}, wizardSettings);

	var formOptionsSuccess = (formOptions)?formOptions.success:undefined;
	var formSettings = $.extend(formOptions,{
		success	: function(data){ 
			if(formOptions && formOptions.resetForm || !formOptions){
				navigate(0);
				if(settings.historyEnabled){
					$.historyLoad(0);
				}else{
					renderStep();
				}
			}
			if(formOptionsSuccess){
				formOptionsSuccess(data);
			}else{
				alert("success");
			}
		}
	});
	
	var currentStep = 0;	
	var form = $(this);
	var steps = $(this).find(".step");
	var backButton = $(this).find(settings.back);
	var nextButton = $(this).find(settings.next);
	var activatedSteps = new Array();
	var isLastStep = false;	
	
	/** 
	 * Navigation event callbacks 
	 */
	nextButton.click(function(){

		if(settings.validationEnabled && !form.valid()){
			return false;
		}

		if(isLastStep){
			if(settings.formPluginEnabled){
				form.ajaxSubmit(formSettings);
				return false;
			}
			form.submit();
			return false;
		}

		// Doing server side validation for the steps
		if(settings.serverSideValidationUrls){
		  var url = "";
		  var errorCallback = undefined;
		  $.each(settings.serverSideValidationUrls, function(){
		     if(this.validation.step == currentStep){ 
			url = this.validation.url;
			errorCallback = this.validation.error;
		     }
		  });

		  if(url != ""){
			form.ajaxSubmit({url : url, 
				success: function(){continueToNextStep();},
				error: function(){errorCallback();}
			 });
			alert("server side done");
			return false;
		  }
		}
		continueToNextStep();
		return false;
	});

	backButton.click(function(){
		if(settings.historyEnabled && activatedSteps.length > 0){
			history.back();
		}else if(activatedSteps.length > 0){
			handleHistory(activatedSteps[activatedSteps.length - 1]);
		}
		if(settings.afterBack)	
			settings.afterBack();
		return false;
	});

	/**
	 * Continues to the next step in the wizard
	 */
	function continueToNextStep(){
		navigate(currentStep);
		renderStep();

		if(settings.historyEnabled){
			$.historyLoad(currentStep);
		}

		if(settings.afterNext)
			settings.afterNext();
	}

    /**
     * Renders the current step and disables the input fields in other steps
     *
     * @name renderStep
     * @type undefined
     */
	function renderStep(){
		backButton.removeAttr("disabled");
		nextButton.val(settings.textNext);

		steps.hide()
			.find(":input")
			.attr("disabled","disabled")
			.end()
			.eq(currentStep)
			.fadeIn()
			.find(":input")
			.removeAttr("disabled");

		if(isLastStep){
			for(var i = 0; i < activatedSteps.length; i++){
				steps.eq(activatedSteps[i]).find(":input").removeAttr("disabled");
			}
			nextButton.val(settings.textSubmit);
		}else if(currentStep == 0){
			backButton.attr("disabled","disabled");
		}
	}

    /**
     * Checks if the step is the last step in a wizard route
     *
     * @name checkIflastStep
     * @type undefined
     * @param Number step The step to check.
     */			
	function checkIflastStep(step){
		var link = getLink(step);

		isLastStep = false;
		
		if((("." + link) == settings.submitStepClass) || (link == undefined && (step*1) == steps.length - 1)){
			isLastStep = true;
		}
	}

    /**
     * Decides and sets the current step in the wizard 
     *
     * @name navigate
     * @type undefined
     * @param Number step The step to navigate from.
     */
	function navigate(step){
		var link = getLink(step);

		if(link){					
			var navigationTarget = steps.index($("#" + link));	
			if(navigationTarget == -1){
				return;
			}else{
				currentStep = navigationTarget;	
			}
			checkIflastStep(step);					
		}else if(link == undefined && !isLastStep){	
			currentStep++;
			checkIflastStep(currentStep);
		}
	}
	
    /**
     * Finds the valid link for the step (if there is one)
     *
     * @name getLink
     * @type String
     * @param Number step The step to search for valid links
     */
	function getLink(step){
		var link = undefined;
		var links = steps.eq((step*1)).find(settings.linkClass);

		if(links != undefined && links.length == 1){
			link = links.val();
		}else if(links != undefined && links.length > 1){ 
			// assume that the link is a radio button or checkbox
			link = steps.eq((step*1)).find(settings.linkClass + ":checked").val();
		}

		return link;
	}

    /**
     * Handles back navigation (and browser back and forward buttons if history is enabled)
     *
     * @name handleHistory
     * @type undefined
     * @param String hash The hash used in the browser history
     */
	function handleHistory(hash){
		if(!hash){
			hash = 0;
		}
		if(activatedSteps[activatedSteps.length - 2] == hash){
			activatedSteps.pop();	
		}else {
			activatedSteps.push(hash);
		}
		currentStep = hash;
		checkIflastStep(hash);
		renderStep();
	}
	
    /**
     * Initialization
     */

	if(settings.historyEnabled && $.historyInit  == undefined){
		settings.historyEnabled = false;
		alert("the history plugin needs to be included");
	}else if(settings.historyEnabled){
		$.historyInit(handleHistory);
	}
	
	if(settings.validationEnabled && jQuery().validate  == undefined){
		settings.validationEnabled = false;
		alert("the validation plugin needs to be included");
	}else if(settings.validationEnabled){
		form.validate(validationSettings);
	}
	
	if(settings.formPluginEnabled && jQuery().ajaxSubmit == undefined){
		settings.formPluginEnabled = false;
		alert("the form plugin needs to be included");
	}
	
	
	renderStep();
	backButton.val(settings.textBack);
    return $(this);
  };
})(jQuery);
