var dateFormat = "dd.MM.yyyy";
var isoFormatRegexPattern =  /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}).*Z$/g;
var timeRegexPattern = /^(\d*):(\d*)/g;
isoFormatRegexPattern.compile(isoFormatRegexPattern);
timeRegexPattern.compile(timeRegexPattern);

function ieCacheKiller() {
	return (new Date).getTime();
}

$.postJSON = function(url, data, callback) {
    return jQuery.ajax({
        'type': 'POST',
        'url': url,
        'data': data,
        'dataType': 'json',
        'success': callback
    });
};

var speed = "normal";

function toggleListing(listingId) {
//	alert("#" + listingId + " a.display_toggle_button");
	if ($("#" + listingId + " form.search_form").is(':visible')) {
		$("#" + listingId + " form.search_form").slideUp(speed); 
		$("#" + listingId + " .listing").slideDown(speed);
		$("#" + listingId + " a.display_toggle_button").button("option" , "label", modifySearchLabel);
	} else {
		$("#" + listingId + " form.search_form").slideDown(speed); 
		$("#" + listingId + " .listing").slideUp(speed);
		$("#" + listingId + " a.display_toggle_button").button("option" , "label", displayListLabel);
	}
}

function toggleCollapsibleParagraph(paragraphID) {
	if ($("#" + paragraphID).hasClass("open")) {
		$("#" + paragraphID + " .content").slideUp(speed);
		$("#" + paragraphID).removeClass("open");
		$("#" + paragraphID).addClass("closed");
	} else {
		$("#" + paragraphID + " .content").slideDown(speed);
		$("#" + paragraphID).removeClass("closed");
		$("#" + paragraphID).addClass("open");
	}
}

function formatPrice(inputElement) {
	if (inputElement) {
		var unformatted = $(inputElement).val();
		if (isNaN(unformatted)) {
			// no number -> let form validation take care of it
		} else {
			unformatted = new Number(unformatted);
//			var formatted = unformatted.toFixed(2);
			$(inputElement).val(unformatted.toFixed(2));
		}
	}
}
/* dialog *****************************************************************************************/
function Dialog(id) {
	var _that = this;
	this.id = id;
	this.steps = new Array();
	this.stepNavItems = $("#" + this.id + " ol.steps li");

	// init the steps
	$("#" + this.id + " div.step").each(function(index) {
		var newStep = new DialogStep(_that, this, index, $(this).attr("id"));
		_that.steps.push(newStep);
	});
	
	// init the "on changes" handles on the form element
	$("#" + this.id + " .data_field").change(function() {
		if (_that.dataObject) {
			var inputName = $(this).attr("name");
			if (inputName) {
				var type = $(this).attr("type").toLowerCase();
				if (type && (type == "checkbox" || type == "radio")) {
					if ($(this).is(":checked")) {
						_that.dataObject[inputName] = $(this).val();
					} else {
						if ($(this).val() == "true") {
							_that.dataObject[inputName] = false;
						} else if ($(this).val() == "false") {
							_that.dataObject[inputName] = true;
						} else {
							delete _that.dataObject[inputName];
						}
					}
/*				} else if (type && type == "radio") {
					var checkedRadioItem = $("#" + this.id + " input[name='" + inputName + "']:checked");
					if ($(checkedRadioItem).size() == 1) {
						_that.dataObject[inputName] = $(checkedRadioItem).val();
					} else {
						delete _that.dataObject[inputName];
					}*/
				} else {
					_that.dataObject[inputName] = $(this).val();
				}
			}
		}
	});

	this.updateDataObject = function() {
		alert("updating data object...");
		$("#" + this.id + " .data_field").each(function() {
			_that.updateDataObjectWithInputElement(this);
		});
		$("#" + this.id + " .date_field").each(function() {
			_that.dataObject[$(this).attr("name") + "JSON"] = $(this).datepicker("getDate");
		});
		alert("data object: " + JSON.stringify(this.dataObject));
	}
	
	this.updateDataObjectWithInputElement = function(dataElement) {
		if (_that.dataObject) {
			var inputName = $(dataElement).attr("name");
			if (inputName) {
				var type = $(dataElement).attr("type").toLowerCase();
				if (type && (type == "checkbox" || type == "radio")) {
					if ($(dataElement).is(":checked")) {
						var value = $(dataElement).val();
						value = this.convertValueOfInputElement(dataElement, value);
						_that.dataObject[inputName] = value;
					} else {
						if ($(dataElement).val() == "true") {
							_that.dataObject[inputName] = false;
						} else if ($(dataElement).val() == "false") {
							_that.dataObject[inputName] = true;
						} else {
							delete _that.dataObject[inputName];
						}
					}
				} else {
					var value = $(dataElement).val();
					value = this.convertValueOfInputElement(dataElement, value);
					if (value == null) {
						$(dataElement).val("");
					}
					_that.dataObject[inputName] = value;
				}
			}
		}
	}
	
	this.updateDisplay = function() {
		// clear all input elements
		$("#" + this.id + " form").each(function() {
			$(this).get(0).reset();
		});
		
		// loop through the attributes of the data object
		for (var index in this.dataObject) {
			if ($("#" + this.id + " .data_field[name='" + index + "']").size() > 0) {
				this.updateInputElementDisplay(index);
			}
		}
	}
	
	this.updateInputElementDisplay = function(key) {
		if (this.dataObject) {
			var _name = key;
			var _value;
			if (this.dataObject[key] != null) {
				_value = "" + this.dataObject[key];
			} else {
				_value = "";
			}
			// get the input element
			$("#" + this.id + " .data_field[name='" + key + "']").each(function() {
				// first, check if it's an input element
				if (this.tagName.toLowerCase() == "input" || this.tagName.toLowerCase() == "textarea" || this.tagName.toLowerCase() == "select") {
					var type = $(this).attr("type");
					if (type && type.toLowerCase() == "checkbox" || type.toLowerCase() == "radio") {
						if (_value == $(this).val()) {
							$(this).attr("checked", "checked");
						} else {
							$(this).removeAttr("checked");
						}
					} else {
						$(this).val(_value);
					}
				} else {
					// TODO: what do we do here?
				}
			});
		}
	}
	
	this.convertValueOfInputElement = function(dataElement, value) {
		if (dataElement && value) {
			if ($(dataElement).hasClass("integer")) {
				return parseInt(value);
			} else if ($(dataElement).hasClass("float")) {
				return parseFloat(value);
			} else if ($(dataElement).hasClass("boolean")) {
				if (value == "true") {
					return true;
				} else if (value == "false") {
					return false;
				} else {
					return value;
				}
			} else {
				return value;
			}
		}
	}
	
	this.toString = function() {
		return "Dialog object \"" + this.id + "\" with " + this.steps.length + " steps";
	}
	
	this.showStep = function(stepNumber, subStepNumber, validateCurrentStep) {
		// remove all error messages
		this.resetErrorMessages();
	
		// if requested, validate current step before switching steps
		if (validateCurrentStep) {
			this.errorMessages = this.validateCurrentStep();
			if (this.errorMessages && this.errorMessages.noOfErrors > 0) {
				this.displayErrorMessages();
				return;
			}
		}
		
		// loop through the steps
		for (var i=0; i<this.steps.length; i++) {
			if (stepNumber == i+1) {
//				$("#" + this.steps[i].id).show();
//				$("#" + this.id + " .body div.step").eq(i).show();
				$(this.steps[i].element).show();
				$(this.stepNavItems[i]).addClass("active");
				$(".substep", this.steps[i].element).each(function(index) {
					if (index + 1 == subStepNumber) {
						if ($(this).is(":visible")) {
							// don't need to do anything
						} else {
							$(this).show();
						}
					} else {
						if ($(this).is(":visible")) {
							$(this).hide();
						} else {
							// don't need to do anything
						}
					}
				});
			} else {
//				$("#" + this.steps[i].id).hide();
//				$("#" + this.id + " .body div.step").eq(i).hide();
				$(this.steps[i].element).hide();
				$(this.stepNavItems[i]).removeClass("active");
			}
		}
		
		// save the step numbers
		this.stepNumber = stepNumber;
		this.subStepNumber = subStepNumber;
	}
	
	this.validateCurrentStep = function() {
		if (this.stepNumber && this.subStepNumber) {
//			alert("steps: "+this.steps);
			var step = this.steps[this.stepNumber-1];
//			alert("step: "+step);
//			alert("substeps: "+step.subSteps);
			var subPanel = this.steps[this.stepNumber-1].subSteps[this.subStepNumber-1];
			if (subPanel) {
				return subPanel.validate();
			} else {
//				alert("Error no step found to validate for: "+ this.stepNumber + "." + this.subStepNumber);
			}
		}
	}
	
	this.displayErrorMessages = function() {
		if (this.errorMessages.noOfErrors > 0) {
			var step = this.steps[this.stepNumber-1].element;
			// main error message at the top of the dialog step
			if ($(".main_error_message", step).size() > 0) {
				$(".main_error_message .message", formPart).text(messages.errors_have_occured_verify_input);
			} else {
				$(step).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.errors_have_occured_verify_input + "</div></div>");
			}
			
			// individual input element error messages
			var errorKeys = new Array();
			for (var index in this.errorMessages) {
				errorKeys.push(index);
			}
			for (var i=1; i<errorKeys.length; i++) {
				$("*[name='"+errorKeys[i]+"']", step).each(function() {
					var id = $(this).attr("id");
					if (id && id.length > 0) {
						$("label[for='" + id + "']", step).addClass("error_label");
					}
				});
				$(".error_" + errorKeys[i], step).each(function() {
					$(this).text(messages[_that.errorMessages[errorKeys[i]]]);
					$(this).show();
				});
			}
			// focus on first error input element
			$("*[name='"+errorKeys[1]+"']:eq(0)", step).focus();
			
			// flash the Background
			$("#" + this.id + " div.body").addClass("error_on_dialog");
			var t = setTimeout("$(\"#" + _that.id + " div.body\").removeClass(\"error_on_dialog\")",100);
		}
	}
	
	this.resetErrorMessages = function() {
		$("#" + this.id + " .main_error_message").remove();
		$("#" + this.id + " label.error_label").removeClass("error_label");
		$("#" + this.id + " .error_message").hide();
	}
	
	this.save = function() {
		// remove all error messages
		this.resetErrorMessages();

		// validate
		this.errorMessages = this.validateCurrentStep();
		if (this.errorMessages && this.errorMessages.noOfErrors > 0) {
			alert("error!");
			this.displayErrorMessages();
			return;
		} else {
			var data = this.dataObject;
//			alert("data: " + JSON.stringify(data));
			// set the command
			// TODO: make this variable
			var command = "saveRegatta";
			// post to server
			$.postJSON(
				sailCalPageURL,
				{
					"data": JSON.stringify(data),
					"command": command,
					"mgnlCK": ieCacheKiller()
				},
				function(data, textStatus) {
					_that.saveCallback(data, textStatus);
				}
			);
		}
	}
	
	this.saveCallback = function(data, textStatus) {
		if (data.errors) {
			alert("an error has occured when trying to save the regatta: " + data.errors);
		} else {
//			alert("regatta saved!");
			$("#" + _that.id).dialog('close');			
		}
	}
}

function DialogStep(dialog, element, index, id) {
	var _that = this;
	this.dialog = dialog;
	this.element = element;
	this.index = index;
	this.id = id;
	this.subSteps = new Array();

	// init the substeps
	$(".substep", element).each(function(index) {
		var newSubStep = new DialogSubStep(_that, this, index, $(this).attr("id"));
		_that.subSteps.push(newSubStep);
	});
}

function DialogSubStep(step, element, index, id) {
	this.step = step;
	this.index = index;
	this.id = id;
	this.inheritFrom = DialogStep;
	this.inheritFrom(step.dialog, element, index, id);

	// overwrite by superclass if you need additional validations
	this.validate = function() {
		var errorMessages = new Array();
		// make sure all inpput elements with the class "mandatory" have a value
//		alert("validating step " + (this.step.index+1) + "." + (this.index+1));
		errorMessages.noOfErrors = 0;
		$("*.validate", this.element).each(function() {
		
//		$("input.validate_not_empty"
			var value = $(this).val();
			if (!value || value.length == 0) {
				var name = $(this).attr("name");
//				alert(name + " is mandatory!");
				errorMessages[name] = "error_mandatory";
				errorMessages.noOfErrors++;
			}
		});
		if (this.extraValidate) {
			this.extraValidate(errorMessages);
		}
		return errorMessages;
	}
}

/* regatta registration ***************************************************************************/
var crewMember;
var sailCalPageURL = contextPath + "/.magnolia/pages/sailingCalendar.html";

function handleRegattaRegistrationSubsteps1(element) {
	var value = $(element).val();
	value = value.substring(value.length-1, value.length);
	showStep(0, parseInt(value));
}

//searchLicense('regatta-registration-dialog_step_1-2', 'swiss_sailing_number', 'registrator');
function searchLicense(panel, type, licenseType) {
	var errors = new Array();
	var formPart = $("#" + panel);
	var swissSailingNumber;
	var lastname;
	var firstname;
	var zip;
	var clubUUID;
	var _panel = panel;
	var _type = type;
	var _licenseType = licenseType;
	if (type == "swiss_sailing_number") {
		if (!(swissSailingNumber = $("input[name='swissSailingNumber']", formPart).val())) {
			errors.push("swissSailingNumber");
		}
		if (!(lastname = $("input[name='lastname']", formPart).val())) {
			errors.push("lastname");
		}
		if (!(zip = $("input[name='zip']", formPart).val())) {
			errors.push("zip");
		}
	} else if (type == "swiss_sailing_no_number") {
		if (!(lastname = $("input[name='lastname']", formPart).val())) {
			errors.push("lastname");
		}
		if (!(firstname = $("input[name='firstname']", formPart).val())) {
			errors.push("firstname");
		}
		if (!(zip = $("input[name='zip']", formPart).val())) {
			errors.push("zip");
		}
		if (!(clubUUID = $("select[name='clubUUID']", formPart).val())) {
			errors.push("clubUUID");
		}
	} else {
		// TODO: display error message
		return;
	}
	if (errors.length > 0) {
		// display error message
		if ($(".main_error_message", formPart).size() > 0) {
			$(".main_error_message .message", formPart).text(messages.error_mandatory_fields);
		} else {
			$(formPart).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_mandatory_fields + "</div></div>");
		}
		// set focus on the first field
		$("input[name='" + errors[0] + "']", formPart).focus();
	} else {
		// load license from server
//		jQuery.getJSON(
		jQuery.postJSON(
			sailCalPageURL,
			{
				"swissSailingNumber": swissSailingNumber,
				"lastname": lastname,
				"firstname": firstname,
				"zip": zip,
				"clubUUID": clubUUID,
				"command": "searchSwissSailingMember",
				"mgnlCK": ieCacheKiller()
			}, 
			function(data, textStatus) {
				if (_licenseType == 'registrator') {
					searchRegistrationLicenseCallback(data, textStatus, formPart, clubUUID);
				} else {
					searchCrewLicenseCallback(data, textStatus, formPart, clubUUID);
				}
			}
		);
	}
}

function searchRegistrationLicenseCallback(data, textStatus, subPanel, clubUUID) {
	if (data.errors) {
		// display error message
		if ($(".main_error_message", subPanel).size() > 0) {
			$(".main_error_message .message", subPanel).text(messages.error_no_member_found);
		} else {
			$(subPanel).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_no_member_found + "</div></div>");
		}
	} else {
		var member = data.data;
		registration.licenseNumber = member.swissSailingNumber;
		registration.lastname = member.lastname;
		registration.firstname = member.firstname;
		registration.addess = member.address;
		registration.addess2 = member.address2;
		registration.zip = member.zip;
		registration.city = member.city;
		registration.registratorClubs = member.clubs;
		registration.clubUUID = clubUUID;
		registration.nationality = member.country;
		registration.registratorUUID = member.uuid;
		registration.registratorDateOfBirth = member.dateOfBirth;
		registration.email = member.email;
		$("#regatta-registration-dialog_step_1-6 .output").each(function() {
			var name = $(this).attr("rel");
			if (name) {
				$(this).html(registration[name]);
			}
		});
		$("#regatta-registration-dialog_step_1-6 input[name=email]").val(registration.email);
		// prepare the club list for the registrator
		$("#regatta-registration-dialog_step_1-6 div[rel='club']").each(function() {
			if (registration.registratorClubs && registration.registratorClubs.length > 0) {
				var html = "<select name=\"clubUUID\">";
				for (var i=0; i<registration.registratorClubs.length; i++) {
					html += "<option value=\"" + registration.registratorClubs[i].uuid + "\">";
					html += registration.registratorClubs[i].name;
					html += "<\/option>";
				}
				html += "<\/select>";
				$(this).html(html);
			}
		});
		// TODO: preselect the club which has been used for the search...
		
		// 0, 4 because... 0-based and first fieldset is not substep
		showStep(0, 4);
		$("#regatta-registration-dialog_step_1-1").hide();
	}
}

function validateForeignRegistrator() {
	var errors = new Array();
	formPart = $("#regatta-registration-dialog_step_1-4");
	if (!(lastname = $("input[name='lastname']", formPart).val())) {
		$("input[name='lastname']", formPart).focus();
		errors.push("lastname");
	}
	if (!(firstname = $("input[name='firstname']", formPart).val())) {
		$("input[name='firstname']", formPart).focus();
		errors.push("firstname");
	}
	if (!(address = $("input[name='address']", formPart).val())) {
		$("input[name='address']", formPart).focus();
		errors.push("address");
	}
	if (!(zip = $("input[name='zip']", formPart).val())) {
		$("input[name='zip']", formPart).focus();
		errors.push("zip");
	}
	if (!(city = $("input[name='city']", formPart).val())) {
		$("input[name='city']", formPart).focus();
		errors.push("city");
	}
	state = $("input[name='state']", formPart).val();
	if (!(country = $("input[name='country']", formPart).val())) {
		$("input[name='country']", formPart).focus();
		errors.push("country");
	}
	if (!(club = $("input[name='club']", formPart).val())) {
		$("input[name='club']", formPart).focus();
		errors.push("club");
	}
	phone = $("select[name='phone']", formPart).val();
	mobile = $("select[name='mobile']", formPart).val();
	email = $("select[name='email']", formPart).val();

	if (errors.length > 0) {
		// display error message
		if ($(".main_error_message", formPart).size() > 0) {
			$(".main_error_message .message", formPart).text(messages.error_mandatory_fields);
		} else {
			$(formPart).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_mandatory_fields + "</div></div>");
		}
		// set focus on the first field
		$("input[name='" + errors[0] + "']", formPart).focus();
	} else {
		registration.registratorLastname = lastname;
		registration.registratorFirstname = firstname;
		registration.registratorAddess = address;
		registration.registratorZip = zip;
		registration.registratorCity = city;
		registration.registratorState = state;
		registration.registratorClubOther = club;
		registration.registratorNationality = country;
		registration.registratorPhone = phone;
		registration.registratorMobile = mobile;
		registration.registratorEmail = email;
		showStep(1, 0);
	}
}

function resetRegistrationForm(newRegistrationObject) {
	$("div.step input").removeAttr("disabled");

	if (newRegistrationObject != undefined && newRegistrationObject) {
		registration = new Object();
	}
	registration.regattaUUID = regattaUUID;
	$("#regatta-registration-dialog_step_1-1 input[name=registratorType]:checked").removeAttr("checked");
	$("#regatta-registration-dialog_step_1-1").show();
	showStep(0);
}

function showStep(stepNumber, subStepNumber) {
	// remove all error messages
	$("#regatta-registration-dialog .main_error_message").remove();

	$("#regatta-registration-dialog div.body div.step").each(function(index) {
//		alert("step to display: " + stepNumber + "\ncurrent step: "+index + "\nid: "+$(this).attr("id"));
		if (index == stepNumber) {
			// highlight the menu item
			$("#regatta-registration-dialog ol.steps li:eq(" + index + ")").addClass("active");
			// show if hidden
//			if ($(this).not(":visible")) {
				$(this).show();
//			}
			// show the correct substep
			if (subStepNumber == undefined) {
				// don't show any substeps at all
				$(".substep", this).each(function(index) {
					$(this).hide();
				});
			} else {
				$(".substep", this).each(function(index) {
					if (index == subStepNumber) {
						if ($(this).is(":visible")) {
							// don't need to do anything
						} else {
							$(this).show();
						}
					} else {
						if ($(this).is(":visible")) {
							$(this).hide();
						} else {
							// don't need to do anything
						}
					}
				});
			}
		} else {
			// turn off menu item highlightning
			$("#regatta-registration-dialog ol.steps li:eq(" + index + ")").removeClass("active");
			// hide if visible
//			if ($(this).is(":visible")) {
				$(this).hide();
//			}
		}
	});
}

function validateSwissSailingRegistrator() {
	// save the additional values from the form:
	registration.clubUUID = $("#regatta-registration-dialog_step_1-6 select[name=clubUUID]").val();
	registration.email = $("#regatta-registration-dialog_step_1-6 input[name=email]").val();
	registration.phone = $("#regatta-registration-dialog_step_1-6 input[name=phone]").val();
	registration.mobile = $("#regatta-registration-dialog_step_1-6 input[name=mobile]").val();
	// the registrator is a swiss sailing member and therefore there is nothing to be validated... for now.
	if (true) {
//		$("#regatta-registration-dialog_step_2-1").show();
		showStep(1, 0);
	}
}

function validateRegisteredBoat() {
	var errors = new Array();
	var boatClassUUID, otherBoatClass, boatName, sailNumberDigits, sailNumberNationCode, advertisingPermit;
	formPart = $("#regatta-registration-dialog_step_2-1");
	if (!(boatClassUUID = $("select[name='boatClassUUID']", formPart).val()) && !(otherBoatClass = $("input[name='otherBoatTypeDescription']", formPart).val())) {
//		$("select[name='boatClassUUID']", formPart).focus();
		errors.push("boatClassUUID");
		errors.push("otherBoatTypeDescription");
	} else {
		if (boatClassUUID) {
			registration.boatClassUUID = boatClassUUID;
			registration.boatClassName = $("select[name='boatClassUUID'] option:selected", formPart).text();
		}
		if (otherBoatClass == undefined) {
			registration.otherBoatTypeDescription = "";
		} else {
			registration.otherBoatTypeDescription = otherBoatClass;
		}
	}
	boatName = $("input[name='boatName']", formPart).val();
	if (!(sailNumberNationCode = $("input[name='sailNumberNationCode']", formPart).val())) {
//		$("input[name='sailNumberNationCode']", formPart).focus();
		errors.push("sailNumberNationCode");
	}
	if (!(sailNumberDigits = $("input[name='sailNumberDigits']", formPart).val())) {
//		$("input[name='sailNumberDigits']", formPart).focus();
		errors.push("sailNumberDigits");
	}
	if (!(advertisingPermit = $("input[name='advertisingPermit']:checked", formPart).val())) {
//		$("input[name='advertisingPermit']", formPart).focus();
		errors.push("advertisingPermit");
	}
	
	if (errors.length > 0) { 
		// display error message
		if ($(".main_error_message", formPart).size() > 0) {
			$(".main_error_message .message", formPart).text(messages.error_mandatory_fields);
		} else {
			$(formPart).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_mandatory_fields + "</div></div>");
		}
		// set focus on the first field
		$("*[name='" + errors[0] + "']", formPart).focus();
	} else {
		registration.boatname = boatName;
		registration.sailNumberNationCode = sailNumberNationCode;
		registration.sailNumberDigits = sailNumberDigits;
		registration.advertisingPermit = advertisingPermit;
		
		// prepare the crew List
		prepareCrewList();
		updateCrewListDisplay()
//		showStep(3);
//		showSubStep(2, 0);
		showStep(2, 0);
	}
}

function prepareCrewList() {
	// init the list if it does not exist yet
	if (!registration.crewmembers) {
		var crewList = new Array();
		var member = new Object();
		member.type = registration.registratorType;
		member.licenseNumber = registration.licenseNumber;
		member.lastname = registration.lastname;
		member.firstname = registration.firstname;
		member.nationality = registration.nationality;
		if (member.type == 'foreigner') {
			member.clubOther = registration.clubOther;
		} else {
			member.clubs = registration.registratorClubs;
			// TODO: preselect club
			member.clubUUID = registration.clubUUID;
		}
		crewList.push(member);
		registration.crewmembers = crewList;
	}
}

function updateCrewListDisplay() {
	// remove all old rows
	$("#regatta-registration-dialog_step_3-1 table tr:gt(1)").remove();
	
	// fill in the data and display the rows
	for (var i=0; i<registration.crewmembers.length; i++) {
		$("#regatta-registration-dialog_step_3-1 table tr:last").after(crewRowTemplate);
		$("#regatta-registration-dialog_step_3-1 table tr:last").removeClass("template");
		$("#regatta-registration-dialog_step_3-1 table tr:last").addClass("data_row");
	}
	$("#regatta-registration-dialog_step_3-1 table tr.data_row").each(function(index) {
		var currMember = registration.crewmembers[index];
		$(".output", this).each(function() {
			var name = $(this).attr("rel");
			if (name) {
				$(this).html(currMember[name]);
			}
		});
		$("*[rel='club']", this).each(function() {
			if (currMember.clubs && currMember.clubs.length > 0) {
				var html = "<select name=\"clubUUID\">";
				for (var i=0; i<currMember.clubs.length; i++) {
					html += "<option value=\"" + currMember.clubs[i].uuid + "\"";
					if (currMember.clubUUID && currMember.clubUUID == currMember.clubs[i].uuid) {
						html += " selected=\"selected\"";
					}
					html += ">";
					html += currMember.clubs[i].name;
					html += "<\/option>";
				}
				html += "<\/select>";
				$(this).html(html);
			} else {
				if (!currMember.clubOther) {
					currMember.clubOther = "";
				}
				$(this).html("<input type=\"text\" name=\"clubOther\" style=\"width: 40px;\" value=\"" + currMember.clubOther + "\" onchange=\"setOtherClub(" + index + ", this);\" />");
			}
		});
		if (currMember.skipper) {
			$("input[name='skipper']", this).attr("checked", "checked");
		}
		$("input[name='skipper']", this).click(function() {
			updateSkipper(index);
		});
		$("a.button_delete", this).click(function() {
			registration.crewmembers.splice(index, 1);
			updateCrewListDisplay();
//			alert("delete member with index "+index);
		});
		$(this).show();
	});
}

function setOtherClub(index, inputElement) {
	registration.crewmembers[index].clubOther = $(inputElement).val();
}

function updateSkipper(index) {
	if (registration.crewmembers && index < registration.crewmembers.length) {
		for (var i=0; i<registration.crewmembers.length; i++) {
			if (i == index) {
				registration.crewmembers[i].skipper = true;
			} else {
				registration.crewmembers[i].skipper = false;
			}
		}
	}
}

function newCrewMember() {
	crewMember = new Object();
	$("#regatta-registration-dialog_step_3-2 input").each(function() {
//		$(this).change(function() {
//		});
		$(this).removeAttr("checked");
	});
//	showSubStep(2, 1);
	showStep(2, 1);
}

function setNewCrewMemberType(element) {
	var type = $(element).val();
	if (type == "swiss_sailing") {
//		showSubStep(2, 2);
		showStep(2, 2);
	} else if (type == "swiss_sailing_no_license_number") {
//		showSubStep(2, 3);
		showStep(2, 3);
	} else if (type == "no_license") {
//		showSubStep(2, 4);
		showStep(2, 4);
	} else if (type == "foreigner") {
//		showSubStep(2, 5);
		showStep(2, 5);
	}
}

function registrationValidateCrewMember(panel, type) {
	var errors = new Array();
	var formPart = $("#" + panel);
	var newCrewMember = new Object();
	if (!(newCrewMember.lastname = $("input[name='lastname']", formPart).val())) {
		errors.push("lastname");
	}
	if (!(newCrewMember.firstname = $("input[name='firstname']", formPart).val())) {
		errors.push("firstname");
	}
	if (!(newCrewMember.address = $("input[name='address']", formPart).val())) {
		errors.push("address");
	}
	if (!(newCrewMember.zip = $("input[name='zip']", formPart).val())) {
		errors.push("zip");
	}
	if (!(newCrewMember.city = $("input[name='city']", formPart).val())) {
		errors.push("city");
	}
	newCrewMember.state = $("input[name='state']", formPart).val();
	newCrewMember.nationality = $("input[name='nationality']", formPart).val();
	if (!newCrewMember.nationality && type == 'no_license') {
		newCrewMember.nationality = "CH"
	}
	newCrewMember.dateOfBirth = $("input[name='dateOfBirth']", formPart).val();
	newCrewMember.clubOther = $("input[name='clubOther']", formPart).val();
	if (newCrewMember.dateOfBirth) {
		var testDate = Date.parseExact(newCrewMember.dateOfBirth, "d.M.yyyy");
		if (!testDate) {
			errors.push("dateOfBirth");
		} else {
			newCrewMember.dateOfBirth = testDate;
		}
	}
	if (errors.length > 0) {
		// display error message
		if ($(".main_error_message", formPart).size() > 0) {
			$(".main_error_message .message", formPart).text(messages.error_mandatory_fields);
		} else {
			$(formPart).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_mandatory_fields + "</div></div>");
		}
		// set the focus
		$("*[name='" + errors[0] + "']", formPart).focus();
	} else {
		registration.crewmembers.push(newCrewMember);
		updateCrewListDisplay();
//		showSubStep(2, 0);
		showStep(2, 0);
	}
}

function searchCrewLicenseCallback(data, textStatus, subPanel) {
	if (data.errors) {
		// display error message
		if ($(".main_error_message", subPanel).size() > 0) {
			$(".main_error_message .message", subPanel).text(messages.error_no_member_found);
		} else {
			$(subPanel).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_no_member_found + "</div></div>");
		}
	} else {
		var member = data.data;
		crewMember.licenseNumber = member.swissSailingNumber;
		crewMember.lastname = member.lastname;
		crewMember.firstname = member.firstname;
		crewMember.addess = member.address;
		crewMember.zip = member.zip;
		crewMember.city = member.city;
		crewMember.clubs = member.clubs;
		crewMember.nationality = member.country;
		crewMember.uuid = member.uuid;
		crewMember.dateOfBirth = member.dateOfBirth;
		registration.crewmembers.push(crewMember);
//		addCrewMemberRow(crewMember);
		updateCrewListDisplay();
//		showSubStep(2, 0);
		showStep(2, 0);
	}
}

function validateRegisteredCrew() {
	// at least one crew member should be in the list...
	if (registration.crewmembers.length == 0) {
		// display error message
		if ($("#regatta-registration-dialog_step_3-1 .main_error_message").size() > 0) {
			$("#regatta-registration-dialog_step_3-1 .main_error_message .message").text(messages.error_crew_list_empty);
		} else {
			$("#regatta-registration-dialog_step_3-1").prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_crew_list_empty + "</div></div>");
		}
		return;
	}
	// set the clubUUID for all crew members according to their selection and make sure that
	// one of the crew members is marked as skipper!
	var hasSkipper = false;
	$("#regatta-registration-dialog_step_3-1 table tr.data_row").each(function(index) {
		// club
		registration.crewmembers[index].clubUUID = $("select[name=clubUUID]", this).val();
		// skipper
		if ($("input[name='skipper']", this).is(":checked")) {
			hasSkipper = true;
			registration.crewmembers[index].skipper = true;
		} else {
			registration.crewmembers[index].skipper = false;
		}
	});
	if (!hasSkipper) {
		// display error message
		if ($("#regatta-registration-dialog_step_3-1 .main_error_message").size() > 0) {
			$("#regatta-registration-dialog_step_3-1 .main_error_message .message").text(messages.error_no_skipper_selected);
		} else {
			$("#regatta-registration-dialog_step_3-1").prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_no_skipper_selected + "</div></div>");
		}
		return;
	} else {
		prepareCartPanel();		
		showStep(3, 0);
	}
}

function prepareCartPanel() {
	// preselect the category products list
	if (!registration.categoryCartItem) {
		// deselect all
		$("#regatta-registration-dialog_step_4-1 select[name=categoryProduct] option:selected").removeAttr("selected");
	} else {
		// reselect the correct one... hm...
	}

	// add up the number of event licenses needed
	var eventLicencesNeeded = 0;
	for (var i=0; i<registration.crewmembers.length; i++) {
		if (!registration.crewmembers[i].licenseNumber && !registration.crewmembers[i].clubOther) {
			// neither swiss sailing member nor member of an other club
			eventLicencesNeeded++;
		}
	}
	if (!registration.eventLicenseCartItem) {
		registration.eventLicenseCartItem = new CartItem("event_license", "Event license", eventLicensePrice, eventLicencesNeeded);
	} else {
		registration.eventLicenseCartItem.quantity = eventLicencesNeeded;
	}
	$("#regatta-registration-dialog_step_4-1 td[rel=eventLicenseQuantity]").text(eventLicencesNeeded);
	
	// set all optional product quantities to 0
	$("#regatta-registration-dialog_step_4-1 tr.optional_products input.quantity").each(function() {
		$(this).val(0);
	});
	// init optionl cart item array if needed
	if (!registration.optionsCart) {
		registration.optionsCart = new Array();
	}
	for (var i=0; i<registration.optionsCart.length; i++) {
		var id = registration.optionsCart[i].id;
		var quantity = registration.optionsCart[i].quantity;
//		alert("item " + i + ": " + quantity + "x " + id);
		$("#regatta-registration-dialog_step_4-1 tr.optional_products input[rel=" + id + "]").val(quantity);
	}
	
	// update the total
	updateCartTotal();
}

function setCategoryProduct(element) {
	var selectedOption = $("option:selected", $(element));
	if ($(selectedOption).val()) {
		var productParts = $(selectedOption).attr("rel").split("||");
		var title = productParts[1];
		var price = productParts[2];
//		alert("product: "+title + ", price: "+price);
		registration.categoryCartItem = new CartItem($(selectedOption).val(), title, price, 1);
//		alert("selected product: " + registration.categoryCartItem.title);
	} else {
		registration.categoryCartItem = null;
	}
	updateCartTotal();	
}

function updateOptionalProductCartItems(productID, inputElement) {
	var quantity = $(inputElement).val();
	var itemIndex;
	// TODO: validate quantity
	// look for cart item with this product id
	var cartItem = null;
	if (registration.optionsCart) {
		for (var i=0; i<registration.optionsCart.length; i++) {
			if (registration.optionsCart[i].id == productID) {
				cartItem = registration.optionsCart[i];
				itemIndex = i;
				break;
			}
		}
	} else {
		registration.optionsCart = new Array();
	}
	if (cartItem == null && quantity > 0) {
		// create new cart item
		var row = $(inputElement).closest("tr"); //.parentsUntil("tr").eq(0);
		var title = $("td[rel=title]", row).text();
		var price = parseFloat($("td[rel=price]", row).text());
		registration.optionsCart.push(new CartItem(productID, title, price, quantity));
	} else {
		if (quantity == 0) {
			// remove product from cart
			registration.optionsCart.splice(itemIndex, 1);
		} else {
			cartItem.quantity = quantity;
		}
	}
	updateCartTotal();
}

function updateOptionalProductQuantityDisplay(productID, inputElement) {
	var quantity = 0;
	if (registration.optionsCart) {
		for (var i=0; i<registration.optionsCart.length; i++) {
			if (registration.optionsCart[i].id == productID) {
				quantity = registration.optionsCart[i].quantity;
			}
		}
	}
	$(inputElement).val(quantity);
}

function updateCartTotal() {
	var total = 0;
	if (registration.categoryCartItem) {
		total += registration.categoryCartItem.total();
	}
	if (registration.eventLicenseCartItem) {
		total += registration.eventLicenseCartItem.total();
	}
	if (registration.optionsCart && registration.optionsCart.length > 0) {
		for (var i=0; i<registration.optionsCart.length; i++) {
			total += registration.optionsCart[i].total();
		}
	}
	registration.total = total;
	$("#regatta-registration-dialog_step_4-1 th[rel=total]").text(total.toFixed(2));
}

function CartItem(id, title, price, quantity) {
	this.id = id;
	this.title = title;
	this.price = price;
	this.quantity = quantity;
	this.total = function() {
		return this.quantity * this.price;
	}
}

function validateQuantity(event) {
	// Allow only backspace, delete, tab and enter
	if ( event.keyCode == 46 || event.keyCode == 8  || event.keyCode == 9 || event.keyCode == 13) {
		// let it happen, don't do anything
	} else {
		// Ensure that it is a number and stop the keypress
		if (event.keyCode < 48 || (event.keyCode > 57 && event.keyCode < 96) || event.keyCode > 105 ) {
//			alert("keyCode: "+event.keyCode);
			event.preventDefault();	
		} else {
			if (event.shiftKey || event.ctrlKey || event.altKey) {
				event.preventDefault();	
			}
		}
	}
}

function validateRegistrationCart() {
	var formPart = $("#regatta-registration-dialog_step_4-1");
	if (!registration.categoryCartItem) {
		// display error message
		if ($(".main_error_message", formPart).size() > 0) {
			$(".main_error_message .message", formPart).text(messages.error_no_category_selected);
		} else {
			$(formPart).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_no_category_selected + "</div></div>");
		}
		// set focus on the first field
		$("select[name=categoryProduct]", formPart).focus();
	} else {
		// fill in values
		formPart = $("#regatta-registration-dialog_step_5-1");
		$(".output", formPart).each(function() {
			var name = $(this).attr("rel");
			if (name) {
				$(this).html(registration[name]);
			}
		});
		// crew
		// clear old entries first
		$("#registration_overview_crew li").remove();
		// add the new entries
		var html;
		for (var i=0; i<registration.crewmembers.length; i++) {
			html = "<li>";
			html += registration.crewmembers[i].firstname + " " + registration.crewmembers[i].lastname;
			if (registration.crewmembers[i].skipper) {
				html += " (skipper)";
			}
			html += "</li>";
			$("#registration_overview_crew").append(html);
		}
		// cart
		// remove old 
		$("#registration_overview_cart li").remove();
		$("#registration_overview_cart").append("<li>1x " + registration.categoryCartItem.title + " - CHF " + registration.categoryCartItem.total().toFixed(2) + "</li>");
		if (registration.eventLicenseCartItem && registration.eventLicenseCartItem.quantity > 0) {
			$("#registration_overview_cart").append("<li>" + registration.eventLicenseCartItem.quantity + "x " + registration.eventLicenseCartItem.title + " - CHF " + registration.eventLicenseCartItem.total().toFixed(2) + "</li>");
		}
		if (registration.optionsCart && registration.optionsCart.length > 0) {
			for (var i=0; i<registration.optionsCart.length; i++) {
				$("#registration_overview_cart").append("<li>" + registration.optionsCart[i].quantity + "x " + registration.optionsCart[i].title + " - CHF " + registration.optionsCart[i].total().toFixed(2) + "</li>");
			}
		}
		$("#registration_overview_cart").append("<li>TOTAL: CHF " + registration.total.toFixed(2) + "</li>");
		
//		showStep(5);
//		showSubStep(4, 0);
		showStep(4, 0);
	}
}

function validateRegistrationConfirmation() {
	var errors = new Array();
	if (!(registration.confirmation = $("#regatta-registration-dialog_step_5-1 input[name=rulesConfirmation]").is(":checked"))) {
		errors.push("rulesConfirmation");
	}
	if (!(registration.paymentMethod = $("#regatta-registration-dialog_step_5-1 input[name=paymentMethod]:checked").val())) {
		errors.push("paymentMethod");
	}
	if (errors.length > 0) {
		// display error message
		if ($("#regatta-registration-dialog_step_5-1 .main_error_message").size() > 0) {
			$("#regatta-registration-dialog_step_5-1 .main_error_message .message").text(messages.error_mandatory_fields);
		} else {
			$("#regatta-registration-dialog_step_5-1").prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + messages.error_mandatory_fields + "</div></div>");
		}
		// set focus on the first field
		$("input[name='" + errors[0] + "']:eq(0)", formPart).focus();
	} else {
		// send registration to server
//		jQuery.getJSON(
		jQuery.postJSON(
			sailCalPageURL,
			{
				"regatta": regattaUUID,
				"registration": JSON.stringify(registration),
				"command": "saveRegistration",
				"mgnlCK": ieCacheKiller()
			},
			registrationCallback
		);
	}
}

function registrationCallback(data, textStatus) {
	if (data.errors) {
		alert("an error has occured when trying to save the registration!");
		// display error message
		if ($(".main_error_message", subPanel).size() > 0) {
			$(".main_error_message .message", subPanel).text(data.errors);
		} else {
			$(subPanel).prepend("<div class=\"error main_error_message ui-state-error ui-corner-all\"><span class=\"ui-icon ui-icon-alert\"><!-- --></span><div class=\"message\">" + data.errors + "</div></div>");
		}
	} else {
//		alert("registration saved!");
		showStep(5, 0);
	}
}
/* date stuff *************************************************************************************/
Date.fromISOString = function(isoString) {
//	alert("trying to convert \"" + isoString + "\" to date (length: "+isoString.length+")");
	// e.g. "2009-08-13T22:00:00Z"
	if (isoString) {
		isoFormatRegexPattern.lastIndex = 0;
		var matches = isoFormatRegexPattern.exec(isoString);
//		alert("matches: "+matches );
		if (matches && matches.length == 7) {
			var myDate = new Date();
			var year = parseInt(matches[1]);
			var month = matches[2];
			if (month.substring(0,1) == "0") {
				month = month.substring(1);
			}
			month = parseInt(month) - 1;
			var day = matches[3];
			if (day.substring(0,1) == "0") {
				day = day.substring(1);
			}
			day = parseInt(day);
			var hour = matches[4];
			if (hour.substring(0,1) == "0") {
				hour = hour.substring(1);
			}
			hour = parseInt(hour);
			var minute = matches[5];
			if (minute.substring(0,1) == "0") {
				minute = minute.substring(1);
			}
			minute = parseInt(minute);
			var second = matches[6];
			if (second.substring(0,1) == "0") {
				second = second.substring(1);
			}
			second = parseInt(second);
			myDate.set({
				millisecond: 0,
				second: second,
				minute: minute,
				hour: hour,
				day: day,
				month: month,
				year: year
			});
//			myDate.add({minutes: myDate.getTimezoneOffset()*-1});
			return myDate;
		} else {
			alert("ERROR: Could not parse ISO date string: \""+isoString+"\"");
			return null;
		}
	}
}

function DateTimePicker(idDateField, idTimeField, dateObject, datePattern, timePattern) {
	var _that = this;
	this.dateFieldID = idDateField;
	this.timeFieldID = idTimeField;
	this.datePatter = datePattern;
	if (!this.datePattern) {
		this.datePattern = "d.M.yyyy";
	}
	this.timePattern = timePattern;
	if (!this.timePattern) {
		this.timePattern = "HH:mm";
	}
	this.dateObject = null;
	if (dateObject) {
		this.dateObject = dateObject;
		$("#" + this.dateFieldID).datepicker("setDate", this.dateObject.clone());
		$("#" + this.timeFieldID).val(this.dateObject.toString(this.timePattern));
	}
	this.dayString = $("#" + this.dateFieldID).val();
	this.timeString = $("#" + this.timeFieldID).val();

	this.hasDateAndTimeValues = function() {
		return (this.dayString && this.timeString);
	}
	
	this.isEmpty = function() {
		return ((!this.dayString || this.dayString.length == 0) && (!this.timeString || this.timeString.length == 0));
	}
	
	/**
	 * valid = either empty or with date and time values which compile to a correct Date object
	 */
	this.isValid = function() {
		return (this.isEmpty() || (this.hasDateAndTimeValues() && this.dateObject));
	}
	
	this.updateDayValue = function() {
		this.dayString = $("#" + this.dateFieldID).val();
		this.updateDateObject();
	}
	
	this.updateTimeValue = function() {
		this.timeString = $("#" + this.timeFieldID).val();
		this.updateDateObject();
	}
	
	this.updateDateObject = function() {
		if (this.hasDateAndTimeValues()) {
			// convert 1:00 to 01:00
//			alert("timeString: "+this.timeString);
			timeRegexPattern.lastIndex = 0;
			var matches = timeRegexPattern.exec(this.timeString);
			if (matches && matches.length == 3) {
				if (matches[1].length == 1) {
					this.timeString = "0" + this.timeString;
				}
			}
//		alert("matches: "+matches );
//		if (matches && matches.length == 7) {

			var dateTimeString = this.dayString + " " + this.timeString;
			var dateTimePattern = this.datePattern + " " + this.timePattern;
			var newDate = Date.parseExact(dateTimeString, dateTimePattern);
			if (newDate) {
//				alert("new date: "+newDate);
				this.dateObject = newDate;
				if (this.updateDateSource) {
					this.updateDateSource(newDate);
				}
			} else {
				alert("invalid date/time format");
			}
		} else if (this.isEmpty()) {
			this.dateObject = null;
			this.updateDateSource(null);
		} else {
			this.dateObject = null;
		}
	}
	
	this.updateDateSource = function(theDate) {
		alert("setting date to " + theDate)
	}

	$("#" + this.dateFieldID).change(function() {
		_that.updateDayValue();
	});
	$("#" + this.timeFieldID).change(function() {
		_that.updateTimeValue();
	});
}

/* noyb stuff *************************************************************************************/
function dcmadr(nnnn) {
	var a = "";
	for(i=0,m=nnnn.length;i < m;i++){
		if(i%3==0){
			a += String.fromCharCode(nnnn.substr(i, 3)-37);
		}
	}
	return a;
}

function dcmt(nnnn) {
	var a = dcmadr(nnnn);
	location.href=('m'+'ail'+'t'+'o:'+a);
}
