
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit, SimpleChanges} from '@angular/core';
import { FormGroup, FormArray, FormControl } from '@angular/forms';
import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type';
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
import { DatasetProfileInternalDmpEntitiesType } from '@app/core/common/enum/dataset-profile-internal-dmp-entities-type';
import { DataTableRequest } from '@app/core/model/data-table/data-table-request';
import { DatasetExternalAutocompleteCriteria } from '@app/core/query/dataset/daatset-external-autocomplete-criteria';
import { DatasetCriteria } from '@app/core/query/dataset/dataset-criteria';
import { DmpCriteria } from '@app/core/query/dmp/dmp-criteria';
import { RequestItem } from '@app/core/query/request-item';
import { ResearcherCriteria } from '@app/core/query/researcher/researcher-criteria';
import { DatasetExternalAutocompleteService } from '@app/core/services/dataset/dataset-external-autocomplete.service';
import { DatasetService } from '@app/core/services/dataset/dataset.service';
import { DmpService } from '@app/core/services/dmp/dmp.service';
import { ExternalSourcesService } from '@app/core/services/external-sources/external-sources.service';
import { MultipleAutoCompleteConfiguration } from '@app/library/auto-complete/multiple/multiple-auto-complete-configuration';
import { SingleAutoCompleteConfiguration } from '@app/library/auto-complete/single/single-auto-complete-configuration';
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
import { BaseComponent } from '@common/base/base.component';
import { TranslateService } from '@ngx-translate/core';
import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { ExternalSourceItemModel } from '@app/core/model/external-sources/external-source-item';
import { ExternalDatasetCriteria } from '@app/core/query/external-dataset/external-dataset-criteria';
import { DataRepositoryCriteria } from '@app/core/query/data-repository/data-repository-criteria';
import { RegistryCriteria } from '@app/core/query/registry/registry-criteria';
import { ServiceCriteria } from '@app/core/query/service/service-criteria';
import { TagCriteria } from '@app/core/query/tag/tag-criteria';
import { isNullOrUndefined } from '@app/utilities/enhancers/utils';
import { ExternalTagEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { MatChipInputEvent } from '@angular/material/chips';
import { ENTER, COMMA } from '@angular/cdk/keycodes';
import { DatasetIdModel } from '@app/core/model/dataset/dataset-id.model';
import { LocalFetchModel } from '@app/core/model/local-fetch/local-fetch.model';
import { CurrencyService } from '@app/core/services/currency/currency.service';
import { AutoCompleteSingleData } from '@app/core/model/dataset-profile-definition/field-data/field-data';
import {LicenseCriteria} from "@app/core/query/license/license-criteria";
import {TaxonomyCriteria} from "@app/core/query/taxonomy/taxonomy-criteria";
import {PublicationCriteria} from "@app/core/query/publication/publication-criteria";
import {FileService} from "@app/core/services/file/file.service";
import {
	SnackBarNotificationLevel,
	UiNotificationService
} from "@app/core/services/notification/ui-notification-service";
import {FormValidationErrorsDialogComponent} from "@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component";
import {MatDialog} from "@angular/material/dialog";
import {HttpError} from "@common/modules/errors/error-handling/http-error-handling.service";
import {HttpErrorResponse} from "@angular/common/http";
import * as FileSaver from "file-saver";

@Component({
	selector: 'app-form-field',
	templateUrl: './form-field.component.html',
	styleUrls: ['./form-field.component.scss'],
	changeDetection: ChangeDetectionStrategy.OnPush
})
export class FormFieldComponent extends BaseComponent implements OnInit {

	// @Input() field: Field;
	@Input() form: FormGroup;
	@Input() datasetProfileId: any;
	@Input() isChild: Boolean = false;
	@Input() autocompleteOptions: AutoCompleteSingleData;

	visible: boolean = true;
	_renderStyle: DatasetProfileFieldViewStyle = null;

	get renderStyle() {
		//console.log('renderStyle');
		return this._renderStyle;
	}

	// change: Subscription;
	// trackByFn = (index, item) => item ? item['id'] : null;

	public singleAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	public multipleAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
	datasetProfileFieldViewStyleEnum = DatasetProfileFieldViewStyle;
	datasetProfileComboBoxTypeEnum = DatasetProfileComboBoxType;
	datasetProfileInternalDmpEntitiesTypeEnum = DatasetProfileInternalDmpEntitiesType;
	externalDatasetAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	dataRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	pubRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	journalRepositoriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	taxonomiesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	licensesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	publicationsAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	registriesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	servicesAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	tagsAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
	researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
	organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
	currencyAutoCompleteConfiguration: SingleAutoCompleteConfiguration;

	readonly separatorKeysCodes: number[] = [ENTER, COMMA];

	tags: ExternalTagEditorModel[] = [];

	datasetIdInitialized: boolean = false;

	validationIcon;

	readonly datasetIdTypes: any[] = [
		{ name: 'Handle', value: 'handle' },
		{ name: 'DOI', value: 'doi' },
		{ name: 'Ark', value: 'ark' },
		{ name: 'Url', value: 'url' },
		{ name: 'Other', value: 'other' }
	];


	readonly validationTypes: any[] = [
		{ name: 'Zenodo', value: 'zenodo' }
	];

	filesToUpload: FileList;

	constructor(
		public visibilityRulesService: VisibilityRulesService,
		private datasetExternalAutocompleteService: DatasetExternalAutocompleteService,
		private externalSourcesService: ExternalSourcesService,
		private language: TranslateService,
		private datasetService: DatasetService,
		private dmpService: DmpService,
		private currencyService: CurrencyService,
		private fileService: FileService,
		private cdr: ChangeDetectorRef,
		private uiNotificationService: UiNotificationService,
		public dialog: MatDialog
	) {
		super();

		this.visibilityRulesService.getElementVisibilityMapObservable().pipe(takeUntil(this._destroyed)).subscribe(x => {
			this.visible = this.visibilityRulesService.checkElementVisibility(this.form?.get('id')?.value);
		});
	}

	ngOnChanges(changes: SimpleChanges) {
		if (changes['form']) {
			this._renderStyle = this.form.get('viewStyle')?.value?.renderStyle;
		}
	}

	ngOnInit() {

		if (this.form.get('value').value) {
			this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, this.form.get('value').value);
		}

		if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList) {
			if (this.form.get('data').value.multiList) {
				const originalValue = <string>this.form.get('value').value;
				if (originalValue !== null && typeof originalValue === 'string') {
					let values = (<string>this.form.get('value').value).slice(1, -1).split(', ').filter((value) => !value.includes('"'));
					let specialValue = (<string>this.form.get('value').value).split('"').filter((value) => !value.startsWith('[') && !value.endsWith(']') && !values.includes(value) && value !== ', ');
					specialValue.forEach(value => values.push(value));
					if (!originalValue.startsWith('[') && !originalValue.endsWith(']')) {
						values = undefined;
						values = [originalValue];
					}
					this.form.patchValue({ 'value': values });
					values.forEach(element => {
						this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, element);
					});
				}
			}
		}

		// Setup autocomplete configuration if needed
		if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.Autocomplete) {
			if (!(this.form.controls['data'].value.multiAutoComplete)) {
				this.singleAutoCompleteConfiguration = {
					filterFn: this.searchFromAutocomplete.bind(this),
					initialItems: () => this.searchFromAutocomplete(''),
					displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item).label : item['label'] } catch { return '' } },
					titleFn: (item) => { try { return item['label'] } catch { return '' } },
					valueAssign: (item) => { try { return JSON.stringify(item) } catch { return '' } },
					subtitleFn: (item) => { try { return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } catch { return '' } }
				};
			}
			else {
				this.multipleAutoCompleteConfiguration = {
					filterFn: this.searchFromAutocomplete.bind(this),
					initialItems: () => this.searchFromAutocomplete(''),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'] } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['label'] : item['label'] } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } },
					subtitleFn: (item) => { try { return item['source'] ? this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-SUBTITLE') + item['source'] : this.language.instant('DATASET-WIZARD.EDITOR.FIELDS.EXTERNAL-AUTOCOMPLETE-NO-SOURCE') } catch { return '' } }
				}
			}
		}

		switch (this.form.get('viewStyle').value.renderStyle) {
			case DatasetProfileFieldViewStyle.ExternalDatasets:
				this.externalDatasetAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalDatasets.bind(this),
					initialItems: () => this.searchDatasetExternalDatasets(''),//.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.DataRepositories:
				this.dataRepositoriesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalDataRepositories.bind(this),
					initialItems: () => this.searchDatasetExternalDataRepositories(''),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.PubRepositories:
				this.pubRepositoriesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalPubRepositories.bind(this),
					initialItems: () => this.searchDatasetExternalPubRepositories(''),
					displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}},
					valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}
				};
				break;
			case DatasetProfileFieldViewStyle.JournalRepositories:
				this.journalRepositoriesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalJournalRepositories.bind(this),
					initialItems: () => this.searchDatasetExternalJournalRepositories(''),
					displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}},
					valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}
				};
				break;
			case DatasetProfileFieldViewStyle.Taxonomies:
				this.taxonomiesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalTaxonomies.bind(this),
					initialItems: () => this.searchDatasetExternalTaxonomies(''),
					displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}},
					valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}
				};
				break;
			case DatasetProfileFieldViewStyle.Licenses:
				this.licensesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalLicences.bind(this),
					initialItems: () => this.searchDatasetExternalLicences(''),
					displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}},
					valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}
				};
				break;
			case DatasetProfileFieldViewStyle.Publications:
				this.publicationsAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalPublications.bind(this),
					initialItems: () => this.searchDatasetExternalPublications(''),
					displayFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					titleFn: (item) => { try{return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name}catch{return''}},
					subtitleFn: (item) => { try{return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')}catch{return''}},
					valueAssign: (item) => { try{return typeof (item) == 'string' ? item : JSON.stringify(item)}catch{return''}}
				};
				break;
			case DatasetProfileFieldViewStyle.Registries:
				this.registriesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalRegistries.bind(this),
					initialItems: () => this.searchDatasetExternalRegistries(''),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.Services:
				this.servicesAutoCompleteConfiguration = {
					filterFn: this.searchDatasetExternalServices.bind(this),
					initialItems: () => this.searchDatasetExternalServices(''),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					subtitleFn: (item) => { try { return item.source ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.source : item.tag ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item.tag : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE') } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.Tags:
				this.tagsAutoCompleteConfiguration = {
					filterFn: this.filterTags.bind(this),
					initialItems: (excludedItems: any[]) => this.filterTags('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
					displayFn: (item) => { try { return this.showTag(item) } catch { return '' } },
					titleFn: (item) => { try { return item['name'] } catch { return '' } },
					valueAssign: (item) => { try { return this.addTag(item) } catch { return '' } }
				};
				this.parseTags();
				break;
			case DatasetProfileFieldViewStyle.Researchers:
				this.researchersAutoCompleteConfiguration = {
					filterFn: this.filterResearchers.bind(this),
					initialItems: (excludedItems: any[]) => this.filterResearchers('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					subtitleFn: (item) => { try { return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.Organizations:
				this.organisationsAutoCompleteConfiguration = {
					filterFn: this.filterOrganisations.bind(this),
					initialItems: (excludedItems: any[]) => this.filterOrganisations('').pipe(map(result => result.filter(resultItem => (excludedItems || []).map(x => x.id).indexOf(resultItem.id) === -1))),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					subtitleFn: (item) => { try { return item['tag'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['tag'] : (item['key'] ? this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.SOURCE:') + item['key'] : this.language.instant('TYPES.EXTERNAL-DATASET-TYPE.NO-SOURCE')) } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.DatasetIdentifier:
				const value = this.form.get('value').value;
				this.form.removeControl('value');
				this.form.addControl('value', new DatasetIdModel(value).buildForm());
				this.datasetIdInitialized = true;
				break;
			case DatasetProfileFieldViewStyle.Currency:
				this.currencyAutoCompleteConfiguration = {
					filterFn: this.searchCurrency.bind(this),
					initialItems: () => this.searchCurrency(''),
					displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)['name'] : item.name } catch { return '' } },
					valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } }
				};
				break;
			case DatasetProfileFieldViewStyle.Validation:
				const value1 = this.form.get('value').value;
				this.form.removeControl('value');
				this.form.addControl('value', new DatasetIdModel(value1).buildForm());
				//this.datasetIdInitialized = true;
				break;
		}

		if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.InternalDmpEntities) {
			if (this.form.get('data').value.type === DatasetProfileInternalDmpEntitiesType.Researchers) {
				this.makeAutocompleteConfiguration(this.searchResearchers.bind(this), "name", "tag");
			}
			else if (this.form.get('data').value.type === DatasetProfileInternalDmpEntitiesType.Datasets) {
				this.makeAutocompleteConfiguration(this.searchDatasets.bind(this), "label");
			}
			else if (this.form.get('data').value.type === DatasetProfileInternalDmpEntitiesType.Dmps) {
				this.makeAutocompleteConfiguration(this.searchDmps.bind(this), "label");
			}
		}

		// this.form = this.visibilityRulesService.getFormGroup(this.field.id);
		this.form.get('value').valueChanges
			.pipe(
				takeUntil(this._destroyed),
				distinctUntilChanged()
			)
			.subscribe(item => {
				// if (this.form.get('viewStyle').value.renderStyle === DatasetProfileFieldViewStyle.ComboBox && this.form.get('data').value.type === DatasetProfileComboBoxType.WordList && this.form.get('data').value.multiList) {
				// 		item.forEach(element => {
				// 			this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, element);
				// 		});

				// } else {
				this.visibilityRulesService.updateValueAndVisibility(this.form.get('id').value, item);
				// }
			});
	}

	// _optionRemove(event) {
	// 	const array = JSON.parse(this.form.get('value').value);
	// 	if (array) {
	// 		const index = array.map(x => x.id).indexOf(event.id);
	// 		if (index >= 0) {
	// 			array.splice(index, 1);
	// 		}
	// 		this.form.get('value').patchValue(JSON.stringify(array));
	// 	}
	// }

	searchFromAutocomplete(query: string) {
		const autocompleteRequestItem: RequestItem<DatasetExternalAutocompleteCriteria> = new RequestItem();
		autocompleteRequestItem.criteria = new DatasetExternalAutocompleteCriteria();
		let parseIdArray: string[] = this.form.get('id').value.split('_');
		if(parseIdArray.length > 1) {
			autocompleteRequestItem.criteria.fieldID = parseIdArray[parseIdArray.length - 1];
		} else {
			autocompleteRequestItem.criteria.fieldID = this.form.get('id').value;
		}
		if (typeof this.datasetProfileId === 'string') {
			autocompleteRequestItem.criteria.profileID = this.datasetProfileId;
		} else if (this.datasetProfileId != null) {
			autocompleteRequestItem.criteria.profileID = this.datasetProfileId.id;
		} else if (this.autocompleteOptions != null) {
			autocompleteRequestItem.criteria.autocompleteOptions = this.autocompleteOptions;
		} else {
			throw "Could not load autocomplete options.";
		}
		autocompleteRequestItem.criteria.like = query;

		if (this.autocompleteOptions) {
			return this.datasetExternalAutocompleteService.queryApi(autocompleteRequestItem);
		}
		return this.datasetExternalAutocompleteService.queryAutocomplete(autocompleteRequestItem);
	}

	searchResearchers(query: string) {
		const reasearcherAutocompleteRequestItem: RequestItem<ResearcherCriteria> = new RequestItem();
		reasearcherAutocompleteRequestItem.criteria = new ResearcherCriteria;
		reasearcherAutocompleteRequestItem.criteria.name = query;
		return this.externalSourcesService.searchDMPResearchers(reasearcherAutocompleteRequestItem);
	}

	searchDatasets(query: string) {
		let fields: Array<string> = new Array();
		const datasetsAutocompleteRequestItem: DataTableRequest<DatasetCriteria> = new DataTableRequest(0, 25, { fields: fields });
		datasetsAutocompleteRequestItem.criteria = new DatasetCriteria();
		datasetsAutocompleteRequestItem.criteria.like = query;
		return this.datasetService.getPaged(datasetsAutocompleteRequestItem).pipe(map(item => item.data));
	}

	searchDmps(query: string) {
		let fields: Array<string> = new Array();
		const dmpsAutocompleteRequestItem: DataTableRequest<DmpCriteria> = new DataTableRequest(0, 25, { fields: fields });
		dmpsAutocompleteRequestItem.criteria = new DmpCriteria();
		dmpsAutocompleteRequestItem.criteria.like = query;
		return this.dmpService.getPaged(dmpsAutocompleteRequestItem).pipe(map(item => item.data));
	}

	makeAutocompleteConfiguration(myfunc: Function, title: string, subtitle?: string): void {
		if (!(this.form.controls['data'].value.multiAutoComplete)) {
			this.singleAutoCompleteConfiguration = {
				filterFn: myfunc.bind(this),
				initialItems: (extraData) => myfunc(''),
				displayFn: (item) => { try { return (item != null && item.length > 1) ? JSON.parse(item)[title] : item[title] } catch { return '' } },
				titleFn: (item) => { try { return item[title] } catch { return '' } },
				valueAssign: (item) => JSON.stringify(item),
				subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } }
			};
		}
		else {
			this.multipleAutoCompleteConfiguration = {
				filterFn: myfunc.bind(this),
				initialItems: (extraData) => myfunc(''),
				displayFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } },
				titleFn: (item) => { try { return typeof (item) == 'string' ? JSON.parse(item)[title] : item[title] } catch { return '' } },
				valueAssign: (item) => { try { return typeof (item) == 'string' ? item : JSON.stringify(item) } catch { return '' } },
				subtitleFn: (item) => { try { return item[subtitle] } catch { return '' } }
			}
		}
	}

	searchDatasetExternalDatasets(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<ExternalDatasetCriteria> = new RequestItem();
		requestItem.criteria = new ExternalDatasetCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchDatasetSExternalDatasetservice(requestItem);
	}

	searchDatasetExternalDataRepositories(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
		requestItem.criteria = new DataRepositoryCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchDatasetRepository(requestItem);
	}
	searchDatasetExternalPubRepositories(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
		requestItem.criteria = new DataRepositoryCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchPublicationRepository(requestItem);
	}
	searchDatasetExternalJournalRepositories(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<DataRepositoryCriteria> = new RequestItem();
		requestItem.criteria = new DataRepositoryCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchJournals(requestItem);
	}
	searchDatasetExternalTaxonomies(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<TaxonomyCriteria> = new RequestItem();
		requestItem.criteria = new TaxonomyCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchTaxonomies(requestItem);
	}
	searchDatasetExternalLicences(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<LicenseCriteria> = new RequestItem();
		requestItem.criteria = new LicenseCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchLicense(requestItem);
	}
	searchDatasetExternalPublications(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<PublicationCriteria> = new RequestItem();
		requestItem.criteria = new PublicationCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchPublications(requestItem);
	}

	searchDatasetExternalRegistries(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<RegistryCriteria> = new RequestItem();
		requestItem.criteria = new RegistryCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchDatasetRegistry(requestItem);
	}

	searchDatasetExternalServices(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<ServiceCriteria> = new RequestItem();
		requestItem.criteria = new ServiceCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchDatasetService(requestItem);
	}

	searchDatasetTags(query: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<TagCriteria> = new RequestItem();
		requestItem.criteria = new TagCriteria();
		requestItem.criteria.like = query;
		requestItem.criteria.type = '';
		return this.externalSourcesService.searchDatasetTags(requestItem);
	}

	parseTags() {
		try {


			let stringValue = this.form.get('value').value;
			if (typeof stringValue === 'string') {
				stringValue = (<string>stringValue).replace(new RegExp('{', 'g'), '{"').replace(new RegExp('=', 'g'), '":"').replace(new RegExp(',', 'g'), '",').replace(new RegExp(', ', 'g'), ', "').replace(new RegExp('}', 'g'), '"}');
				stringValue = stringValue.replace(new RegExp('}"', 'g'), '}').replace(new RegExp('"{', 'g'), '{');
			} else if (stringValue instanceof Array) {
				const tempArray = new Array();
				for (let stringTag of stringValue) {
					tempArray.push(JSON.parse(stringTag));
				}
				stringValue = JSON.stringify(tempArray);
			}
			const tagArray = JSON.parse(stringValue);
			this.form.patchValue({ 'value': tagArray });
		} catch (e) {
			console.warn('Could not parse tags');
		}
	}

	filterTags(value: string): Observable<ExternalSourceItemModel[]> {
		const requestItem: RequestItem<TagCriteria> = new RequestItem();
		const criteria: TagCriteria = new TagCriteria();
		criteria.like = value;
		requestItem.criteria = criteria;
		return this.externalSourcesService.searchDatasetTags(requestItem);
	}

	showTag(ev: any) {
		if (typeof ev === 'string') {
			return ev;
		} else {
			return ev.name;
		}
	}

	addTag(ev: any) {
		let item: ExternalTagEditorModel;
		//this.filteredTags = this.formGroup.get('tags').value;
		if (typeof ev === 'string') {
			item = new ExternalTagEditorModel('', ev);
		} else {
			item = ev;
		}
		if (item.name !== '') {
			return item;
		}
	}

	filterOrganisations(value: string): Observable<ExternalSourceItemModel[]> {
		return this.externalSourcesService.searchDMPOrganizations(value);
	}

	filterResearchers(value: string): Observable<ExternalSourceItemModel[]> {
		return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } });
	}

	getDatasetIdControl(name: string): FormControl {
		return this.form.get('value').get(name) as FormControl;
	}

	searchCurrency(query: string): Observable<LocalFetchModel[]> {
		return this.currencyService.get(query);
	}

	validateId() {
		const identifier = this.getDatasetIdControl('identifier').value;
		const type = this.getDatasetIdControl('type').value;
		this.validationIcon = 'loading';
		this.externalSourcesService.validateIdentifier(identifier, type).pipe(takeUntil(this._destroyed)).subscribe(result => {
			this.validationIcon = result === true ? 'done' : 'clear';
		});

	}

	public upload() {
		this.fileService.upload(this.filesToUpload[0], this.datasetProfileId.id, this.form.value.id).subscribe((fileId: string) => {
			this.form.get("value").patchValue(
				{"name": this.filesToUpload[0].name, "id": fileId+"", "type": this.filesToUpload[0].type});
			this.cdr.detectChanges();
		}, error => {
			this.onCallbackUploadFail(error.error);
		})
	}


	private onCallbackUploadFail(error: any) {
		this.makeFilesNull();
		this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error);
	}

	fileChangeEvent(fileInput: any, dropped: boolean = false) {
		if(this.form.value.value) {
			this.onRemove(false);
		}

		if(dropped) {
			this.filesToUpload = fileInput.addedFiles;
		} else {
			this.filesToUpload = fileInput.target.files;
		}


		let messages: string[] = [];
		if (this.filesToUpload.length == 0) {
			messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.NO-FILES-SELECTED'));
			return;
		} else {
			let fileToUpload = this.filesToUpload[0];
			if (this.form.get("data") && this.form.get("data").value.types
				&& this.form.get("data").value.types.map(type => type.value).includes(fileToUpload.type)
				&& this.form.get("data").value.maxFileSizeInMB
				&& this.form.get("data").value.maxFileSizeInMB*1048576 >= fileToUpload.size) {
				this.upload();
			} else {
				this.filesToUpload = null;
				messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.LARGE-FILE-OR-UNACCEPTED-TYPE'));
				messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.MAX-FILE-SIZE', {'maxfilesize': this.form.get("data").value.maxFileSizeInMB}));
				messages.push(this.language.instant('DATASET-WIZARD.MESSAGES.ACCEPTED-FILE-TYPES')+ this.form.get("data").value.types.map(type => type.value).join(", "));
			}

			if(messages && messages.length > 0) {
				this.dialog.open(FormValidationErrorsDialogComponent, {
					data: {
						errorMessages: messages
					}
				})
			}
		}
	}

	onRemove(makeFilesNull: boolean = true) {
		// delete from tmp folder - subscribe call
		this.fileService.deleteFromTempFolder(this.form.value.value.id).subscribe(res => {
			if(makeFilesNull) {
				this.makeFilesNull();
			}
			this.cdr.detectChanges();
		}, error => {
			if(makeFilesNull) {
				this.makeFilesNull();
			}
		})
	}

	makeFilesNull() {
		this.filesToUpload = null;
		this.form.value.value = null;
		this.form.get("value").patchValue(null);
	}

	typesToString() {
		return this.form.get("data").value.types.map(type => type.value).toString();
	}

	download(): void {
		this.fileService.download(this.form.value.value.id)
			.pipe(takeUntil(this._destroyed))
			.subscribe(response => {
				const blob = new Blob([response.body], {type: this.form.value.value.type});
				const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));

				FileSaver.saveAs(blob, filename);
			});
	}

	// create a fileUtils/ fileHelper file and add this function (and any other possibly generic) there
	getFilenameFromContentDispositionHeader(header: string): string {
		const regex: RegExp = new RegExp(/filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/g);

		const matches = header.match(regex);
		let filename: string;
		for (let i = 0; i < matches.length; i++) {
			const match = matches[i];
			if (match.includes('filename="')) {
				filename = match.substring(10, match.length - 1);
				break;
			} else if (match.includes('filename=')) {
				filename = match.substring(9);
				break;
			}
		}
		return filename;
	}

	// isImageFile(fileType: string) {
	// 	if(!fileType) {
	// 		return false;
	// 	}
	// 	return fileType.startsWith("image/");
	// }
}
