$(function() {
	$('.fx-collapsed-form').each(function() {
		var form = $(this).find('form').hide();
		var actionButtons = $(this).find('.fx-collapsed-form-actions');
		var refineSearchButton = actionButtons.find('.fx-collapsed-form-refine-search').removeClass('hidden');

		refineSearchButton.click(function() {
			form.toggle();
		});
	});

	$('.fx-select-with-text-option').each(function() {
		var select = $(this);
		var metadata = select.metadata();
		var map = {};
		map[metadata.textOptionValue] = metadata.textFieldClass;
		dropDown(select.attr('name'), map);
	});

	var visitedRadioGroups = [];
	$('.fx-radio-toggle').each(function() {
		var currentName = $(this).attr('name');
		if ($.inArray(currentName, visitedRadioGroups) == -1) {
			visitedRadioGroups.push(currentName);

			var map = {};
			$('input:radio[name="' + currentName + '"]').each(function() {
				var radio = $(this);
				var value = radio.val();
				var target = radio.metadata().toggleTarget;
				map[value] = target;
			});

			radio(currentName, map);
		}
	});
	
	$('.fx-form-components').each(function() {
		var stage = $(this);
		var templates = stage.find('.fx-templates');
		var components = stage.find('.fx-form-component');
		var relevantFormFieldsSelector = 'textarea, select, input:not(.fx-form-component-delete-input)';
		var metaData = stage.metadata();

		var requiredComponents = parseInt(metaData.requiredComponents);
		var autoAddOnSubmit = parseInt(metaData.autoAddOnSubmit);

		var addButton = stage.append(templates.find('.fx-form-component-add').clone()).children(':last').find('.fx-form-component-add-input');

		var uniqueSelection = components.find('.fx-form-component-unique-value').eq(0).clone();
		uniqueSelection.attr('name', '');
		uniqueSelection.val('');
		addButton.before(uniqueSelection);
		
		components.each(function(index) {
			var component = $(this).hide();
			var include = component.find('.fx-form-component-include').hide();
			var includeCheckbox = include.find('.fx-form-component-include-input');
			component.data('includeCheckbox', includeCheckbox);

			if (uniqueSelection.size()) {
				component.data('uniqueValue', component.find('.fx-form-component-unique-value').hide());
				component.data('uniqueValueDisplay', component.data('uniqueValue').after('<span></span>').next());
				component.data('uniqueValue').change(function() {
					var uniqueValue = $(this);
					var display = uniqueValue.next();
					display.html(uniqueValue.find('option:selected').text());
				}).change();
			}

			if (index >= requiredComponents) {
				var deleteButton = component.append(templates.find('.fx-form-component-delete').clone()).children(':last').find('.fx-form-component-delete-input');
				component.data('deleteButton', deleteButton);
				deleteButton.click(function() {
					var componentsAfter = component.nextAll('.fx-form-component');
					var current = component;

					if (uniqueSelection.size()) {
						uniqueSelection.find('option[value="' + current.data('uniqueValue').val() + '"]').removeAttr('disabled');
					}

					componentsAfter.each(function() {
						var next = $(this);
						if (!next.is(':visible')) {
							return false;
						}
						next.find(relevantFormFieldsSelector).each(function(index) {
							current.find(relevantFormFieldsSelector).eq(index).val($(this).val()).change();
						});
						current = next;
					});

					current.find(relevantFormFieldsSelector).val('').change();
					current.find('.fx-form-component-readonly').remove();
					current.data('includeCheckbox').removeAttr('checked');
					current.hide();

					addButton.show();
					uniqueSelection.show();
				});
			}
		});

		addButton.click(function() {
			components.each(function() {
				var component = $(this);
				if (!component.data('includeCheckbox').is(':checked')) {
					if (uniqueSelection.size()) {
						var componentUniqueValue = component.data('uniqueValue').val();
						if (uniqueSelection.val()) {
							component.data('uniqueValue').val(uniqueSelection.val()).change();
							uniqueSelection.find('option:selected').attr('disabled', 'disabled');
							uniqueSelection.val('');
						} else if (componentUniqueValue) {
							uniqueSelection.find('option[value="' + componentUniqueValue + '"]').attr('disabled', 'disabled');
						} else {
							return false;
						}
					}

					component.data('includeCheckbox').attr('checked', 'checked');

					component.show();
					return false;
				}
			});
			if (!components.filter(':not(:visible)').size()) {
				addButton.hide();
				uniqueSelection.hide();
			}
		});

		var visibleComponents = Math.max(requiredComponents, components.find('.fx-form-component-include-input:checked').size());
		components.slice(0, visibleComponents).each(function() {
			var component = $(this);
			component.data('includeCheckbox').removeAttr('checked');
			addButton.click();
		});

		if (!components.filter(':not(:visible)').size()) {
			addButton.hide();
		}

		if (autoAddOnSubmit) {
			stage.closest('form').submit(function() {
				addButton.click();
			});
		}
	});
	
	$('.fx-form-multiplechoice').each(function() {
		var stage = $(this);
		var templates = stage.find('.fx-templates');
		var choices = stage.find('.fx-form-choice').hide();
		var addChoice = stage.append(templates.find('.fx-form-choice-add').clone()).children(':last');

		var maximumChoices = stage.metadata().maximumChoices;
		if (!maximumChoices)
			maximumChoices = choices.size();
		
		var addChoiceSelect = addChoice.find('.fx-form-choice-add-select');
		var optionsHtml = '';
		choices.each(function(index) {
			var choice = $(this);
			var value = choice.find('.fx-form-choice-value').val();
			var label = choice.find('.fx-form-choice-label');
			choice.data('value', value);
			optionsHtml += '<option class="' + index + '" value="' + value + '">' + label.text() + '</option>'; 
		});
		addChoiceSelect.append(optionsHtml);
		
		var addChoiceButton = addChoice.find('.fx-form-choice-add-input');
		addChoiceButton.click(function() {
			var value = addChoiceSelect.val();
			if (!value) return;

			var option = addChoiceSelect.find('option[value="' + value + '"]');
			option.attr('disabled', 'disabled');

			addChoiceSelect.val('');

			var checkbox = choices.find('input[value="' + value + '"]');
			checkbox.attr('checked', 'checked');

			var selectedInformation = addChoice.before(templates.find('.fx-form-choice-selected').clone()).prev();
			selectedInformation.find('.fx-form-choice-selected-slot').append(option.text());
			var deleteButton = selectedInformation.find('.fx-form-choice-selected-delete-input');
			deleteButton.click(function() {
				checkbox.removeAttr('checked');
				option.removeAttr('disabled');
				selectedInformation.remove();
				if (addChoiceSelect.find('option:disabled').size() < maximumChoices) {
					addChoice.show();
				}
			});

			if (addChoiceSelect.find('option:disabled').size() >= maximumChoices) {
				addChoice.hide();
			}
		});
		
		choices.each(function() {
			var choice = $(this)
			var checkbox = choice.find('input');
			if (checkbox.is(':checked')) {
				addChoiceSelect.val(choice.data('value'));
				addChoiceButton.click();
			}
		});
		
		stage.closest('form').submit(function() {
			addChoiceButton.click();
		});
	});
	
	$('.fx-date').datepicker({
		dateFormat: 'yy-mm-dd'
	});
	
	$('.fx-hide-next').each(function() {
		var row = $(this);
		var next = row.next();
		var checkbox = row.find('.fx-hide-next-toggle');
			
		var checkboxToggle = function() {
			if (checkbox.is(':checked')) {
				next.show();
			} else {
				next.hide();
			}
		};

		checkbox.click(checkboxToggle);
		checkboxToggle();
	});
	
	$('.fx-textarea-count').each(function() {
		var row = $(this);
		var text = row.find('textarea');
		var counter = row.find('.counter');
		var maxCharacters = parseInt(counter.text());
		
		var charactersLeft;
		
		var update = function() {
			charactersLeft = maxCharacters - text.val().length;
			counter.text(charactersLeft);
			if (charactersLeft < 0) {
				counter.addClass('counter-minus');
			} else {
				counter.removeClass('counter-minus');
			}
		}
		
		text.keyup(function() {
			update();
		}).keyup();
		
		text.keypress(function(event) {
			update();
			if ((charactersLeft <= 0) && ($.inArray(event.keyCode, [
				$.ui.keyCode.BACKSPACE,
				$.ui.keyCode.INSERT,
				$.ui.keyCode.SHIFT,
				$.ui.keyCode.DELETE,
				$.ui.keyCode.LEFT,
				$.ui.keyCode.RIGHT,
				$.ui.keyCode.UP,
				$.ui.keyCode.DOWN
			]) == -1))
				return false;
		});
	});

	$('.fx-tag-autocomplete').each(function() {
		var input = $(this);
		var metadata = input.metadata();
		var url = metadata.url;
		var parameterName = metadata.parameterName;

		input.autocomplete({
			minLength: 3,
			source: function( request, response ) {
				var parameters = {};
				parameters[parameterName] = request.term;
				$.ajax({
					url: url,
					dataType: "json",
					data: parameters,
					success: function( data ) {
						response( $.map( data, function( item ) {
							return {
								label: item.tag,
								value: item.tag
							}
						}));
					}
				});
			}
		});
	});

	$('.fx-tags').each(function() {
		var section = $(this);
		var tagCloud = section.find('.tag-cloud');
		var tagCloudTags = tagCloud.find('.tag');
		var tagComponents = section.find('.fx-form-component');
		var addButton = section.find('.fx-form-component-add-input');

		tagCloudTags.click(function() {
			var tag = $(this);
			var tagComponent = tagComponents.filter(':not(:visible):first');
			if (!tag.is('.tag-selected') && tagComponent.size()) {
				addButton.click();
				tagComponent.find('input:text').val(tag.text()).keyup();
			}
		});

		tagComponents.find('input:text').keyup(function() {
			tagCloudTags.each(function() {
				var tagCloudTag = $(this);
				var tagCloudTagText = tagCloudTag.text();
				var found = false;
				tagComponents.each(function() {
					var tagComponent = $(this);
					var textField = $(this).find('input:text');
					var tag = textField.val();
					if (tagCloudTagText == tag) {
						found = true;
						return false;
					}
				});
				tagCloudTag.removeClass('tag-selected');
				if (found) {
					tagCloudTag.addClass('tag-selected');
				}
			});

		}).keyup();

		tagComponents.each(function() {
			var tagComponent = $(this);
			var deleteInput = tagComponent.find('.fx-form-component-delete-input');
			var textField = tagComponent.find('input:text');
			deleteInput.click(function() {
				textField.keyup();
			});
		});
	});

	$('.fx-checkbox-hierarchy-selection').each(function() {
		var checkboxHierarchyContainer = $(this);
		var hierarchyNodes = checkboxHierarchyContainer.find('li').addClass('fx-checkbox-hierarchy-node');
		var hierarchyNodesWithChildren = hierarchyNodes.has('ul');

		hierarchyNodesWithChildren.each(function() {
			var currentContainer = $(this);

			var expansionHandle = $('<div class="fx-checkbox-hierarchy-expansion-handle checkbox-hierarchy-expansion-handle"><span>Expand or collapse</span></div>');
			currentContainer.prepend(expansionHandle);

			expansionHandle.click(function() {
				if (currentContainer.is('.checkbox-hierarchy-collapsed')) {
					expandContainer(currentContainer);
				} else {
					collapseContainer(currentContainer);
				}
			});
		});

		if (checkboxHierarchyContainer.is('.fx-checkbox-hierarchy-selection-collapse-all')) {
			collapseContainer(hierarchyNodesWithChildren);
		}

		checkboxHierarchyContainer.find('input:checked').each(function() {
			var checkbox = $(this);
			var parentContainers = checkbox.parents('.fx-checkbox-hierarchy-node').not(checkbox.parent());
			updateHierarchyNode(checkbox);
			expandContainer(parentContainers);
		});

		checkboxHierarchyContainer.find('input').click(function() {
			updateHierarchyNode($(this));
		});

		function updateHierarchyNode(clickedInput) {
			var parentContainers = clickedInput.parents('.fx-checkbox-hierarchy-node');
			var firstParent = parentContainers.eq(0);
			var isChecked = clickedInput.attr('checked');

			if (firstParent.has('ul'))
				firstParent.find('input').attr('checked', isChecked);

			if (!isChecked) {
				var toggleInputs = parentContainers.find('> input');
				toggleInputs.attr('checked', false);
			} else {
				parentContainers.each(function() {
					var parentContainer = $(this);
					if (!parentContainer.find('ul').find('input:not(:checked)').size()) {
						parentContainer.children('input').attr('checked', true);
					}
				});
			}
		}

		function expandContainer(container) {
			container.removeClass('checkbox-hierarchy-collapsed');
			container.children('ul').show();
		}

		function collapseContainer(container) {
			container.addClass('checkbox-hierarchy-collapsed');
			container.children('ul').hide();
		}
	});
});

var checkbox = function(valueOrName, toggledContainerClass) {
	var checkbox = $('input:checkbox[value="' + valueOrName + '"],input:checkbox[name="' + valueOrName + '"]');
	if (checkbox.size()) {
		var toggledContainerSelector = '.' + toggledContainerClass;

		var toggle = function() {
			if (checkbox.is(':checked')) {
				showFields(toggledContainerSelector);
			} else {
				hideFields(toggledContainerSelector);
			}
		};

		checkbox.click(toggle);
		toggle();
	}
};

var dropDown = function(name, toggledContainerClasses, toggledContainerClass) {
	singleChoiceField(name, toggledContainerClasses, toggledContainerClass, 'select', function(field) { return field.find('option'); }, function(option) { return option.is(':selected'); }, function(field, toggle) { field.change(toggle); });
}

var radio = function(name, toggledContainerClasses, toggledContainerClass) {
	singleChoiceField(name, toggledContainerClasses, toggledContainerClass, 'input:radio', function(field) { return field; }, function(option) { return option.is(':checked'); }, function(field, toggle) { field.click(toggle); });
};

var singleChoiceField = function(name, toggledContainerClasses, toggledContainerClass, selector, optionsCallback, selectedCallback, registerCallback) {
	var field = $(selector + '[name="' + name + '"]');
	var options = optionsCallback(field);
	if (field.size()) {
		var toggle = function() {
			var foundChecked = false;

			options.each(function() {
				var option = $(this);
				var value = option.val();
				if (toggledContainerClasses[value]) {
					var toggledContainerSelector = '.' + toggledContainerClasses[value];
					if (selectedCallback(option)) {
						foundChecked = true;
						showFields(toggledContainerSelector);
					} else {
						hideFields(toggledContainerSelector);
					}
				}
			});

			if (toggledContainerClass) {
				var toggledContainerSelector = '.' + toggledContainerClass;

				if (foundChecked) {
					showFields(toggledContainerSelector);
				} else {
					hideFields(toggledContainerSelector);
				}
			}
		};

		registerCallback(field, toggle);
		toggle();
	}
};

var showFields = function(selector) {
	var toggledContainer = $(selector);
	if (toggledContainer.is(':hidden')) {
		toggledContainer.show();
		if (toggledContainer.data('removeHandler')) {
			toggledContainer.parents('form').unbind('submit', toggledContainer.data('removeHandler'));
			toggledContainer.data('removeHandler', null);
		}
	}
};

var hideFields = function(selector) {
	var toggledContainer = $(selector);
	if (toggledContainer.is(':visible')) {
		toggledContainer.hide();
		toggledContainer.data('removeHandler', function() {
			removeFieldsWhenSubmitting(selector);
		});
		toggledContainer.parents('form').bind('submit', toggledContainer.data('removeHandler'));
	}
};

var removeFieldsWhenSubmitting = function(selector) {
	$(selector).remove();
}

var toggleOptionalField = function(selector, toggledContainerClass) {
	var field = $('#' + selector);
	var toggle = function() {
		var action = field.is(':checked') ? 'required' : 'optional';
		$('.' + toggledContainerClass).each(function() {
			var optionalSpans = $(this).find('label > span.optional');
			if (action == 'required') {
				$(this).addClass('validator-required');
				optionalSpans.hide();
			} else {
				$(this).removeClass('validator-required');
				optionalSpans.show();
			}
		});
	};

	field.click(toggle);
	toggle();
};

