/*
 * Copyright (c) 2026, Tribal Limited
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Zenario, Tribal Limited nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL TRIBAL LTD BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
	This file contains JavaScript source code.
	The code here is not the code you see in your browser. Before this file is downloaded:
	
		1. Compilation macros are applied (e.g. "foreach" is a macro for "for .. in ... hasOwnProperty").
		2. It is minified (e.g. using Google Closure Compiler).
		3. It may be bundled together with other files (this is to reduce the number of http requests on a page).
	
	For more information, see js_minify.shell.php for steps (1) and (2), and organizer.bundle.js.php for step (3).
*/


zenario.lib(function(
	undefined,
	URLBasePath,
	document, window, windowOpener, windowParent,
	zenario, zenarioA, zenarioT, zenarioAB, zenarioAT, zenarioO,
	encodeURIComponent, defined, engToBoolean, get, htmlspecialchars, jsEscape, phrase,
	extensionOf, methodsOf, has,
	panelTypes
) {
	"use strict";


//Note: extensionOf() and methodsOf() are our shortcut functions for class extension in JavaScript.
	//extensionOf() creates a new class (optionally as an extension of another class).
	//methodsOf() allows you to get to the methods of a class.
var methods = methodsOf(
	panelTypes.form_builder = extensionOf(panelTypes.form_builder_base_class)
);

//Draw the panel, as well as the header at the top and the footer at the bottom
//This is called every time the panel is loaded, refreshed or when something in the header toolbar is changed.
methods.showPanel = function($header, $panel, $footer) {
	$header.html('').hide();
	$footer.html('').show();
	
	//Load main panel
	var html = thus.getMainPanelHTML();
	$panel.html(html).show();
	
	//Page currently on
	thus.currentPageId = thus.currentPageId ? thus.currentPageId : false;
	//Thing currently being edited (page/field)
	thus.editingThing = thus.editingThing ? thus.editingThing : false;
	thus.editingThingId = thus.editingThingId ? thus.editingThingId : false;
	thus.editingThingTUIXTabId = thus.editingThingTUIXTabId ? thus.editingThingTUIXTabId : false;
	thus.editingNameField = false;
	thus.editingNameFieldComplete = false;
	thus.deletedPages = [];
	thus.deletedFields = [];
	thus.deletedValues = [];
	thus.changeMadeOnPanel = false;
	thus.pagesReordered = false;
	thus.newItemCount = 0;
	
	//On initial load create the first page
	var pages = thus.getOrderedPages();
	if (pages.length == 0) {
		thus.createPage();
	}
	
	thus.fixTUIXData();
	
	//Load right panel (pages list and fields list)
	thus.loadPagesList();
	thus.loadFieldsList(thus.currentPageId);
	
	//Load left panel
	var stopAnimation = true;
	if (thus.editingThing == 'field') {
		// Show an editor for the selected field
		thus.openFieldEdit(thus.editingThingId, thus.editingThingTUIXTabId, stopAnimation);
	} else if (thus.editingThing == 'page') {
		// Show an editor for the selected page
		thus.openPageEdit(thus.editingThingId, thus.editingThingTUIXTabId, stopAnimation);
	} else {
		// Show a list of fields that can be added by drag and drop
		thus.loadNewFieldsPanel(true);
	}
	
	//Show Growl message if saved changes
	if (thus.changesSaved) {
		thus.changesSaved = false;
		zenarioT.notification(phrase.changesSaved);
	}
};

methods.fixTUIXData = function() {
	//Arrays are turned into objects, fix these here.
	var pages = thus.getOrderedPages();
	for (var i = 0; i < pages.length; i++) {
		var page = thus.getItem('page', pages[i].id);
		
		if (page.visible_condition_checkboxes_field_value) {
			page.visible_condition_checkboxes_field_value = zenarioT.tuixToArray(page.visible_condition_checkboxes_field_value);
		}
		
		var fields = thus.getOrderedFields(page.id);
		for (var j = 0; j < fields.length; j++) {
			var field = thus.getItem('field', fields[j].id);
			if (field.type == 'calculated' && field.calculation_code) {
				field.calculation_code = zenarioT.tuixToArray(field.calculation_code);
			}
			
			if (field.invalid_responses) {
				field.invalid_responses = zenarioT.tuixToArray(field.invalid_responses);
			}
			
			if (field.visible_condition_checkboxes_field_value) {
				field.visible_condition_checkboxes_field_value = zenarioT.tuixToArray(field.visible_condition_checkboxes_field_value);
			}
			if (field.mandatory_condition_checkboxes_field_value) {
				field.mandatory_condition_checkboxes_field_value = zenarioT.tuixToArray(field.mandatory_condition_checkboxes_field_value);
			}
		}
	}
};

methods.getMainPanelHTML = function() {
	var mergeFields = {
		form_title: thus.tuix.form_title
	};
	var html = thus.microTemplate('zenario_organizer_form_builder', mergeFields);
	return html;
};

methods.loadPagesList = function() {
	//Find the current page
	var pages = thus.getOrderedPages();
	if (!thus.currentPageId && pages.length > 0) {
		thus.currentPageId = pages[0].id;
	}
	
	for (var i = 0; i < pages.length; i++) {
		if (thus.currentPageId == pages[i].id) {
			pages[i]._is_current_page = true;
		}
		pages[i].name = thus.formatPageLabel(pages[i].name);
	}
	//Only show page pages if there are at least 2
	if (pages.length <= 1) {
		pages = false;
	}

	//Set HTML
	var mergeFields = {pages: pages, status: thus.tuix.form.status};
	var html = thus.microTemplate('zenario_organizer_form_builder_tabs', mergeFields);
	$('#organizer_form_tabs').html(html);
	
	
	//Add events
	
	//Click on a page
	$('#organizer_form_tabs .tab').on('click', function() {
		var pageId = $(this).data('id');
		if (thus.tuix.pages[pageId]) {
			thus.clickPage(pageId);
		}
	});
	
	if (!thus.tuix.form.status || thus.tuix.form.status == 'active') {
		
		//Add a new page
		$('#organizer_add_new_tab').on('click', function() {
			if (thus.saveCurrentOpenDetails()) {
				var pageId = thus.createPage();
				thus.clickPage(pageId, true);
				thus.changeMadeToPanel();
			}
		});
		
		//Page sorting
		$('#organizer_form_tabs').sortable({ 
			containment: 'parent',
			tolerance: 'pointer',
			items: 'div.sort',
			start: function(event, ui) {
				thus.startIndex = ui.item.index();
			},
			stop: function(event, ui) {
				if (thus.startIndex == ui.item.index()) {
					return;
				}
				//Update ordinals
				$('#organizer_form_tabs .tab.sort').each(function(i) {
					var pageId = $(this).data('id');
					thus.tuix.pages[pageId].ord = (i + 1);
				});
				thus.pagesReordered = true;
				thus.changeMadeToPanel();
			
				//If currently viewing a pages details, reload because the content changes depending on position
				if (thus.editingThing == 'page') {
					thus.saveCurrentOpenDetails();
					thus.openPageEdit(thus.editingThingId, thus.editingThingTUIXTabId, true);
				}
			}
		});
	
		//Moving fields between pages
		$('#organizer_form_tabs .tab').droppable({
			accept: 'div.is_sortable:not(.repeat_end)',
			greedy: true,
			hoverClass: 'ui-state-hover',
			tolerance: 'pointer',
			drop: function(event, ui) {
				if (thus.saveCurrentOpenDetails()) {
					var pageId = $(this).data('id');
					var fieldId = $(ui.draggable).data('id');
					
					if (pageId && fieldId) {
						thus.moveFieldToPage(thus.currentPageId, pageId, fieldId);
		
						if (thus.editingThing == 'field' && thus.editingThingId == fieldId) {
							thus.loadNewFieldsPanel();
						}
						thus.loadFieldsList(thus.currentPageId);
					}
				}
			}
		});
	}
};

methods.getOrderedMergeFieldsForFields = function(pageId) {
	var mergeFields = [];
	var groupedFields = [];
	var groups = {};
	
	foreach (thus.tuix.pages[pageId].fields as var fieldId => var x) {
		var fieldClone = _.clone(thus.tuix.items[fieldId]);
		
		fieldClone.lov = thus.getOrderedFieldValues(fieldId);
		
		if (fieldClone.is_consent) {
			fieldClone.type = 'consent';
		}
		
		//Highlight the current field
		if (thus.editingThing == 'field') {
			if (thus.editingThingId == fieldClone.id) {
				fieldClone._is_current_field = true;
				
				if (fieldClone.visible_condition_field_id) {
					var currentFieldOrdinal = fieldClone.ord;
					
					var currentFieldStepId = fieldClone.page_id;
					var currentFieldStepOrdinal = thus.tuix.pages[currentFieldStepId].ord;
					
					var conditionalFieldId = fieldClone.visible_condition_field_id;
					var conditionalField = thus.tuix.items[conditionalFieldId];
					var conditionalFieldOrdinal = conditionalField.ord;
					
					var conditionalFieldStepId = conditionalField.page_id;
					var conditionalFieldStepOrdinal = thus.tuix.pages[conditionalFieldStepId].ord;
					
					if (fieldClone.repeat_start_id) {
						var repeatingSectionId = fieldClone.repeat_start_id;
						foreach (thus.tuix.items as var fieldId => var field) {
							if (fieldId == conditionalFieldId && (!field.repeat_start_id || field.repeat_start_id != fieldClone.repeat_start_id)) {
								fieldClone.visibility_on_condition_error_message = 'Visibility should only be conditional on another field in this repeating section';
								break;
							}
						}
					} else {
						if (thus.tuix.pages[currentFieldStepId] && thus.tuix.pages[currentFieldStepId].visibility == 'visible_on_condition' && conditionalFieldStepOrdinal != currentFieldStepOrdinal) {
							//If this field is on a step that is visible on condition,
							//AND the field itself is also visible on condition,
							//but its conditional field is on yet another step, show a warning.
							fieldClone.visibility_on_condition_error_message = 'Visibility should only be conditional on another field on this step.';
						} else if (conditionalFieldStepId != currentFieldStepId && conditionalFieldStepOrdinal > currentFieldStepOrdinal) {
							fieldClone.visibility_on_condition_error_message = 'Visibility should only be conditional on another field on this step.';
						} else if (conditionalFieldStepId == currentFieldStepId && conditionalFieldOrdinal > currentFieldOrdinal) {
							fieldClone.visibility_on_condition_error_message = 'Visibility should only be conditional on a previous field.';
						}
					}
				}
			}
		}
		
		//Hide duplicate button for dataset fields
		if (fieldClone.dataset_field_id) {
			fieldClone._hide_duplicate_button = true;
		}
		
		//Group together dataset repeat fields
		if (fieldClone.dataset_repeat_grouping) {
			if (!groups[fieldClone.dataset_repeat_grouping]) {
				groups[fieldClone.dataset_repeat_grouping] = {};
				groups[fieldClone.dataset_repeat_grouping].fields = [];
			}
			if (fieldClone.type != 'repeat_start') {
				fieldClone._hide_drag_button = true;
				fieldClone._hide_delete_button = true;
				fieldClone._hide_duplicate_button = true;
			}
			groupedFields.push(fieldClone);
		} else {
			fieldClone._is_sortable = true;
			mergeFields.push(fieldClone);
		}
		
		//Do not allow editing fields on an archived form
		if (thus.tuix.form.status && thus.tuix.form.status == 'archived') {
			fieldClone._hide_drag_button = true;
			fieldClone._hide_delete_button = true;
			fieldClone._hide_duplicate_button = true;
		} else if (
			thus.tuix.form.send_email_to_admin
			&& thus.tuix.form.send_email_to_admin_destination_for_form_response == 'destination_depends_on_a_field_and_its_values'
			&& thus.tuix.form.admin_email_destination_select_list_for_fields == fieldClone.id
		) {
			fieldClone._hide_drag_button = true;
			fieldClone._hide_delete_button = true;
		}
	}
	
	if (groupedFields.length > 0) {
		for (var i = 0; i < groupedFields.length; i++) {
			groups[groupedFields[i].dataset_repeat_grouping].fields.push(groupedFields[i]);
		}
	}
	
	foreach (groups as var groupName => var group) {
		group.fields.sort(thus.sortByOrd);
		if (group.fields.length) {
			group.ord = group.fields[0].ord;
			group._is_sortable = true;
			mergeFields.push(group);
		}
	}
	
	mergeFields.sort(thus.sortByOrd);
	
	//Remember which fields have a repeat above them for indenting
	var inRepeat = false;
	for (var i = 0; i < mergeFields.length; i++) {
		if (mergeFields[i].type == 'repeat_start') {
			inRepeat = true;
		} else if (mergeFields[i].type == 'repeat_end') {
			inRepeat = false;
		} else if (inRepeat) {
			mergeFields[i]._is_repeat_field = true;
		}
	}
	
	return mergeFields;
};

methods.getOrderedMergeFieldsForDatasetFields = function() {
	var mergeFields = [];
	var usedDatasetFields = {};
	var fields = thus.getOrderedFields();
	for (var i = 0; i < fields.length; i++) {
		if (fields[i].dataset_field_id) {
			usedDatasetFields[fields[i].dataset_field_id] = true;
		}
	}
	
	foreach (thus.tuix.dataset.tabs as var tabName => var tab) {
		var tabClone = _.clone(tab);
		tabClone.fields = [];
		foreach (tab.fields as var fieldId => var x) {
			var fieldClone = _.clone(thus.tuix.dataset.fields[fieldId]);
			if (usedDatasetFields[fieldId]) {
				continue;
			}
			fieldClone.tab_label = tabClone.label ? tabClone.label : tabClone.default_label;
			tabClone.fields.push(fieldClone);
		}
		tabClone.fields.sort(thus.sortByOrd);
		mergeFields.push(tabClone);
	}
	mergeFields.sort(thus.sortByOrd)
	
	return mergeFields;
};

methods.getFormFieldMergeName = function(fieldId) {
	var field = thus.getItem('field', fieldId);
	return field.db_column ? field.db_column : 'unlinked_' + field.type + '_' + fieldId;
};

methods.createPage = function() {
	var pageId = 't' + (++thus.newItemCount);
	var ord = 1;
	var pages = thus.getOrderedPages();
	if (pages.length) {
		ord = pages[pages.length - 1].ord + 1;
	}
	
	var page = {};
	page.id = pageId;
	page.ord = ord;
	page._just_added = true;
	page.fields = {};
	page.name = 'Step ' + (pages.length + 1);
	
	//Load default values for fields
	foreach (thus.tuix.form_page_details.tabs as var tuixTabName => var tuixTab) {
		if (tuixTab.fields) {
			foreach (tuixTab.fields as var tuixFieldName => var tuixField) {
				if (defined(tuixField.value) && !defined(page[tuixFieldName])) {
					page[tuixFieldName] = tuixField.value;
				}	
			}
		}
	}
	
	thus.tuix.pages[pageId] = page;
	return pageId;
};

methods.createField = function(type, ord, datasetFieldId, copyFromFieldId, centralisedSource, centralisedSourceLabel) {
	var fieldId = 't' + (++thus.newItemCount);
	var field = {};
	
	//Create for a dataset field
	if (datasetFieldId) {
		var datasetField = thus.tuix.dataset.fields[datasetFieldId];
		field.type = datasetField.type;
		if (field.type == 'consent') {
			field.type = 'checkbox';
			field.is_consent = true;
			
			//Make new consent fields mandatory by default.
			field.readonly_or_mandatory = 'mandatory';
		}
		
		if (datasetField.type == 'text') {
			if (datasetField.db_column == 'first_name' || datasetField.db_column == 'last_name') {
				field.field_validation = 'name';
				field.field_validation_error_message = 'Please enter a valid name. Don\'t include < or > characters.';
			} else if (datasetField.db_column == 'email') {
				field.field_validation = 'email';
				field.field_validation_error_message = 'The email address you have entered is not valid, please enter a valid email address.';
				field.confirmation_field_error_message = 'The email addresses you have entered do not match.';
			}
		}
		
		field.name = datasetField.label.replace(/:$/, "");
		field.label = datasetField.label;
		field.confirmation_field_label = field.label + ' (confirm)';
		field.dataset_field_id = datasetFieldId;
		field.values_source = datasetField.values_source;
		field.values_source_filter = datasetField.values_source_filter;
		field.db_column = datasetField.db_column;
		
		//Special logic to set terms and conditions label
		if (datasetField.db_column == 'terms_and_conditions_accepted') {
			field.label = 'By submitting your details you are agreeing that we can store your data for legitimate business purposes and contact you to inform you about our products and services.';
			field.note_to_user = 'Full details can be found in our <a href="privacy" target="_blank">privacy policy</a>.';
		}
		
		if (datasetField.repeat_start_id) {
			field.dataset_repeat_grouping = datasetField.repeat_start_id;
		}
		
		if (datasetField.lov) {
			field.lov = datasetField.lov;
		}
		
		if (datasetField.type == 'repeat_start') {
			field.dataset_repeat_grouping = datasetField.id;
			
			var orderedFields = [];
			foreach (thus.tuix.dataset.tabs[datasetField.tab_name].fields as var datasetTabFieldId => var x) {
				var datasetTabField = thus.tuix.dataset.fields[datasetTabFieldId];
				if (datasetTabField.repeat_start_id == datasetFieldId) {
					var datasetTabFieldClone = _.clone(datasetTabField);
					orderedFields.push(datasetTabFieldClone);
				}
			}
			orderedFields.sort(thus.sortByOrd);
			
			for (var i = 0; i < orderedFields.length; i++) {
				thus.createField(undefined, ord + (0.001 * (i + 1)), orderedFields[i].id);
			}
		}
		
	//Copy from existing field
	} else if (copyFromFieldId) {
		field = JSON.parse(JSON.stringify(thus.getItem('field', copyFromFieldId)));
		delete field.field_is_used_as_email_destination_in_form_setting;
		
		if (field.type == 'checkboxes' || type == 'sortable_selection'  || field.type == 'select' || field.type == 'radios') {
			var lov = field.lov;
			delete(field.lov);
			
			field.lov = {};
			for (var valueId in lov) {
				thus.addFieldValue(field, lov[valueId].label, lov[valueId].ord);
			}
		}
		
	//Create new blank field
	} else {
		field.type = type;
		
		if (field.type == 'centralised_select' && centralisedSource) {
			field.values_source = centralisedSource;
			
			field.label = centralisedSourceLabel;
			field.name = centralisedSourceLabel;
		} else {
			field.label = 'Untitled';
			field.name = 'Untitled ' + thus.getFieldReadableType(type).toLowerCase();
		}
		
		field.confirmation_field_label = field.label + ' (confirm)';
		field.confirmation_field_error_message = 'The email addresses you have entered do not match.';
		
		if (type == 'checkboxes' || type == 'sortable_selection' || type == 'radios' || type == 'select') {
			field.lov = {};
			for (var i = 1; i <= 3; i++) {
				thus.addFieldValue(field, 'Option ' + i);
			}
		} else if (type == 'repeat_start') {
			thus.createField('repeat_end', ord + 0.001);
		}
	}
	
	//Load default values for fields
	foreach (thus.tuix.form_field_details.tabs as var tuixTabName => var tuixTab) {
		if (tuixTab.fields) {
			foreach (tuixTab.fields as var tuixFieldName => var tuixField) {
				if (defined(tuixField.value) && !defined(field[tuixFieldName])) {
					field[tuixFieldName] = tuixField.value;
				}	
			}
		}
	}
	
	field.id = fieldId;
	field.page_id = thus.currentPageId;
	field.ord = ord;
	field._just_added = true;
	
	//Work out if this field is in a repeating section.
	var orderedFields = [];
	foreach (thus.tuix.items as var itemId => var item) {
		if (item.page_id == field.page_id) {
			orderedFields.push(item);
		}
	}
	
	if (orderedFields) {
		orderedFields.sort(thus.sortByOrd);
		
		var repeatingSectionStart, repeatingSectionEnd;
		foreach (orderedFields as var fieldOnPageId => var fieldOnPage) {
			if (fieldOnPage.ord >= field.ord) {
				break;
			}
			
			if (fieldOnPage.type == 'repeat_start') {
				//Remember the last started repeating section...
				repeatingSectionStart = fieldOnPage.id
			} else if (fieldOnPage.type == 'repeat_end') {
				//... and forget it if it has been closed by the time we reach the new field.
				repeatingSectionStart = 0;
				repeatingSectionEnd = 0;
			}
		}
		
		if (repeatingSectionStart) {
			field.repeat_start_id = repeatingSectionStart;
		}
	}
	
	thus.tuix.pages[thus.currentPageId].fields[fieldId] = 1;
	thus.tuix.items[fieldId] = field;
	
	thus.loadFieldsList(thus.currentPageId);
	return fieldId;
};


methods.clickPage = function(pageId, isNewPage) {
	if (thus.editingThing == 'page' && thus.editingThingId == pageId) {
		return;
	}
	
	if (!thus.saveCurrentOpenDetails() || !thus.displayPageFieldOrderErrors()) {
		return;
	}
	
	//By clicking a page, we first show the fields on the page
	if (thus.currentPageId != pageId) {
		var stopAnimation = !thus.editingThing;
		thus.currentPageId = pageId;
		thus.editingThing = false;
		
		thus.loadPagesList();
		thus.loadFieldsList(pageId);
		thus.loadNewFieldsPanel(stopAnimation);
		
		//Complete both steps for new page
		if (isNewPage) {
			thus.clickPage(pageId);
		}
		
	//If we click the page again then we start editing the page
	} else {
		thus.editingThing = 'page';
		thus.editingThingId = pageId;
		thus.editingThingTUIXTabId = false;
		
		thus.tuix.form_page_details.tabs['details'].label = 'Step details';
		
		//Get a count of elements of the tuix pages object...
		var lastElementOrd = 0;
		Object.keys(thus.tuix.pages).forEach(function (item) {
			lastElementOrd++;
		});

		//... and find the last page.
		var lastPageId = 0;
		if (lastElementOrd > 0) {
			Object.values(thus.tuix.pages).forEach(function (item) {
				if (item.ord == lastElementOrd) {
					lastPageId = item.id;
				}
			});
		}

		//If this is the last page, check if it's always visible.
		//If it's not, and there is no summary page, show a visibility setting error.
		if (thus.currentPageId == lastPageId) {
			thus.tuix.form_page_details.tabs['details'].fields.visibility.note_below = "Please ensure the form settings are set to 'Enable summary step', in case this step is not visible.";
		} else {
			delete thus.tuix.form_page_details.tabs['details'].fields.visibility.note_below;
		}
		
		thus.openPageEdit(pageId);
	}
};

methods.clickField = function(fieldId, justAdded) {
	if ((thus.editingThing == 'field' && thus.editingThingId == fieldId) || thus.tuix.items[fieldId].type == 'repeat_end') {
		return;
	}
	
	if (!thus.saveCurrentOpenDetails()) {
		return;
	}
	
	var field = thus.getItem('field', fieldId);
	if (!justAdded && field._just_added) {
		delete(field._just_added);
	}
		
	thus.editingThing = 'field';
	thus.editingThingId = fieldId;
	thus.editingThingTUIXTabId = false;

	if (thus.tuix.items[fieldId].type == 'repeat_start') {
		thus.tuix.form_field_details.tabs['details'].label = 'Section details';
	} else {
		thus.tuix.form_field_details.tabs['details'].label = 'Field details';
	}
	
	thus.loadFieldsList(thus.currentPageId);
	thus.openFieldEdit(fieldId);
};

methods.openEdit = function(itemType, itemId, tuixTabId, stopAnimation) {
	thus.editingNameField = false;
	thus.editingNameFieldComplete = false;
	
	//Set left panel HTML
	var item = thus.getItem(itemType, itemId);
	var tuixMode = thus.getTUIXModeForItemType(itemType);
	var tuix = thus.tuix[tuixMode];
	var mergeFields = {
		name: item.name,
		hide_tab_bar: tuix.hide_tab_bar
	};
	
	if (itemType == 'page') {
		switch (item.visibility) {
			case 'visible':
				mergeFields.type = 'page_break';
				break;
			case 'visible_on_condition':
				mergeFields.type = 'page_break_visible_on_condition';
				break;
			case 'hidden':
				mergeFields.type = 'page_break_hidden';
				break;
		}
		
		mergeFields.mode = 'edit_page';
		item.type = mergeFields.type  ;
		
		//If a step was clicked for editing, and the last edited item was a field,
		//make sure the field is no longer highlighted.
		thus.loadFieldsList(thus.currentPageId);
	} else if (itemType == 'field') {
		mergeFields.type = item.type;
		mergeFields.mode = 'edit_field';
	}
	
	mergeFields.type_phrase = thus.getFieldReadableType(item);
	if (item.dataset_field_id) {
		mergeFields.type_phrase += ', linked field → ' + item.db_column;
	}
	
	mergeFields.status = thus.tuix.form.status;
	
	var html = thus.microTemplate('zenario_organizer_form_builder_left_panel', mergeFields);
	var $div = $('#organizer_form_builder .form_fields_palette .form_fields_palette_outer').html(html);
	
	//Set TUIX tabs HTML
	var tabs = thus.getTUIXTabs(tuix, tuixTabId, item);
	tuixTabId = thus.editingThingTUIXTabId; //Update current tab
	var html = thus.getTUIXTabsHTML(tabs);
	$('#organizer_field_details_tabs').html(html);
	
	thus.openItemTUIXTab(itemType, itemId, tuixTabId);
	
	//Animation
	if (!stopAnimation) {
		$div.hide().show('drop', {direction: 'left'}, 200);
	}
	
	
	//Events
	//Click a TUIX tab
	$('#organizer_field_details_tabs .tab').on('click', function() {
		var newTUIXTabId = $(this).data('id');
		if (newTUIXTabId && newTUIXTabId != tuixTabId) {
			if (thus.saveCurrentOpenDetails()) {
				thus.openEdit(itemType, itemId, newTUIXTabId, true);
			}
		}
	});
	
	//Click "Done" button
	$('#organizer_field_details_inner span.add_new_field').on('click', function() {
		if (thus.saveCurrentOpenDetails()) {
			thus.loadNewFieldsPanel();
			thus.loadFieldsList(thus.currentPageId);
		}
	});
	
	//Edit form settings
	$('input.form_settings').on('click', function() {
		thus.openFormSettings();
	});
	
	//Edit name field
	$('#zenario_field_details_header_content .edit_field_name_button').on('click', function() {
		$('#zenario_field_details_header_content .view_mode').hide();
		$('#zenario_field_details_header_content .edit_mode').show();
		thus.editingNameField = true;
	});
	$('#zenario_field_details_header_content .done_field_name_button').on('click', function() {
		$('#zenario_field_details_header_content .edit_mode').hide();
		$('#zenario_field_details_header_content .view_mode').show();
		
		thus.editingNameField = false;
		thus.editingNameFieldComplete = true;
		
		var name = $('#field__name').val();
		$('#zenario_field_details_header_content .view_mode h5').text(name);
	});
	$('#field__name').on('keyup', function() {
		thus.changeMadeToPanel();
		if (itemType == 'page') {
			var name = thus.formatPageLabel($(this).val());
			$('#organizer_form_tab_' + thus.currentPageId + ' span').text(name);
		}
	});
};

methods.deletePage = function(pageId) {
	var pages = thus.getOrderedPages();
	
	//Do not allow the final page to be deleted
	if (pages.length < 2) {
		return;
	}
	
	var fields = thus.getOrderedFields(pageId);
	for (var i = 0; i < pages.length; i++) {
		if (pages[i].id == pageId) {
			//Move all fields on deleted page to another
			if (pages[i - 1]) {
				var nextPageId = pages[i - 1].id;
			} else {
				var nextPageId = pages[i + 1].id;
			}
			thus.deletedPages.push(pageId);
			delete(thus.tuix.pages[pageId]);
			
			thus.clickPage(nextPageId);
			thus.changeMadeToPanel();
			break;
		}
	}
};

methods.deleteField = function(fieldId) {
	var field = thus.tuix.items[fieldId];
	var fields = thus.getOrderedFields(field.page_id);
	
	//Delete a repeat start's matching repeat end
	if (field.type == 'repeat_start') {
		var repeatEndId = thus.getMatchingRepeatEnd(fieldId);
		if (repeatEndId) {
			var repeatEndField = thus.tuix.items[repeatEndId];
			thus.deletedFields.push(repeatEndId);
			delete(thus.tuix.pages[repeatEndField.page_id].fields[repeatEndId]);
			delete(thus.tuix.items[repeatEndId]);
		}
	}
	
	//When deleting a dataset repeat, remove all fields inside as well.
	if (field.dataset_repeat_grouping && field.type == 'repeat_start') {
		for (var i = 0; i < fields.length; i++) {
			if (fields[i].dataset_repeat_grouping && fields[i].dataset_repeat_grouping == field.dataset_repeat_grouping && fields[i].type != 'repeat_start') {
				thus.deletedFields.push(fields[i].id);
				delete(thus.tuix.pages[field.page_id].fields[fields[i].id]);
				delete(thus.tuix.items[fields[i].id]);
			}
		}
	}
	
	//Select the next field if one exists
	var deletedFieldIndex = false;
	var nextFieldId = false;
	var fields = thus.getOrderedFields(field.page_id);
	for (var i = 0; i < fields.length; i++) {
		if (fields[i].id == fieldId) {
			deletedFieldIndex = i;
		}
		
		if (deletedFieldIndex !== false) {
			if (deletedFieldIndex > 0) {
				nextFieldId = fields[deletedFieldIndex - 1].id;
				break;
			} else if (fieldId != fields[i].id) {
				nextFieldId = fields[i].id;
				break;
			}
		}
	}
	if (nextFieldId && thus.tuix.items[nextFieldId].type == 'repeat_end') {
		nextFieldId = false;
	}
	
	thus.deletedFields.push(fieldId);
	delete(thus.tuix.pages[field.page_id].fields[fieldId]);
	delete(thus.tuix.items[fieldId]);
	
	thus.changeMadeToPanel();
	thus.loadFieldsList(field.page_id);
	
	if (nextFieldId) {
		thus.clickField(nextFieldId);
	} else {
		thus.loadNewFieldsPanel();
	}
};

methods.addTUIXTabEvents = function(itemType, itemId, tuixTabId) {
	var item = thus.getItem(itemType, itemId);
	var tuix = thus.tuix[thus.getTUIXModeForItemType(itemType)];
	
	if (itemType == 'page' && thus.tuix.form.status == 'active') {
		$('#organizer_remove_form_page').on('click', function(e) {
			e.stopPropagation();
			
			//Make sure we can delete this field
			if (!thus.saveCurrentOpenDetails()) {
				return;
			}
			
			var keys = {
				id: item.id,
				form_id: item.form_id,
				
				//Catch the case where an admin is trying to delete a step which has not been saved yet.
				step_name: item.name,
				step_fields: JSON.stringify(item.fields)
			};
			
			zenarioAB.open(
				'zenario_delete_form_step',
				keys,
				undefined, undefined,
				function() {
					thus.deletePage(item.id);
				}
			);
		});
		
	} else if (itemType == 'field') {
		if (tuixTabId == 'details') {
			$('#field__label').on('keyup', function() {
				$('#organizer_form_field_' + itemId + ' .label').text($(this).val());
				if (item._just_added && !thus.editingNameField && !thus.editingNameFieldComplete) {
					var fieldName = $(this).val().replace(/:/g, '');
					$('#field__name').val(fieldName);
					$('#field_display__name').text(fieldName);
				}
			});
			
			$('#field__note_to_user').on('keyup', function() {
				var value = $(this).val().trim();
				$('#organizer_form_field_note_below_' + itemId + ' div.zenario_note_content').text(value);
				$('#organizer_form_field_note_below_' + itemId).toggle(value !== '');
			});
			
			$('#field__placeholder').on('keyup', function() {
				$('#organizer_form_field_' + itemId + ' :input').prop('placeholder', $(this).val());
			});
			
			$('#field__description').on('keyup', function() {
				$('#organizer_form_field_' + itemId + ' .description').text($(this).val());
			});
			
			$('#edit_field_calculation').on('click', function() {
				//Get all numeric text fields
				var numericFields = {};
				var fields = thus.getOrderedFields();
				for (var i = 0; i < fields.length; i++) {
					var field = fields[i];
					if (
						(
							(field.type == 'text' && ['number', 'integer', 'floating_point'].indexOf(field.field_validation) != -1)
							|| (field.type == 'calculated' && field.id != itemId)
						)
						&& !field.repeat_start_id
					) {
						numericFields[field.id] = {label: field.name, ord: i};
					}
				}
				
				var key = {
					id: itemId, 
					title: 'Editing the calculation for the field "' + item.name + '"',
					calculation_code: JSON.stringify(item.calculation_code),
					form_status: thus.tuix.form.status
				};
				var values = {
					details: {
						dummy_field: JSON.stringify(numericFields)
					}
				};
				
				zenarioAB.open(
					'zenario_field_calculation', 
					key,
					undefined, values,
					function(key, values) {
						if (values.details.calculation_code) {
							item.calculation_code = JSON.parse(values.details.calculation_code);
						} else {
							item.calculation_code = '';
						}
						thus.tuixFieldDetailsChanged(itemType, itemId, tuixTabId, 'calculation_code');
					}
				);
			});
			
		} else if (tuixTabId == 'advanced') {
			$('#field__css_classes').on('keyup', function() {
				$('#organizer_form_field_' + itemId + ' .form_field_classes .css').toggle(!!$(this).val()).prop('title', $(this).val());
			});
			$('#field__div_wrap_class').on('keyup', function() {
				$('#organizer_form_field_' + itemId + ' .form_field_classes .div').toggle(!!$(this).val()).prop('title', $(this).val());
			});

			$('#field__rows').on('keyup', function() {
				$('#organizer_form_field_' + itemId + ' :input').attr("rows", $(this).val());
				
			});
			
			
		} else if (tuixTabId == 'values') {
			
			//Sorting
			$('#field_values_list').sortable({
				containment: 'parent',
				tolerance: 'pointer',
				axis: 'y',
				start: function(event, ui) {
					thus.startIndex = ui.item.index();
				},
				stop: function(event, ui) {
					if (thus.startIndex != ui.item.index()) {
						thus.saveFieldListOfValues(itemId);
						thus.loadFieldValuesListPreview(itemId);
						thus.changeMadeToPanel();
					}
				}
			});
			
			//Update labels on preview
			$('#field_values_list input').on('keyup', function() {
				var valueId = $(this).data('id');
				$('#organizer_field_value_' + valueId + ' label').text($(this).val());
				thus.changeMadeToPanel();
			});
			
			//Add new field value
			$('#organizer_add_a_field_value').on('click', function() {
				thus.addFieldValue(item);
				thus.saveTUIXTab(tuix, tuixTabId, item);
				thus.openItemTUIXTab(itemType, itemId, tuixTabId);
				thus.loadFieldValuesListPreview(itemId);
				thus.changeMadeToPanel();
			});
			
			//Delete field value
			$('#field_values_list .delete_icon').on('click', function() {
				var valueId = $(this).data('id');
				if (item.lov[valueId]) {
					thus.deletedValues.push(valueId);
					delete(item.lov[valueId]);
					delete(item.crm_lov[valueId]);
				}
				thus.saveTUIXTab(tuix, tuixTabId, item);
				thus.openItemTUIXTab(itemType, itemId, tuixTabId);
				thus.loadFieldValuesListPreview(itemId);
				thus.changeMadeToPanel();
			});
			
		} else if (tuixTabId == 'translations') {
			$('#organizer_field_translations input').on('keyup', function() {
				thus.changeMadeToPanel();
			});
			
		} else if (tuixTabId == 'crm') {
			$('#field__crm_validate_test').on('click', function() {
				//Save any changes
				thus.saveTUIXTab(tuix, tuixTabId, item);
				var itemJSON = JSON.stringify(item);
				
				//Send item details to be validated by salesforce
				var actionRequests = {
					mode: 'validate_salesforce_field',
					item: itemJSON
				};
				thus.sendAJAXRequest(actionRequests, function(response) {
					//Validation successfull
					if (response === true) {
						var notices = ['Field is valid.'];
						thus.openItemTUIXTab(itemType, itemId, thus.editingThingTUIXTabId, undefined, undefined, notices);
						
					//Validation could not be completed
					} else if (response === false) {
						var errors = ['Something went wrong. Validation could not be completed.'];
						thus.openItemTUIXTab(itemType, itemId, thus.editingThingTUIXTabId, errors);
						
					//Validation failed
					} else if (response.error) {
						var errors = [];
						if (response.error == 'missing_values') {
							for (var i = 0; i < response.values.length; i++) {
								errors.push('Field value not found: "' + response.values[i] + '"');
							}
						} else if (response.error == 'not_found') {
							errors.push('Field not found.');
						} else if (response.error == 'too_many_values') {
							errors.push('Too many values to load from Salesforce.')
						} else {
							errors.push('Unknown error.');
						}
						thus.openItemTUIXTab(itemType, itemId, thus.editingThingTUIXTabId, errors);
					}
				});
			});
			
			//Swap CRM values and labels around for centralised lists
			$('#organizer_crm_button__set_labels').on('click', function() {
				thus.changeMadeToPanel();
				$('#organizer_field_crm_values input.crm_value_input').each(function(i, e) {
					var valueId = $(this).data('id');
					var value = '';
					if (item.lov && item.lov[valueId]) {
						value = item.lov[valueId].label;
					}
					$(this).val(value);
				});
			});
			$('#organizer_crm_button__set_values').on('click', function() {
				thus.changeMadeToPanel();
				$('#organizer_field_crm_values input.crm_value_input').each(function(i, e) {
					$(this).val($(this).data('id'));
				});
			});
			
			$('#organizer_field_crm_values input.crm_value_input').on('keyup', function() {
				thus.changeMadeToPanel();
			});
		}
	}
};

methods.loadFieldsList = function(pageId) {
	//Load HTML
	var fields = thus.getOrderedMergeFieldsForFields(pageId);
	var mergeFields = {fields: fields};
	var html = thus.microTemplate('zenario_organizer_form_builder_section', mergeFields);
	$('#organizer_form_fields').html(html);
	
	//Add events
	
	//Click on a field
	$('#organizer_form_fields div.form_field').on('click', function() {
		var fieldId = $(this).data('id');
		if (thus.tuix.items[fieldId]) {
			thus.clickField(fieldId);
		}
	});
	
	//Show information on hover
	var hoverTimeoutId;
	$('#organizer_form_fields div.form_field').hover(
		//mouseover
		function() {
			var that = this;
			if (!hoverTimeoutId) {
				hoverTimeoutId = setTimeout(function() {
					hoverTimeoutId = null;
					var fieldId = $(that).data('id');
					$('#organizer_form_field_' + fieldId + ' .form_field_classes').show();
				}, 200)
			}
		//mouseout
		}, function() {
			if (hoverTimeoutId) {
				clearTimeout(hoverTimeoutId);
				hoverTimeoutId = null;
			} else {
				var fieldId = $(this).data('id');
				if (thus.editingThing == 'field' && fieldId != thus.editingThingId) {
					$('#organizer_form_field_' + fieldId + ' .form_field_classes').hide();
				}
			}
		}
	);
	$('#organizer_form_builder').tooltip();
	
	if (thus.tuix.form.status == 'active') {
		//Make fields sortable
		$('#organizer_form_fields .form_section').sortable({
			items: 'div.is_sortable',
			tolerance: 'pointer',
			placeholder: 'preview',
			//Add new field to the form
			receive: function(event, ui) {
				$(this).find('div.field_type, div.dataset_field').each(function() {
					var fieldType = $(this).data('type');
					var datasetFieldId = $(this).data('id');
					var centralisedSource = $(this).data('source');
					var centralisedSourceLabel = $(this).data('label');
					var ord = 0.1;
					var previousFieldId = $(this).prev().data('id');
					if (previousFieldId && thus.tuix.items[previousFieldId]) {
						ord = thus.tuix.items[previousFieldId].ord + 0.1;
					} else {
						var nextFieldId = $(this).next().data('id');
						if (nextFieldId && thus.tuix.items[nextFieldId]) {
							ord = thus.tuix.items[nextFieldId].ord - 0.1;
						}
					}
					
					var fieldId = thus.createField(fieldType, ord, datasetFieldId, 0, centralisedSource, centralisedSourceLabel);
					thus.clickField(fieldId, true);
					thus.updateFieldOrds();
				});
			},
			start: function(event, ui) {
				thus.startIndex = ui.item.index();
			},
			//Detect reorder/new/deleted fields
			stop: function(event, ui) {
				if (thus.startIndex != ui.item.index()) {
					thus.tuix.pages[pageId].fields_reordered = true;
					//Update ordinals
					thus.updateFieldOrds();
					//Redraw fields for indenting
					thus.loadFieldsList(pageId);
				}
			}
		});
		
		//Delete a field
		$('#organizer_form_fields .delete_icon').on('click', function(e) {
			e.stopPropagation();
			var fieldId = $(this).data('id');
			
			//Make sure we can delete this field
			if (!thus.saveCurrentOpenDetails(true)) {
				return;
			}
			
			var field = thus.tuix.items[fieldId];
			var transferFields = {};
			
			//Data can be transfered to fields of the same type
			//Groups can have their data moved into checkbox fields also
			var fields = thus.getOrderedFields();
			for (var i = 0; i < fields.length; i++) {
				if ((field.type == fields[i].type || (field.type == 'group' && fields[i].type == 'checkbox')) && fieldId != fields[i].id ) {
					transferFields[fields[i].id] = fields[i].name;
				}
			}
			
			var keys = {
				id: fieldId,
				field_name: field.name,
				field_type: field.type,
				field_english_type: thus.getFieldReadableType(field)
			};
			//Pass the fields this responses can be transfered to a dummy field via values because this may be too large for the key
			//which is passed in the URL
			var values = {details: {dummy_field: JSON.stringify(transferFields)}};
			zenarioAB.open(
				'zenario_delete_form_field',
				keys,
				undefined, values,
				function(key, values) {
					//Migrate data to another field
					var migrateResponsesTo = undefined;
					if (values.details.delete_field_options == 'delete_field_but_migrate_data' 
						&& values.details.migration_field
					) {
						if (thus.tuix.items[values.details.migration_field]) {
							thus.tuix.items[values.details.migration_field]._migrate_responses_from = fieldId;
						}
					}
					thus.deleteField(fieldId);
				}
			);
		});
		//Duplicate a field
		$('#organizer_form_fields .duplicate_icon').on('click', function(e) {
			e.stopPropagation();
			var fieldId = $(this).data('id');
			if (thus.saveCurrentOpenDetails()) {
				var field = thus.getItem('field', fieldId);
				var message = '<p>Duplicate the field "' + field.name + '"?</p>';
				zenarioA.floatingBox(message, 'Duplicate', 'warning', true, false, undefined, undefined, function() {
					var newFieldId = thus.createField(undefined, field.ord + 0.1, undefined, fieldId);
					thus.clickField(newFieldId, true);
					thus.updateFieldOrds();
				});
			}
		});
		
		//Update a dataset repeat field
		$('#organizer_form_fields .update_repeat_field_icon').on('click', function(e) {
			e.stopPropagation();
			var repeatFieldId = $(this).data('id');
			var repeatField = thus.getItem('field', repeatFieldId);
			
			if (!thus.saveCurrentOpenDetails()) {
				return;
			}
			
			var message = '<p>Update this repeating field?</p>';
			zenarioA.floatingBox(message, 'Update', 'warning', true, false, undefined, undefined, function() {
				
				var datasetRepeatFieldId = repeatField.dataset_field_id;
				var datasetRepeatField = thus.tuix.dataset.fields[datasetRepeatFieldId];
				
				//Add / remove / reorder fields
				var formRepeatFields = [];
				var datasetRepeatFields = [];
				
				//Get form fields inside dataset repeat
				var fields = thus.getOrderedFields(thus.currentPageId);
				for (var i = 0; i < fields.length; i++) {
					if (fields[i].dataset_repeat_grouping == datasetRepeatFieldId && fields[i].type != 'repeat_end' && fields[i].type != 'repeat_start') {
						formRepeatFields.push(fields[i].id);
					}
				}
				
				//Get dataset fields inside dataset repeat
				foreach (thus.tuix.dataset.tabs[datasetRepeatField.tab_name].fields as var datasetFieldId => var x) {
					var datasetField = thus.tuix.dataset.fields[datasetFieldId];
					if (datasetField.repeat_start_id == datasetRepeatFieldId && datasetField.type != 'repeat_end') {
						datasetRepeatFields.push(datasetField);
					}
				}
				datasetRepeatFields.sort(thus.sortByOrd);
				
				//Add new fields and update ordinals
				var ord = repeatField.ord;
				for (var i = 0; i < datasetRepeatFields.length; i++) {
					var found = false;
					for (var j = 0; j < formRepeatFields.length; j++) {
						var formRepeatField = thus.getItem('field', formRepeatFields[j]);
						if (datasetRepeatFields[i].id == formRepeatField.dataset_field_id) {
							thus.tuix.items[formRepeatFields[j]].ord = ord + (datasetRepeatFields[i].ord / 1000);
							found = true;
							break;
						}
					}
					if (!found) {
						datasetRepeatFields[i].dataset_repeat_grouping = datasetRepeatField.id;
						thus.createField(undefined, ord + (datasetRepeatFields[i].ord / 1000), datasetRepeatFields[i].id);
					}
				}
		
				//Remove fields this no longer exist
				for (var i = 0; i < formRepeatFields.length; i++) {
					var found = false;
					for (var j = 0; j < datasetRepeatFields.length; j++) {
						if (thus.tuix.items[formRepeatFields[i]].dataset_field_id == datasetRepeatFields[j].id) {
							found = true;
						}
					}
					if (!found) {
						thus.deleteField(formRepeatFields[i]);
					}
				}
				
				//Update display
				thus.tuix.pages[thus.currentPageId].fields_reordered = true;
				thus.loadFieldsList(thus.currentPageId);
				thus.updateFieldOrds();
				thus.changeMadeToPanel();
			});
		});
	}
};

methods.updateFieldOrds = function() {	
	$('#organizer_form_fields div.form_field').each(function(i) {
		var fieldId = $(this).data('id');
		if (fieldId) {
			thus.tuix.items[fieldId].ord = (i + 1);
		}
	});
	thus.changeMadeToPanel();
};

methods.loadNewFieldsPanel = function(stopAnimation) {
	thus.editingThing = false;
	
	//Load HTML
	var mergeFields = {
		mode: 'new_fields',
		link_to_dataset: thus.tuix.link_to_dataset,
		datasetTabs: thus.getOrderedMergeFieldsForDatasetFields(),
		centralised_lists: thus.tuix.centralised_lists.values
	};
	
	var html = thus.microTemplate('zenario_organizer_form_builder_left_panel', mergeFields);
	var $div = $('#organizer_form_builder .form_fields_palette .form_fields_palette_outer').html(html);
	
	if (!stopAnimation) {
		$div.hide().show('drop', {direction: 'right'}, 200);
	}
	
	//Add events. Skip this if the form is archived.
	
	if (thus.tuix.form.status == 'active') {
		//Allow fields to be dragged onto list
		$('#organizer_field_type_list div.field_type, #organizer_centralised_field_type_list div.field_type, #organizer_linked_field_type_list div.dataset_field').draggable({
			connectToSortable: '#organizer_form_fields .form_section',
			appendTo: '#organizer_form_builder',
			helper: 'clone'
		});
	}
	
	//Edit form settings
	$('input.form_settings').on('click', function() {
		thus.openFormSettings();
	});
};


//Similar to PHP method formatAdminBox
methods.formatTUIX = function(itemType, item, tab, tags, changedFieldId) {
	
	//Visibility selector (available to both pages and fields)
	if (tab == 'details' ) {
		if (itemType == 'field') {
			tags.tabs[tab].fields.visible_condition_field_is_not_in_the_same_repeating_section.hidden =
			tags.tabs[tab].fields.visible_condition_field_is_at_a_different_step.hidden =
			tags.tabs[tab].fields.visible_condition_field_is_after_the_current_field.hidden = true;
		}
		
		if (item.visibility && item.visibility == 'visible_on_condition' && item.visible_condition_field_id) {
			var conditionField = thus.getItem('field', item.visible_condition_field_id);
			if (conditionField) {
				if (conditionField.type != 'checkboxes' && conditionField.type != 'checkbox' && conditionField.type != 'group') {
					tags.tabs[tab].fields.visible_condition_field_type.values.visible_if_one_of = {label: 'Visible if one of...'};
					tags.tabs[tab].fields.visible_condition_field_value.empty_value = '-- Any value --';
					tags.tabs[tab].fields.visible_condition_field_value.values = JSON.parse(JSON.stringify(conditionField.lov));
				
					if (item.visible_condition_field_type == 'visible_if_one_of') {
						tags.tabs[tab].fields.visible_condition_field_value.hidden = true;
						tags.tabs[tab].fields.visible_condition_checkboxes_field_value.hidden = false;
					}
				}
			
				if (conditionField.type == 'checkboxes') {
					tags.tabs[tab].fields.visible_condition_field_value.hidden = true;
					tags.tabs[tab].fields.visible_condition_checkboxes_operator.hidden = false;
					tags.tabs[tab].fields.visible_condition_checkboxes_field_value.hidden = false;
				}
			
				if (conditionField.type != 'checkbox' && conditionField.type != 'group') {
					tags.tabs[tab].fields.visible_condition_checkboxes_field_value.values = JSON.parse(JSON.stringify(conditionField.lov));
				}
				
				if (itemType == 'field') {
					//Show a warning in certain situations
					var currentFieldOrdinal = item.ord;
					
					var currentFieldStepId = item.page_id;
					var currentFieldStepOrdinal = thus.tuix.pages[currentFieldStepId].ord;
					
					var conditionalFieldOrdinal = conditionField.ord;
					
					var conditionalFieldStepId = conditionField.page_id;
					var conditionalFieldStepOrdinal = thus.tuix.pages[conditionalFieldStepId].ord;
					
					var errorAlreadySet = false;
					if (item.repeat_start_id) {
						var repeatingSectionId = item.repeat_start_id;
						foreach (thus.tuix.items as var fieldId => var field) {
							if (fieldId == item.visible_condition_field_id) {
								if (!item.repeat_start_id || field.repeat_start_id != item.repeat_start_id) {
									tags.tabs[tab].fields.visible_condition_field_is_not_in_the_same_repeating_section.hidden = false;
									errorAlreadySet = true;
									break;
								}
							}
						}
					} else {
						if (thus.tuix.pages[currentFieldStepId] && thus.tuix.pages[currentFieldStepId].visibility == 'visible_on_condition') {
							//If this field is on a step that is visible on condition,
							//AND the field itself is also visible on condition,
							//but its conditional field is on yet another step, show a warning.
							if (conditionalFieldStepOrdinal != currentFieldStepOrdinal) {
								tags.tabs[tab].fields.visible_condition_field_is_at_a_different_step.hidden = false;
								errorAlreadySet = true;
							}
						}
					}
					
					if (!errorAlreadySet) {
						if (conditionalFieldStepId != currentFieldStepId && conditionalFieldStepOrdinal > currentFieldStepOrdinal) {
							tags.tabs[tab].fields.visible_condition_field_is_at_a_different_step.hidden = false;
						} else if (conditionalFieldStepId == currentFieldStepId && conditionalFieldOrdinal > currentFieldOrdinal) {
							tags.tabs[tab].fields.visible_condition_field_is_after_the_current_field.hidden = false;
						}
					}
				}
			}
		}
	}
	
	if (itemType == 'page') {
		switch (tab) {
			case 'details':
				//Hide previous/next button fields on first/last pages
				var pages = thus.getOrderedPages();
				for (var i = 0; i < pages.length; i++) {
					if (pages[i].id == item.id) {
						if (i == 0) {
							tags.tabs[tab].fields.previous_button_text.hidden = true;
						} else if (i == (pages.length - 1) && !thus.tuix.form_enable_summary_page) {
							tags.tabs[tab].fields.next_button_text.hidden = true;
						}
						break;
					}
				}
				
				//Reload pages list to get visibility styles
				thus.loadPagesList();
				break;
		}
	} else if (itemType == 'field') {
		switch (tab) {
			case 'details':
				//Show and update values source label
				if (item.values_source && thus.tuix.centralised_lists.values[item.values_source]) {
					var list = thus.tuix.centralised_lists.values[item.values_source];
					if (!list.info.can_filter) {
						tags.tabs[tab].fields.values_source_filter.hidden = true;
					} else {
						tags.tabs[tab].fields.values_source_filter.label = list.info.filter_label;
					}
				}
				
				//Readonly / mandatory selector
				if (item.readonly_or_mandatory && item.readonly_or_mandatory == 'conditional_mandatory' && item.mandatory_condition_field_id) {
					var conditionField = thus.getItem('field', item.mandatory_condition_field_id);
					if (conditionField) {
						if (conditionField.type == 'checkboxes') {
							tags.tabs[tab].fields.mandatory_condition_checkboxes_field_value.values = JSON.parse(JSON.stringify(conditionField.lov));
							tags.tabs[tab].fields.mandatory_condition_field_value.hidden = true;
							tags.tabs[tab].fields.mandatory_condition_checkboxes_operator.hidden = false;
						} else {
							tags.tabs[tab].fields.mandatory_condition_checkboxes_field_value.hidden = true;
							if (conditionField.type != 'checkbox' && conditionField.type != 'group') {
							    tags.tabs[tab].fields.mandatory_condition_field_type.values.mandatory_if_one_of = {label: 'Mandatory if at least one of...'};
								tags.tabs[tab].fields.mandatory_condition_field_value.values = JSON.parse(JSON.stringify(conditionField.lov));
								tags.tabs[tab].fields.mandatory_condition_field_value.empty_value = '-- Any value --';
								if (item.mandatory_condition_field_type == 'mandatory_if_one_of') {
                                    tags.tabs[tab].fields.mandatory_condition_field_value.hidden = true;
                                    tags.tabs[tab].fields.mandatory_condition_checkboxes_field_value.values = JSON.parse(JSON.stringify(conditionField.lov));
                                    tags.tabs[tab].fields.mandatory_condition_checkboxes_field_value.hidden = false;
                                }
							}
						}
					}
				}
				
				//Default validation error messages
				if (changedFieldId == 'field_validation') {
					if (item.field_validation == 'name') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'Please enter a valid name. Don\'t include < or > characters.';
					} else if (item.field_validation == 'email') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'The email address you have entered is not valid, please enter a valid email address.';
					} else if (item.field_validation == 'URL') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'Please enter a valid URL.';
					} else if (item.field_validation == 'number') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'Please enter a valid number.';
					} else if (item.field_validation == 'phone_number') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'Please enter a valid phone number, which may contain 0-9 + - ( ) and spaces.';
					} else if (item.field_validation == 'integer') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'Please enter a valid integer.';
					} else if (item.field_validation == 'floating_point') {
						tags.tabs[tab].fields.field_validation_error_message.value = 'Please enter a valid floating point number.';
					}
					
					$('#organizer_form_field_' + item.id + ' .form_field_classes .validation').toggle(item.field_validation && item.field_validation != 'none');
					
				} else if (changedFieldId == 'visibility') {
					var title = '';
					if (item.visibility == 'hidden') {
						title = 'Hidden';
					} else if (item.visibility == 'visible_on_condition') {
						title = 'Visible on condition';
					}
					$('#organizer_form_field_' + item.id + ' .form_field_classes .not_visible').toggle(item.visibility != 'visible').prop('title', title);
					
				} else if (changedFieldId == 'values_source') {
					if (item.values_source) {
						var actionRequests = {
							mode: 'get_centralised_lov',
							method: item.values_source
						};
						if (thus.tuix.centralised_lists.values[item.values_source].info.can_filter) {
							actionRequests.filter = item.values_source_filter;
						}
						thus.sendAJAXRequest(actionRequests, function(lov) {
							item.lov = lov;
							thus.loadFieldValuesListPreview(item.id);
						});
					} else {
						item.lov = {};
						thus.loadFieldValuesListPreview(item.id);
					}
				}
				
				if (changedFieldId == 'field_validation' || changedFieldId == 'show_field_twice_for_confirmation') {
					if (item.field_validation == 'email' && item.show_field_twice_for_confirmation) {
						if (!tags.tabs[tab].fields.confirmation_field_error_message.value) {
							tags.tabs[tab].fields.confirmation_field_error_message.value = 'The email addresses you have entered do not match.';
						}
						
						if (!tags.tabs[tab].fields.confirmation_field_label.value) {
							tags.tabs[tab].fields.confirmation_field_label.value = tags.tabs[tab].fields.label.value + ' (confirm)';
						}
					}
				}
				
				
				//Update calculation code preview
				if (item.type == 'calculated') {
					var displayHTML = false;
					if (item.calculation_code) {
						tags.tabs[tab].fields.calculation_code.value = thus.getCalculationCodeDisplay(item.calculation_code, displayHTML);
					}
				}
				
				//Disable some options for dataset fields
				if (item.dataset_field_id) {
					tags.tabs[tab].fields.values_source.readonly = true;
					tags.tabs[tab].fields.values_source_filter.readonly = true;
					tags.tabs[tab].fields.min_rows.readonly = true;
					tags.tabs[tab].fields.max_rows.readonly = true;
				}
				
				if (item.type == 'repeat_start') {
					tags.tabs[tab].fields.label.label = 'Section heading:';
					tags.tabs[tab].fields.label.note_below = 'This will be the heading at the start of the repeating section.';
				}
				break;
				
			case 'advanced':
				if (item.type == 'select') {
					tags.tabs[tab].fields.default_value_options.label = 'Pre-select field:';
				}
				
				if (item.type == 'date') {
					tags.tabs[tab].fields.default_value_text.note_below = 'Enter a value to pre-populate this field. Use the format yyyy-mm-dd.';
				} else {
					tags.tabs[tab].fields.default_value_text.note_below = 'Enter a value to pre-populate this field.';
				}
				
				//Update default values list for list type fields (defaults to checkbox values)
				if (['radios', 'centralised_radios', 'select', 'centralised_select'].indexOf(item.type) != -1 && item.lov) {
					tags.tabs[tab].fields.default_value_lov.values = JSON.parse(JSON.stringify(item.lov));
				}
				
				if (item.custom_code_name) {
					tags.tabs[tab].fields.merge_name.snippet.html = '<div><b>Merge names:</b> ' + htmlspecialchars(item.custom_code_name) + ', ' + thus.getFormFieldMergeName(item.id) + '</div>';
				} else {
					tags.tabs[tab].fields.merge_name.snippet.html = '<div><b>Merge name:</b> ' + thus.getFormFieldMergeName(item.id) + '</div>';
				}
				
				break;
			
			case 'values':
				if (item.dataset_field_id && item.type != 'text') {
					tags.tabs[tab].fields.values.readonly = true;
				}
				
				if (item.db_column == 'salutation') {
					for (var i in tags.tabs[tab].fields.suggested_values_source.values) {
						if (i != 'zenario_common_features::getSalutations') {
							delete(tags.tabs[tab].fields.suggested_values_source.values[i]);
						}
					}
					
					tags.tabs[tab].fields.suggested_values_source.note_below = '<a href="' + thus.tuix.link + 'organizer.php?#zenario__languages/panels/salutations" target="_blank">Manage list of salutations</a>';
				}
				break;
		}
	}
};

//Similar to PHP method validateAdminBox
methods.validateTUIX = function(itemType, item, tab, tags) {
	if (!item.name) {
		tags.tabs[tab].fields.name.error = 'Please enter a name.';
	}
	
	//Visibility selector validation (available to both pages and fields)
	if (tab == 'details') {
		if (item.visibility && item.visibility == 'visible_on_condition') {
			if (!item.visible_condition_field_id) {
				tags.tabs[tab].fields.visible_condition_field_id.error = 'Please select a field on which its visibility is conditional.';
			} else if (!item.visible_condition_field_value) {
				var conditionField = thus.getItem('field', item.visible_condition_field_id);
				if (conditionField && (conditionField.type == 'checkbox' || conditionField.type == 'group')) {
					tags.tabs[tab].fields.visible_condition_field_value.error = 'Please select a field value on which its visiblity is conditional.';
				}
			}
		}
	}
	
	if (itemType == 'field') {
		switch (tab) {
			case 'details':
				if (item.type == 'checkbox' || item.type == 'group') {
					if (!item.label) {
						tags.tabs[tab].fields.label.error = 'Please enter a label for this checkbox.';
					}
				} else if (item.type == 'repeat_start') {
					if (!item.min_rows) {
						tags.tabs[tab].fields.min_rows.error = 'Please enter the minimum rows.';
					} else if (+item.min_rows != item.min_rows) {
						tags.tabs[tab].fields.min_rows.error = 'Please a valid number for mininum rows.';
					} else if (item.min_rows < 1 || item.min_rows > 10) {
						tags.tabs[tab].fields.min_rows.error = 'Mininum rows must be between 1 and 10.';
					} else if (+item.min_rows > +item.max_rows) {
						tags.tabs[tab].fields.min_rows.error = 'Minimum rows cannot be greater than maximum rows.'
					}
				
					if (!item.max_rows) {
						tags.tabs[tab].fields.max_rows.error = 'Please enter the maximum rows.';
					} else if (+item.max_rows != item.max_rows) {
						tags.tabs[tab].fields.max_rows.error = 'Please a valid number for maximum rows.';
					} else if (item.max_rows < 1 || item.max_rows > 20) {
						tags.tabs[tab].fields.max_rows.error = 'Maximum rows must be between 1 and 20.';
					}
				} else if (item.type == 'restatement') {
					if (!item.restatement_field) {
						tags.tabs[tab].fields.restatement_field.error = 'Please select the field to mirror.';
					}
				} else if (item.type == 'centralised_radios' || item.type == 'centralised_select') {
					if (!item.values_source) {
						tags.tabs[tab].fields.values_source.error = 'Please select a values source.';
					}
				}
				
				if (item.readonly_or_mandatory) {
					if ((item.readonly_or_mandatory == 'mandatory' || item.readonly_or_mandatory == 'conditional_mandatory' || item.readonly_or_mandatory == 'mandatory_if_visible') && !item.required_error_message) {
						tags.tabs[tab].fields.required_error_message.error = 'Please enter an error message when this field is incomplete.';
					}
				
					if (item.readonly_or_mandatory == 'mandatory') {
						if (item.visibility == 'hidden') {
							tags.tabs[tab].fields.readonly_or_mandatory.error = 'A field cannot be mandatory while hidden.';
						} else if (item.visibility == 'visible_on_condition') {
							tags.tabs[tab].fields.readonly_or_mandatory.error = "This field is marked as mandatory, but is only visible based on a condition. Either: change this field to be visible (without condition); or mandatory on condition, with the same condition as that on which visibility depends.";
						}
					} else if (item.readonly_or_mandatory == 'conditional_mandatory') {
						if (!item.mandatory_condition_field_id) {
							tags.tabs[tab].fields.mandatory_condition_field_id.error = 'Please select a mandatory on condition form field.';
						} else if (!item.mandatory_condition_field_value) {
							var conditionField = thus.getItem('field', item.mandatory_condition_field_id);
							if (conditionField && ['checkbox', 'group'].indexOf(conditionField.type) != -1) {
								tags.tabs[tab].fields.mandatory_condition_field_value.error = 'Please select a mandatory on condition form field value.';
							}
						}
						if (item.visibility == 'hidden') {
							tags.tabs[tab].fields.visibility.error = 'A field cannot be mandatory while hidden.';
						}else if(item.visible_condition_field_type == "visible_if_one_of" && item.visible_condition_field_id!="" && _.isEmpty(item.visible_condition_checkboxes_field_value)){
						    tags.tabs[tab].fields.visibility.error = "Please select a checkbox for visibility condition.";

					    }else if(item.visible_condition_field_type == "visible_if_one_of" && item.mandatory_condition_field_type != "mandatory_if_one_of") {
					        error = 0;
					        switch(item.mandatory_condition_field_type) {
					            case "mandatory_if_not":
                                    if( (item.mandatory_condition_field_value=="" && !_.isEmpty(item.visible_condition_checkboxes_field_value)) 
                                    || (item.mandatory_condition_field_value=="" && _.isEmpty(item.visible_condition_checkboxes_field_value))
                                    || (!_.contains(item.visible_condition_checkboxes_field_value,item.mandatory_condition_field_value)) ){
                                        error = 1;
                                    }
                                    break;
                                    
                                case "mandatory_if":
                                    if(item.mandatory_condition_field_value==""){
                                        //any value
                                        error = 1;
                                    } else if(item.visible_condition_checkboxes_field_value){
                                        if(_.contains(item.visible_condition_checkboxes_field_value,item.mandatory_condition_field_value)){
                                            error = 0;
                                        } else {
                                            error = 1;
                                        }
                                    } 
                                    break;
                            
                                default:
                                    break;    
					        }
					        if(error == 1) {
					            tags.tabs[tab].fields.visibility.error = "A field cannot be mandatory while hidden. If this field is both mandatory and visible on a condition, both fields and values must be the same.";
					        }
					    
					    }
					    else if(item.mandatory_condition_field_type == "mandatory_if_one_of"){
                            error = 0;
                            if(_.isEmpty(item.mandatory_condition_checkboxes_field_value) && item.mandatory_condition_field_id!=""){
                                tags.tabs[tab].fields.mandatory_condition_field_value.error = "Please select a checkbox for mandatory condition.";
                            }
                            else {
                                if(item.visibility =='visible') {
                                     error =0;
                                }
                                else if(item.visible_condition_field_id != item.mandatory_condition_field_id){
                                    error = 1;
                                } else{
                                    switch(item.visible_condition_field_type) {
                                        case "visible_if_one_of":
                                            if(item.visible_condition_checkboxes_field_value!= ''){
                                                if(item.mandatory_condition_checkboxes_field_value){
                                                    for (i = 0; i < item.mandatory_condition_checkboxes_field_value.length; i++) {
                                                        if(!_.contains(item.visible_condition_checkboxes_field_value,item.mandatory_condition_checkboxes_field_value[i])){
                                                            error = 1;
                                                            break;
                                                        }
                                                    }
                                                }
                                            }
                                            break;
                                
                                        case "visible_if_not":
                                            if( (item.visible_condition_field_value=="" && !_.isEmpty(item.mandatory_condition_checkboxes_field_value)) 
                                            || (item.visible_condition_field_value=="" && _.isEmpty(item.mandatory_condition_checkboxes_field_value))
                                            || (_.contains(item.mandatory_condition_checkboxes_field_value, item.visible_condition_field_value)) ){
                                                error = 1;
                                            }
                                            break;
                                    
                                        case "visible_if":
                                            if(item.visible_condition_field_value==""){
                                                //any value
                                            }
                                            else if(item.mandatory_condition_checkboxes_field_value && item.mandatory_condition_checkboxes_field_value.length!=1){
                                                error = 1;
                                            } else if(item.mandatory_condition_checkboxes_field_value){
                                                for (i = 0; i < item.mandatory_condition_checkboxes_field_value.length; i++) {
                                                    if(item.mandatory_condition_checkboxes_field_value[i] != item.visible_condition_field_value){
                                                        error = 1;
                                                        break;
                                                    }
                                                }
                                            } 
                                            break;
                                    
                                        default:
                                            break;    
                        
                                    }
                                }
                                if(error != 0){
                                     tags.tabs[tab].fields.mandatory_condition_field_value.error = 'A field cannot be mandatory while hidden. If this field is both mandatory and visible on a condition, both fields and values must be the same.';
                                }
                            }
                        }  else if (item.visibility == 'visible_on_condition' && item.readonly_or_mandatory == 'conditional_mandatory'
                            && item.visible_condition_field_id && item.mandatory_condition_field_id
                            && ((item.visible_condition_field_id != item.mandatory_condition_field_id)
                                || item.visible_condition_field_type == 'visible_if' && item.mandatory_condition_field_type == 'mandatory_if_not'
                                || item.visible_condition_field_type == 'visible_if_not' && item.mandatory_condition_field_type == 'mandatory_if'
                                || ((conditionField = thus.getItem('field', item.mandatory_condition_field_id))
                                    && (conditionField.type != 'checkboxes'
                                        && (item.visible_condition_field_value != item.mandatory_condition_field_value)
                                    )
                                    || (conditionField.type == 'checkboxes'
                                        && (item.visible_condition_checkboxes_operator != item.mandatory_condition_checkboxes_operator
                                            || !_.isEqual(item.visible_condition_checkboxes_field_value, item.mandatory_condition_checkboxes_field_value)
                                        )
                                    )
                                )
                            )
                        ) {
                        
                               tags.tabs[tab].fields.visibility.error = 'A field cannot be mandatory while hidden. If this field is both mandatory and visible on a condition, both fields and values must be the same.';

                        
                          }
                    }
                }
				
				if (item.field_validation && item.field_validation != 'none') {
					if (!item.field_validation_error_message) {
						tags.tabs[tab].fields.field_validation_error_message.error = 'Please enter a validation error message for this field.';
					}
					
					if (item.field_validation == 'email' && item.show_field_twice_for_confirmation) {
						if (!item.confirmation_field_label) {
							tags.tabs[tab].fields.confirmation_field_label.error = 'Please enter the confirmation field label.';
						}
						
						if (!item.confirmation_field_error_message) {
							tags.tabs[tab].fields.confirmation_field_error_message.error = 'Please enter a confirmation error message for this field.';
						}
					}
				}
				
				if (item.type == 'text' && item.field_validation && ['number', 'integer', 'floating_point'].indexOf(item.field_validation) == -1) {
					var formFields = thus.getOrderedFields(); 
					for (var i = 0; i < formFields.length; i++) {
						var field = formFields[i];
						if (field.type == 'calculated' && field.calculation_code) {
							for (j = 0; j < field.calculation_code.length; j++) {
								if (field.calculation_code[j].type == 'field' && field.calculation_code[j].value == item.id) {
									tags.tabs[tab].fields.field_validation.error = 'The field "' + field.name + '" requires this field to be numeric. You must first remove this from this field.';
									break;
								}
							}
						}
					}
				}
				
				//If this is the first name, last name or email field from the "Users" dataset,
				//it will need to use a specific type of validation. Only for visible and editable fields.
				if (item.type == 'text' && item.visibility != 'hidden' && item.readonly_or_mandatory != 'readonly') {
					if (item.db_column == 'first_name' || item.db_column == 'last_name') {
						if (!item.field_validation || item.field_validation != 'name') {
							tags.tabs[tab].fields.field_validation.error = 'A name field must use the validation type "Name".';
						}
					} else if (item.db_column == 'email') {
						if (!item.field_validation || item.field_validation != 'email') {
							tags.tabs[tab].fields.field_validation.error = 'An email field must use the validation type "Email".';
						}
					}
				}
				break;
			
			case 'values':
				if (item.enable_suggested_values) {
					if (item.suggested_values_type == 'pre_defined' && !item.suggested_values_source) {
						tags.tabs[tab].fields.suggested_values_source.error = 'Please select a values source.';
					} else if (item.suggested_values_type == 'custom' && (!item.lov || Object.keys(item.lov).length == 0)) {
						tags.tabs[tab].fields.values.error = 'Please add at least one value.';
					}
				}
				break;
			
			case 'advanced':
				if (item.default_value_options) {
					if (item.default_value_options == 'value') {
						if (!item.default_value_lov && !item.default_value_text) {
							field.default_value.error = 'Please enter a default value.';
						}
					} else if (item.default_value_options == 'method') {
						if (!item.default_value_class_name) {
							field.default_value_class_name.error = 'Please enter a class name.';
						}
						if (!item.default_value_method_name) {
							field.default_value_method_name.error = 'Please enter the name of a static method.';
						}
					}
				}
				
				//Custom code names must be unique
				if (item.custom_code_name) {
					let pattern = /^[a-zA-Z0-9_-]+$/;
					
					if (!pattern.test(item.custom_code_name)) {
						tags.tabs[tab].fields.custom_code_name.error = 'Custom field names may only contain capital and lower case letters, numbers, dashes and underscores.';
					} else {
						if (thus.getFormFieldMergeName(item.id) == item.custom_code_name) {
							tags.tabs[tab].fields.custom_code_name.error = 'The custom field name may not be identical to the default merge name.';
						} else {
							var formFields = thus.getOrderedFields();
							for (var i = 0; i < formFields.length; i++) {
								var field = formFields[i];
								if (field.id != item.id && (item.custom_code_name == field.custom_code_name || thus.getFormFieldMergeName(field.id) == field.custom_code_name)) {
									tags.tabs[tab].fields.custom_code_name.error = 'Another field already has this code name on this form.';
									break;
								}
							}
						}
					}
				}
				
				if (item.css_classes) {
					if (item.css_classes.indexOf('<') != -1 || item.css_classes.indexOf('>') != -1) {
						tags.tabs[tab].fields.css_classes.error = 'CSS classes may not contain < or >.';
					}
				}
				
				if (item.div_wrap_class) {
					if (item.div_wrap_class.indexOf('<') != -1 || item.div_wrap_class.indexOf('>') != -1) {
						tags.tabs[tab].fields.div_wrap_class.error = 'Wrapper div CSS class may not contain < or >.';
					}
				}
				
				if (item.invalid_responses && item.invalid_responses.length) {
					if (!item.invalid_field_value_error_message) {
						tags.tabs[tab].fields.invalid_field_value_error_message.error = 'Please enter an error message when an invalid response is chosen.';
					}
				}
				
				if (item.type == 'textarea') {
					if (item.word_count_max) {
						if (+item.word_count_max != item.word_count_max) {
							tags.tabs[tab].fields.word_count_max.error = 'Please enter a valid number for the max word count.';
						} else if (item.word_count_max < 1) {
							tags.tabs[tab].fields.word_count_max.error = 'Word count must be greater than 0.';
						}
					}
					if (item.word_count_min) {
						if (+item.word_count_min != item.word_count_min) {
							tags.tabs[tab].fields.word_count_min.error = 'Please enter a valid number for the min word count.';
						} else if (item.word_count_min < 1) {
							tags.tabs[tab].fields.word_count_min.error = 'Word count must be greater than 0.';
						}
					}
					if (item.rows) {
						if (+item.rows != item.rows) {
							tags.tabs[tab].fields.rows.error = 'Please enter a valid number for the rows.';
						} else if (item.rows < 1 || item.rows > 100) {
							tags.tabs[tab].fields.rows.error = 'Rows must be greater than 0 and less than 100.';
						}
					}
				}
				break;
			
			case 'crm':
				if (item.send_to_crm && !item.field_crm_name) {
					tags.tabs[tab].fields.field_crm_name.error = 'Please enter a CRM field name.';
				}
				break;
		}
	}
};

//Values are saved automatically on client and then passed to server to save to the database
//methods.saveTUIX = function() {};


methods.getTUIXFieldCustomValues = function(type) {
	var values = {};
	//A list of centralised lists
	if (type == 'centralised_lists') {
		values = JSON.parse(JSON.stringify(thus.tuix.centralised_lists.values));
	//Lists of fields on this form that meet a certain criteria
	} else if (type == 'centralised_list_filter_fields' || type == 'conditional_fields' || type == 'mirror_fields') {
		var pages = thus.getOrderedPages();
		var useOptGroups = pages.length > 1;
		var ord = 0;
		for (var i = 0; i < pages.length; i++) {
			var page = pages[i];
			var fields = thus.getOrderedFields(pages[i].id);
			for (var j = 0; j < fields.length; j++) {
				var field = fields[j];
				if (!thus.canAddFieldToList(type, field.id)) {
					continue;
				}
				
				values[field.id] = {
					label: field.name + ' [' + thus.getFieldReadableType(field.type).toLowerCase() + ']',
					ord: ++ord
				};
				if (useOptGroups) {
					var parentId = 'page_' + page.id;
					values[field.id].parent = parentId;
					if (!values[parentId]) {
						values[parentId] = {
							label: page.name,
							ord: ++ord
						};
					}
				}
			}
		}
	//A list of this fields values
	} else if (type == 'field_lov') {
		if (thus.editingThing == 'field' && thus.editingThingId) {
			var field = thus.getItem(thus.editingThing, thus.editingThingId);
			if (field && field.lov) {
				values = JSON.parse(JSON.stringify(field.lov));
			}
		}
	}
	return values;
};

methods.canAddFieldToList = function(type, fieldId) {
	var field = thus.tuix.items[fieldId];
	if (type == 'centralised_list_filter_fields') {
		return (thus.editingThing != 'field' || field.id != thus.editingThingId) && (field.type == 'centralised_select' || (field.type == 'text' && field.enable_suggested_values && field.suggested_values == 'pre_defined' && field.suggested_values_source));
	} else if (type == 'conditional_fields') {
		return (thus.editingThing != 'field' || field.id != thus.editingThingId) && (['checkbox', 'group', 'radios', 'select', 'centralised_radios', 'centralised_select', 'checkboxes'].indexOf(field.type) != -1);
	} else if (type == 'mirror_fields') {
		return (thus.editingThing != 'field' || field.id != thus.editingThingId) && (['text', 'calculated', 'select', 'centralised_select', 'radios', 'centralised_radios'].indexOf(field.type) != -1);
	}
	return false;
};

methods.saveCurrentOpenDetails = function(deleted) {
	var errors = [];
	var itemType = thus.editingThing;
	var itemId = thus.editingThingId;
	if (itemType && itemId && thus.editingThingTUIXTabId) {
		var tuixMode = thus.getTUIXModeForItemType(itemType);
		var tuix = thus.tuix[tuixMode];
		var item = thus.getItem(itemType, itemId);
		
		if (item) {
			thus.saveTUIXTab(tuix, thus.editingThingTUIXTabId, item);
			
			//Get errors if trying to delete
			if (deleted) {
				errors = thus.getDeleteErrors(itemType, itemId);
				
			//Get regular errors
			} else {
				//Save name field
				item.name = $('#field__name').val().trim();
		
				//Validate tuix fields
				var tags = thus.getTUIXTags(tuixMode, item, itemType);
				thus.validateTUIX(itemType, item, thus.editingThingTUIXTabId, tags);
				
				foreach (tags.tabs as var tuixTabId => var tuixTab) {
					foreach (tuixTab.fields as var tuixFieldId => var tuixField) {
						if (tuixField.error) {
							errors.push(tuixField.error);
						}
					}
				}
			}
		
			//Reload tab to show errors
			if (errors.length) {
				thus.openItemTUIXTab(itemType, itemId, thus.editingThingTUIXTabId, errors);
			}
		}
	}
	return errors.length == 0;
};

methods.getDeleteErrors = function(itemType, itemId) {
	var errors = [];
	if (itemType == 'field') {
		var fieldToDelete = thus.getItem(itemType, itemId);
		var fields = thus.getOrderedFields();
		for (var i = 0; i < fields.length; i++) {
			var field = fields[i];
			var required = false;
			
			//Check if this field is used in a calculated field
			if (field.type == 'calculated' && field.calculation_code) {
				for (var j = 0; j < field.calculation_code.length; j++) {
					var step = field.calculation_code[j];
					if (step.type == 'field' && step.value == itemId) {
						required = true;
						break;
					}
				}
			}
			
			//Check if this field is used in a conditional
			if ((field.visibility && field.visibility == 'visible_on_condition' && field.visible_condition_field_id == itemId) || (field.readonly_or_mandatory && field.readonly_or_mandatory == 'conditional_mandatory' && field.mandatory_condition_field_id == itemId)
			) {
				required = true;
			}
			
			if (required) {
				errors.push('Unable to delete field because the field "' + field.name + '" depends on it.');
			}
			
		}
	}
	return errors;
};

methods.displayPageFieldOrderErrors = function() {
	if (!thus.getItem('page', thus.currentPageId)) {
		return true;
	}
	
	var errors = [];
	var fields = thus.getOrderedFields(thus.currentPageId);
	var fieldsAllowedInRepeatBlock = [
		//Valid form field types
		'checkbox', 
		'checkboxes', 
		'date', 
		'radios', 
		'centralised_radios', 
		'select', 
		'centralised_select', 
		'text', 
		'textarea', 
		'url', 
		'attachment', 
		'section_description', 
		//Valid dataset field types not included above
		'group'
	];
	
	var inRepeatBlock = false;
	for (var i = 0; i < fields.length; i++) {
		var field = fields[i];
		if (field.type == 'repeat_start' && !inRepeatBlock) {
			inRepeatBlock = true;
		} else if (field.type == 'repeat_end') {
			//Validate repeat end positioning
			if (inRepeatBlock) {
				inRepeatBlock = false;
			} else {
				errors.push('Repeat ends must be placed after repeat starts.');
			}
		} else {
			//Validate field types in repeat block
			if (inRepeatBlock && fieldsAllowedInRepeatBlock.indexOf(field.type) == -1) {
				errors.push('Field type "' + thus.getFieldReadableType(field).toLowerCase() + '" is not allowed in a repeat block.');
			}
		}
	}
	
	//Display errors
	var foundErrors = errors.length > 0;
	var $errorDiv = $('#organizer_fields_error');
	$errorDiv.html('');
	for (i = 0; i < errors.length; i++) {
		$errorDiv.append('<p class="error">' + errors[i] + '</p>');
	}
	$errorDiv.toggle(foundErrors);
	
	return !foundErrors;
};

methods.getTUIXModeForItemType = function(itemType) {
	if (itemType == 'page') {
		return 'form_page_details';
	} else if (itemType == 'field') {
		return 'form_field_details';
	} else {
		return false;
	}
};

methods.getFieldReadableType = function(item) {
	if (typeof item == 'string') {
		var type = item;
	} else {
		var type = item.type;
		if (item.is_consent) {
			type = 'consent'
		}
	}
	switch (type) {
		case 'checkbox':
			return 'Checkbox';
		case 'checkboxes':
			return 'Checkboxes';
		case 'date':
			return 'Date';
		case 'editor':
			return 'Editor';
		case 'radios':
			return 'Radios';
		case 'centralised_radios':
			return 'Centralised radios';
		case 'select':
			return 'Select';
		case 'centralised_select':
			return 'Centralised select';
		case 'text':
			return 'Text';
		case 'textarea':
			return 'Textarea';
		case 'url':
			return 'URL';
		case 'attachment':
			return 'Attachment';
		case 'page_break':
			return 'Step';
		case 'page_break_visible_on_condition':
			return 'Conditional step';
		case 'page_break_hidden':
			return 'Hidden step';
		case 'section_description':
			return 'Subheading';
		case 'section_spacer':
			return 'Spacer';
		case 'calculated':
			return 'Calculated';
		case 'restatement':
			return 'Mirror';
		case 'repeat_start':
			return 'Start of repeating section';
		case 'repeat_end':
			return 'End of repeating section';
		case 'document_upload':
			return 'Multi-upload';
		case 'sortable_selection':
			return 'Sortable selection';
		default:
			return 'Unknown';
		
		//Types unique to dataset fields
		case 'group':
			return 'Group';
		case 'consent':
			return 'Consent';
		case 'file_picker':
			return 'File picker';
	}
};

methods.getCalculationCodeDisplay = function(calculationCode, displayHTML) {
	//If this is called from the "Edit calculation" admin box,
	//the calculation code display will use HTML to lay out every field/operator in a separate row.
	//If this is called from the form builder,
	//the calculation code will be displayed as a single string.
	var calculationDisplay = '';
	if (calculationCode) {
		var lastIsParenthesisOpen = false;
		for (var i = 0; i < calculationCode.length; i++) {
			if (!lastIsParenthesisOpen && calculationCode[i].type != 'parentheses_close') {
				if (displayHTML) {
					calculationDisplay += '<br />';
				} else {
					calculationDisplay += ' ';
				}
			} else if (!lastIsParenthesisOpen && calculationCode[i].type == 'parentheses_close') {
				if (displayHTML) {
					calculationDisplay += '<br />';
				}
			} else if (lastIsParenthesisOpen) {
				lastIsParenthesisOpen = false;
				if (displayHTML) {
					calculationDisplay += '<br />';
				}
			}
			
			if (displayHTML) {
				calculationDisplay += "<span>";
			}
			
			switch (calculationCode[i].type) {
				case 'operation_addition':
					calculationDisplay += '+';
					break;
				case 'operation_subtraction':
					calculationDisplay += '-';
					break;
				case 'operation_multiplication':
					calculationDisplay += '×';
					break;
				case 'operation_division':
					calculationDisplay += '÷';
					break;
				case 'parentheses_open':
					calculationDisplay += '(';
					lastIsParenthesisOpen = true;
					break;
				case 'parentheses_close':
					calculationDisplay += ')';
					break;
				case 'static_value':
					calculationDisplay += calculationCode[i].value;
					break;
				case 'field':
					var name = '';
					var field = thus.getItem('field', calculationCode[i].value);
					if (field) {
						name = field.name;
					} else {
						name = 'UNKNOWN FIELD';
					}
					calculationDisplay += '"' + name + '"';
					break;
			}
			
			if (displayHTML) {
				calculationDisplay += "</span>";
			}
			
			calculationDisplay = calculationDisplay.trim();
		}
	}
	
	return calculationDisplay;
};

//Calculation admin box methods
methods.calculationAdminBoxAddSomething = function(type, value) {
	var code = false;
	switch (type) {
		case 'operation_addition':
		case 'operation_subtraction':
		case 'operation_multiplication':
		case 'operation_division':
		case 'parentheses_open':
		case 'parentheses_close':
			code = {type: type};
			break;
		case 'static_value':
			if (value !== '' && !isNaN(+value)) {
				code = {type: type, value: +value};
				$('#zaf_static_value').val('');
			}
			break;
		case 'field':
			if (value) {
				code = {type: type, value: value};
				$('#zaf_numeric_field').val('');
			}
			break;
	}
	if (code) {
		var calculationCode = [];
		if ($('#zaf_calculation_code').val()) {
			calculationCode = JSON.parse($('#zaf_calculation_code').val());
		}
		calculationCode.push(code);
		$('#zaf_calculation_code').val(JSON.stringify(calculationCode));
		
		thus.calculationAdminBoxUpdateDisplay(calculationCode);
	}
};
methods.calculationAdminBoxDelete = function() {
	var calculationCode = [];
	if ($('#zaf_calculation_code').val()) {
		calculationCode = JSON.parse($('#zaf_calculation_code').val());
		if (calculationCode) {
			calculationCode.pop();
			$('#zaf_calculation_code').val(JSON.stringify(calculationCode));
		}
	}
	thus.calculationAdminBoxUpdateDisplay(calculationCode);
};
methods.calculationAdminBoxUpdateDisplay = function(calculationCode) {
	var displayHTML = true;
	var calculationDisplay = thus.getCalculationCodeDisplay(calculationCode, displayHTML);
	$('#zaf_zenario_calculation_display').html(calculationDisplay);
};


methods.openFormSettings = function() {
	zenarioAB.open(
		'zenario_user_form', 
		{id: zenarioO.pi.refiner.id, opened_from_form_editor: 1},
		undefined, undefined,
		function(key, values) {
			//Update form title (note if lots of changes might be better to redraw entire form)
			var title = '';
			if (values.details.show_title) {
				title = values.details.title;
			}
			thus.tuix.title = title;
			$('#organizer_form_builder .form_outer .form_header h5').text(title);
		}
	);
};

methods.changeMadeToPanel = function() {	
	if (!thus.changeMadeOnPanel) {
		thus.changeMadeOnPanel = true;
		window.onbeforeunload = function() {
			return 'You are currently editing this form. If you leave now you will lose any unsaved changes.';
		}
		var warningMessage = 'Please either save your changes, or click Reset to discard them, before exiting the form editor.';
		zenarioO.disableInteraction(warningMessage);
		zenarioO.setButtons();
	}
};


methods.saveChanges = function() {
	if (thus.tuix.form.status == 'active') {
		//Show warning
		if (thus.tuix.not_used_or_on_public_page) {
			var hasNonEmailDatasetFields = false;
			var hasEmailDatasetField = false;
			var fields = thus.getOrderedFields();
			for (var i = 0; i < fields.length; i++) {
				if (fields[i].dataset_field_id) {
					if (fields[i].db_column == 'email') {
						hasEmailDatasetField = true;
					} else {
						hasNonEmailDatasetFields = true;
					}
				}
			}
					
			if (hasNonEmailDatasetFields && !hasEmailDatasetField && !confirm("Warning: this form contains fields that are linked to the Users Dataset, but doesn\'t contain the Email field from the Users Dataset.\n\nIf this form is used on a public web page by anonymous visitors, form responses will not be stored in the Users & Contacts database table.\n\nTo overcome this, please add the Email field linked to the Users Dataset.\n\nSave anyway?")) {
				return;
			}
		}
		
		var actionRequests = {
			mode: 'save',
			pages: JSON.stringify(thus.tuix.pages),
			fields: JSON.stringify(thus.tuix.items),
			fieldsTUIX: JSON.stringify(thus.tuix.form_field_details),
			pagesReordered: thus.pagesReordered,
			deletedPages: JSON.stringify(thus.deletedPages),
			deletedFields: JSON.stringify(thus.deletedFields),
			deletedValues: JSON.stringify(thus.deletedValues),
			currentPageId: thus.currentPageId,
			editingThing: thus.editingThing,
			editingThingId: thus.editingThingId
		};
	
		zenarioA.nowDoingSomething('saving', true);
		
		thus.sendAJAXRequest(actionRequests, function(info) {
			zenarioA.nowDoingSomething();
			
			if (info) {
				if (info.errors) {
					var message = '';
					for (var i = 0; i < info.errors.length; i++) {
						message += info.errors[i] + '<br>';
					}
					if (message) {
						zenarioA.floatingBox(message);
					}
				}
				thus.currentPageId = info.currentPageId;
				thus.editingThing = info.editingThing
				thus.editingThingId = info.editingThingId;
			}
			
			window.onbeforeunload = false;
			zenarioO.enableInteraction();
			
			thus.changeMadeOnPanel = false;
			thus.changesSaved = true;
			
			zenarioO.reload();
		});
	}
};

}, zenarioO.panelTypes);
