/*
 * jQuery wizard plug-in 1.0.1
 *
 *
 * 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 1.0.1
 * -------------
 * - fixed so that the validation plugin handles all validation using form.valid(). 
 * - fixed so that it is possible set focus to a  in the form after the wizard is rendered
 * 
 * version 1.0.0
 * -------------
 * - fixed textarea validation
 * 
 * version 0.9.9
 * -------------
 * - Added a way to by-pass the reset functionality so that the $.fn.formwizard is not
 * 	 redefined. This is done by specifying 
 *
 *				callable : false 
 *
 *   in the wizard settings when initializing all wizards on a page. This means that the forms
 *	 cannot be reset but the initialization code will be run for all wizards. 
 * 
 * version 0.9.8
 * -------------
 * - Reworked the serverside validation part. One can specify the usual options used by the 
 *   form plugin for each step validation. To do server side validation for steps 1 and 4 the 
 *	 serverSideValidationUrls option for the wizard should be defined as in the examples below. 
 *   The  name "1" denotes that validation for step 1 should use that s value as options
 *   when calling the validation service. Only the input s on the current step will be sent
 *   (except on submit steps).
 *		
 *   If your validation service returns HTTP status 200 together with data specifying the status of the validation - use 
 *	 the success callback to check the data and take actions depending on it.
 *	 NOTE: The success callback should return true if the s validated ok and false otherwise. 
 *   The variable 'validated' in the example below would be set to true if the page validated ok
 *		
 *
 *		serverSideValidationUrls : {"1" : {	"success" : function(data, textStatus){...do stuff...; return validated;}, 
 *																				"url" : "urltovalidationservice1.php" },
 *																"4" : {	"success" : function(data, textStatus){...do stuff...; return validated;}, 
 *																				"url" : "urltovalidationservice2.php" },
 *														    }
 *
 *		If your service returns HTTP status >200 together with data specifying the status of the validation - use 
 *    the error callback and take actions depending on the data returned.
 *
 *	  serverSideValidationUrls : {"1" : {	"error" : function(XMLHttpRequest, textStatus, errorThrown){alert("check for errors in the data, HTTP status >200");}, 
 *																				"url" : "urltovalidationservice1.php" },
 *																"4" : {	"error" : function(XMLHttpRequest, textStatus, errorThrown){alert("check for errors in the data, HTTP status >200");}, 
 *																				"url" : "urltovalidationservice2.php" },
 *															 }
 *
 * 
 * version 0.9.7
 * -------------
 * - Added a way to reset the wizard by calling $("#theform").formwizard("reset");
 * - The afterBack and afterNext callbacks now get some information about the plugin
 * 
 * version 0.9.6
 * -------------
 * - Fix for enabling select validation
 * 
 * version 0.9.5
 * -------------
 * - Fix for enabling optional validation
 *
 * version 0.9.4
 * -------------
 * - Performance fixes for validation of the steps
 * - Performance fixes for rendering of the steps
 * - Introduces a need for input s in the wizard to be disabled in the html
 *
 * version 0.9.3
 * ------------- 
 * - Fixed the continueToNextStep and backButton.click callback to handle navigation correctly when the 
 * history plugin is not used
 * 
 * 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 : 'View Results',
		textNext : 'Next',
		textBack : 'Back',
		afterNext: undefined,
		afterBack: undefined,
		serverSideValidationUrls : undefined,
		callable : true
	}, wizardSettings);
	
	var globalProgressStep = undefined;
	

	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 previousStep = undefined;	
	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;	
	
	backButton.attr("class","back");
	nextButton.attr("class","next");

	/** 
	 * Navigation event callbacks 
	 */
	nextButton.click(function(){	

		//alert("cs: " + currentStep);
 		var prevProgressStep = currentStep;
		prevProgressStep = prevProgressStep + 1;
		//alert("pps: " + prevProgressStep);
		var currProgressStep = prevProgressStep + 1;
		//alert("cps: " + currProgressStep);
		
		if(settings.validationEnabled){
			if(!form.valid()){
				form.validate().focusInvalid();
				return false;
			}else{
				
				if (!currentStep > 0){
					$("#complete").attr("class","s2");
				}else{
					$("#complete").attr("class","s" + currProgressStep);
				}
			}
		}
		if(isLastStep){
			if(settings.formPluginEnabled){
				//alert("ajax submit");
				//alert("ajax");
				form.ajaxSubmit(formSettings);
				return false;
			}
			//alert("form submit");
			form.submit();
			return false;
		}else{
				
		}

		// Doing server side validation for the steps
		if(settings.serverSideValidationUrls){
		  var options = settings.serverSideValidationUrls[currentStep];
			if(options != undefined){ 
			  var success = options.success;
				$.extend(options,{success: function(data, statusText){
						if((success != undefined && success(data, statusText)) || (success == undefined)){
							continueToNextStep();
						}
					}})
				form.ajaxSubmit(options);
				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 - 2]);
		}
		if(settings.afterBack)	
			settings.afterBack({"currentStep" : currentStep, 
													"previousStep" : previousStep,
													"isLastStep" : isLastStep, 
													"activatedSteps" : activatedSteps});
		
		var progBackStep = parseInt(currentStep) + 1;
		//alert(progBackStep);
		$("#complete").attr("class","s" + progBackStep);
		return false;
	});

	/**
	 * Continues to the next step in the wizard
	 */
	function continueToNextStep(){
		navigate(currentStep);
		
		renderStep();

		if(settings.historyEnabled){
			$.historyLoad(currentStep);
		}else{
			handleHistory(currentStep);
		}

		if(settings.afterNext)
			settings.afterNext({"currentStep" : currentStep, 
													"previousStep" : previousStep,
													"isLastStep" : isLastStep, 
													"activatedSteps" : activatedSteps});
	}
	
	// Perform calculations
	function calcInput(currentStep) {
		
		if (currentStep == 1){
			// ######### step 2 ######## //
			
			// Individuals specified for each classification
			var e1 = parseInt($('#fp_people').val());
			var e2 = parseInt($('#bh_people').val());
			var e3 = parseInt($('#br_people').val());			
			// Days specified for each classification
			var d1 = parseInt($('#fp_days').val());
			var d2 = parseInt($('#bh_days').val());
			var d3 = parseInt($('#br_days').val());
			// Salary specified for each classification
			var s1 = parseInt($('#fp_salary').val());		
			var s2 = parseInt($('#bh_salary').val());	
			var s3 = parseInt($('#br_salary').val());
			// Additional salary calculation
			var s1_calc = s1/250;
			var s2_calc = s2/250;
			var s3_calc = s3/250;
			
			// Total cost for each section
			var total_fp = e1 * d1 * s1_calc;
			var total_bh = e2 * d2 * s2_calc;
			var total_br = e3 * d3 * s3_calc;
			// Total cost combined
			var total_all = parseInt(total_fp) + parseInt(total_bh) + parseInt(total_br);
			// Total days
			var total_d = d1 + d2 + d3
			
			$("#calc-days").html(total_d);
			$("#hf-calc-days").val(total_d);
			
			$("#calc-estannualcost").html(formatCurrency(roundNumber(total_all,0)));
			$("#hf-calc-estannualcost").val(total_all);
		}else if (currentStep == 2){
			
			// ######### step 3 ######## //
			var ac = $('#hf-calc-estannualcost').val();
			var rf = parseInt($('#reforcast').val());
			var ef = parseInt($('#reforcasteffort').val()) / 100;
			
			var ecf = ac * rf * ef;
			$("#calc-forcasting").html(formatCurrency(roundNumber(ecf,0)));
			$("#hf-calc-forcasting").val(ecf);
			
			var ecpf = parseFloat(ac) + parseFloat(ecf);
			//alert(ecpf + "=" + ac + " " + ecf);
			$("#calc-planning").html(formatCurrency(roundNumber(ecpf,0)));
			$("#hf-calc-planning").val(ecpf);
			
			var lt = ecpf * 5;
			$("#calc-longterm").html(formatCurrency(roundNumber(lt,0)));
			$("#hf-calc-longterm").val(lt);
		}else if (currentStep == 3){
			// step 4

		}
	}

    /**
     * Renders the current step and disables the input s in other steps
     *
     * @name renderStep
     * @type undefined
     */
	function renderStep(){
		//$('#appform').fadeIn();
		$('#form-handler-response').hide();
		nextButton.attr("class","next");
		calcInput(currentStep);
		backButton.removeAttr("disabled");
		nextButton.val(settings.textNext);

			if(previousStep != undefined){
				steps.eq(previousStep).hide()
					.find(":input")
					.attr("disabled","disabled");
			}
			
			var currProgressStep = 0;
			currProgressStep = parseInt(currentStep) + 1;
			//alert(currProgressStep);
			
			if (currentStep > 0){
				//alert("bing!");
				$("#complete").attr("class","s" + currProgressStep);
				steps.eq(currentStep)
				.fadeIn('slow')
				.find(":input")
				.removeAttr("disabled");
				
			}else{
				$("#complete").attr("class","s1");
				steps.eq(currentStep)
				.show()
				.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);
			nextButton.attr("class","submit-results");
		}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{
				previousStep = currentStep;
				currentStep = navigationTarget;	
			}
			checkIflastStep(step);			
		}else if(link == undefined && !isLastStep){	
			previousStep = currentStep;
			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;
	}
	
	// Parse number as currency
	function formatCurrency(strValue)
	{
		strValue = strValue.toString().replace(/\$|\,/g,'');
		dblValue = parseFloat(strValue);
	 
		blnSign = (dblValue == (dblValue = Math.abs(dblValue)));
		dblValue = Math.floor(dblValue*100+0.50000000001);
		intCents = dblValue%100;
		strCents = intCents.toString();
		dblValue = Math.floor(dblValue/100).toString();
		if(intCents<10)
			strCents = "0" + strCents;
		for (var i = 0; i < Math.floor((dblValue.length-(1+i))/3); i++)
			dblValue = dblValue.substring(0,dblValue.length-(4*i+3))+','+
			dblValue.substring(dblValue.length-(4*i+3));
		return (((blnSign)?'':'-') + '$' + dblValue + '.' + strCents);
	}
	
	// Round decimals
	function roundNumber(num, dec) {
		var result = Math.round(num*Math.pow(10,dec))/Math.pow(10,dec);
		return result;
	}

    /**
     * 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){
			var elem = activatedSteps.pop();	
		}else {
			activatedSteps.push(hash);
		}
		previousStep = currentStep;
		currentStep = hash;
		checkIflastStep(hash);
		renderStep();
	}
	
	   /**
     * Resets the wizard to its original state
     *
     * @name resetWizard
     * @type undefined
     */
	function resetWizard(){
		form.resetForm();
		currentStep = 0;
		for(var i = 0; i < activatedSteps.length; i++){
			steps.eq(activatedSteps[i]).hide().find(":input").attr("disabled","disabled");
		}
		previousStep = undefined;	
		activatedSteps = new Array();
		isLastStep = false;	
		if(settings.historyEnabled){
			$.historyLoad(0);
		}else{
			renderStep();
		}
	}
	
    /**
     * Initialization
     */
	
	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");
	}

	steps.hide();
	
	if(settings.historyEnabled && $.historyInit  == undefined){
		settings.historyEnabled = false;
		alert("the history plugin needs to be included");
	}else if(settings.historyEnabled){
		$.historyInit(handleHistory);
	}else{
		handleHistory(0);
  }
	
	backButton.val(settings.textBack);
	
	if(settings.callable == true){
		// provides a way of calling internal methods (note that $.fn.formwizard is redefined)
		$.fn.formwizard = function(event){
			switch(event){
				case 'reset':	resetWizard(); break;
			}
			return $(this);
		};
  }
  return $(this);
  };
})(jQuery);
