/* =================
   FIELDS SELECTOR
   ================= */

import Globals from './_globals';
import ExportSettings from '../../config/_export-settings';
import { Entity, Field } from '../../utils/_interfaces';
import SelectedField from './_selected-field';

export default class FieldSelector {
	
	groups: any;
	$elem: JQuery = null;
	fieldListTemplate: string;
	addColumnIcon: string = `<i class="select-field atum-icon" title="${ this.settings.get('addColumn') }"></i>`;
	isMainEntity: boolean = false;
	addedSubentities: string[] = [];
	entityFields: any = {};
	$searchFieldInput: JQuery;
	
	constructor(
		private entities: Entity[],
		private globals: Globals,
		private settings: ExportSettings
	) {
		
		if (!this.entities.length) {
			return;
		}
		
		this.isMainEntity = this.entities.length === 1 && this.entities[0].isMain;
		this.groups = this.settings.get('fieldTypes');
		this.$elem = $(this.globals.$entitySection.find('#ent-field-selector-tmpl').html());
		
		const $fieldSelectorTitle: JQuery = this.$elem.find('.field-selector-title');
		$fieldSelectorTitle.html(this.isMainEntity ? this.entities[0].title : this.settings.get('subentities'));
		$fieldSelectorTitle.prepend(`<i class="atum-icon atum-tooltip ${ this.isMainEntity ? 'atmi-apartment' : 'atmi-link' }" title="${ this.settings.get(this.isMainEntity ? 'mainEntity' : 'subentities') }"></i> `);
		this.globals.tooltip.addTooltips($fieldSelectorTitle);
		this.fieldListTemplate = this.globals.$entitySection.find('#ent-field-list-tmpl').html();
		this.$searchFieldInput = this.$elem.find('input[type=search]');
		
		// NOTE: The events must be binded before adding the list.
		this.bindEvents();
		
		this.entities.forEach( (entity: Entity) => this.addFieldsList(entity) );
		
	}
	
	/**
	 * Add fields lists to the selector component
	 *
	 * @param {Entity} entity
	 */
	addFieldsList(entity: Entity) {
		
		// Some groups have fields and meta and others only fields.
		for (const group in this.groups) {
			
			let $fieldList: JQuery  = $(this.fieldListTemplate),
			    $selectList: JQuery = $fieldList.find('.select-list').data({entity: entity.name, group: group}),
			    $listTitle: JQuery  = $fieldList.find('.field-list-title');
			
			const fieldListTitle: string = this.isMainEntity ? this.groups[group] : entity.title;
			
			if (!this.isMainEntity && group !== 'fields') {
				$listTitle.remove();
			}
			else {
				$listTitle.text(fieldListTitle);
			}
			
			if (entity.hasOwnProperty(group) && !$.isEmptyObject(entity[group])) {
				
				const fields: Field[] = entity[group];
				
				if (!this.entityFields.hasOwnProperty(entity.name)) {
					this.entityFields[entity.name] = [];
				}
				
				this.entityFields[entity.name] = [...this.entityFields[entity.name], ...fields];
				
				for (const fieldIndex in fields) {
					
					const field: Field      = fields[fieldIndex],
					      $listItem: JQuery = $(`
							<li data-field="${ field.name }" data-group="${ field.group || 'fields' }" class="atum-tooltip" title="${ field.label ? `${ field.label } (${ field.name })` : field.name }">
								<span>${ field.label || field.name }</span> ${ this.addColumnIcon }
							</li>
						  `);
					
					$selectList.append($listItem);
					
					// Is selected?
					if ( field.selected ) {
						this.globals.selectedFields[field.settings.position] = $listItem; // Preserve the field position.
					}
					
				}
				
				this.$elem.find('.field-list-wrapper').append($fieldList);
				this.globals.tooltip.addTooltips($fieldList);
				
			}
		
		}
		
	}
	
	bindEvents() {
	
		this.$elem
			
			// Select a field from the list.
			.on('click', '.select-list li', (evt: JQueryEventObject) => {
				
				const $field: JQuery      = $(evt.target).closest('li'),
				      fieldName: string   = $field.data('field'),
				      fieldGroup: string  = $field.data('group'),
				      $fieldList: JQuery  = $field.closest('.select-list'),
				      fieldEntity: string = $fieldList.data('entity') || '',
				      entity: Entity      = this.globals.findEntity(fieldEntity);
				
				if (!$field.hasClass('selected')) {
					
					if ( fieldEntity && fieldGroup && this.entityFields.hasOwnProperty(fieldEntity) ) {
						
						// Try to find a field with the same name and group within the entity fields' array.
						const fieldFound: Field[] = this.entityFields[fieldEntity].filter( (field: Field) => {
							return field.name === fieldName && field.group === fieldGroup;
						} );
						
						if (fieldFound.length) {
							$field.addClass('selected');
							this.addSelectedField(fieldFound[0], entity, $field);
						}
					
					}
					
				}
				else {
					this.removeSelectedField($field);
				}
				
			})
		
			// Toggle the component.
			.on('click', '.toggle-component', () => {
				this.$elem.toggleClass('closed');
				$(window).scroll(); // Force the entity section reposition.
			} )
		
			// Search fields.
			.on('keyup search paste', '.field-search input', () => this.searchFields() );
		
	}
	
	/**
	 * Add the selected field to the selection zone
	 *
	 * @param {Field}  $field
	 * @param {Entity} entity
	 * @param {JQuery} $field
	 */
	addSelectedField(field: Field, entity: Entity, $field: JQuery) {
		
		const selectedField: SelectedField = new SelectedField(field, entity, $field, this.globals, this.settings);
		
		this.globals.$selectedFieldsWrapper.append(selectedField.$elem);
		this.globals.fixSwitchers(selectedField.$elem.find('input:checkbox'));
		this.globals.maybeShowDroppingZone();
		this.doSortableSelectedFields();
		this.globals.summary.maybeCreateSummary();
		
		if (typeof selectedField.field.settings === 'undefined' || !selectedField.field.settings) {
			selectedField.rearrangePositionSelect();
		}
		
		this.globals.$selectedFieldsWrapper.trigger('atum-export-selected-field-added', [selectedField]);
	
	}
	
	/**
	 * Remove a selected field from the selection zone
	 *
	 * @param {JQuery} $field
	 */
	removeSelectedField($field: JQuery) {
		
		const selectedField: SelectedField = $field.data('selected-field');
		
		if (typeof selectedField !== 'undefined') {
			selectedField.remove();
			this.globals.rearrangePositionSelects();
			
			this.globals.$selectedFieldsWrapper.trigger('atum-export-selected-field-removed', [selectedField]);
		}
		
	}
	
	/**
	 * Allow to reorder the fields with drag and drop
	 */
	doSortableSelectedFields() {
		
		(<any>this.globals.$selectionSection).find('.selected-fields').sortable({
			handle              : '.drag-item',
			items               : '.selected-field',
			forcePlaceholderSize: true,
			stop                : (evt: JQueryEventObject, ui: any) => {
				
				// Rearrange the position selects without affecting the field position.
				this.globals.rearrangePositionSelects(true);
				this.globals.summary.maybeCreateSummary();
				
			},
		});
		
	}
	
	/**
	 * Search fields within this field selector
	 */
	searchFields() {
		
		const filter: string      = this.$searchFieldInput.val().toUpperCase(),
		      $fieldLists: JQuery = this.$elem.find('.field-list'),
		      $fields: JQuery     = $fieldLists.find('.select-list > li');
		
		// Loop through all list items, and hide those who don't match the search query.
		$fields.each( (index: number, elem: Element) => {
			
			const $field: JQuery = $(elem),
				txtValue: string = $field.attr('title') || $field.data('original-title');
			
			if (txtValue.toUpperCase().indexOf(filter) > -1) {
				$field.removeClass('hidden');
			}
			else {
				$field.addClass('hidden');
			}
			
		});
		
		// If there are empty lists, hide them completely.
		$fieldLists.each( (index: number, elem: Element) => {
			
			const $fieldList: JQuery = $(elem);
			
			if ($fieldList.find('.select-list > li').not('.hidden').length) {
				$fieldList.show();
			}
			else {
				$fieldList.hide();
			}
			
		});
		
	}
	
	/**
	 * Add the caption to the component
	 */
	addCaption() {
		if (this.$elem !== null) {
			this.$elem.before(`<strong class="field-selector--caption">${ this.settings.get(this.isMainEntity ? 'mainEntity' : 'subentities') }</strong>`);
		}
	}

}