
import { of as observableOf, Observable,  combineLatest, BehaviorSubject,of } from 'rxjs';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Component, OnInit, QueryList, ViewChild } from '@angular/core';
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { MatHorizontalStepper} from '@angular/material/stepper';
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { debounceTime, filter, map, mergeMap, takeUntil, tap } from 'rxjs/operators';
import * as FileSaver from 'file-saver';
import { BaseComponent } from '@common/base/base.component';
import { DatasetProfileEditorModel } from '@app/ui/admin/dataset-profile/editor/dataset-profile-editor-model';
import { DatasetWizardModel } from '@app/core/model/dataset/dataset-wizard';
import { BreadcrumbItem } from '@app/ui/misc/breadcrumb/definition/breadcrumb-item';
import { DatasetProfileService } from '@app/core/services/dataset-profile/dataset-profile.service';
import { LoggingService } from '@app/core/services/logging/logging-service';
import { UiNotificationService, SnackBarNotificationLevel } from '@app/core/services/notification/ui-notification-service';
import { DatasetProfile } from '@app/core/model/admin/dataset-profile/dataset-profile';
import { DatasetProfileEnum } from '@app/core/common/enum/dataset-profile';
import { SectionEditorModel } from '@app/ui/admin/dataset-profile/admin/section-editor-model';
import { PageEditorModel } from '@app/ui/admin/dataset-profile/admin/page-editor-model';
import { DatasetStatus } from '@app/core/common/enum/dataset-status';
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { LanguageInfo } from '@app/core/model/language-info';
import { LanguageInfoService } from '@app/core/services/culture/language-info-service';
import { FormValidationErrorsDialogComponent } from '@common/forms/form-validation-errors-dialog/form-validation-errors-dialog.component';
import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { DatasetWizardService } from '@app/core/services/dataset-wizard/dataset-wizard.service';
import { DatasetWizardEditorModel } from '@app/ui/dataset/dataset-wizard/dataset-wizard-editor.model';
import { NewEntryType, ToCEntry, ToCEntryType } from '../table-of-contents/table-of-contents-entry';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { FieldSetEditorModel } from '../admin/field-set-editor-model';
import { Guid } from '@common/types/guid';
import { FieldEditorModel } from '../admin/field-editor-model';
import { VisibilityRulesService } from '@app/ui/misc/dataset-description-form/visibility-rules/visibility-rules.service';
import { CdkStep, StepperSelectionEvent } from '@angular/cdk/stepper';
import { DatasetDescriptionCompositeFieldEditorModel, DatasetDescriptionFieldEditorModel, DatasetDescriptionSectionEditorModel } from '@app/ui/misc/dataset-description-form/dataset-description-form.model';
import { Rule } from '@app/core/model/dataset-profile-definition/rule';
import { DatasetProfileFieldViewStyle } from '@app/core/common/enum/dataset-profile-field-view-style';
import { SideNavService } from '@app/core/services/sidenav/side-nav.sevice';
import { EditorCustomValidators, EditorCustomValidatorsEnum } from './custom-validators/editor-custom-validators';
import { GENERAL_ANIMATIONS, STEPPER_ANIMATIONS } from './animations/animations';
import { DatasetProfileComboBoxType } from '@app/core/common/enum/dataset-profile-combo-box-type';
import { UserService } from '@app/core/services/user/user.service';
import { MatInput } from '@angular/material/input';
import { CheckDeactivateBaseComponent } from '@app/library/deactivate/deactivate.component';

const skipDisable: any[] = require('../../../../../assets/resources/skipDisable.json');

@Component({
	selector: 'app-dataset-profile-editor-component',
	templateUrl: './dataset-profile-editor.component.html',
	styleUrls: ['./dataset-profile-editor.component.scss'],
	animations:[...STEPPER_ANIMATIONS, ...GENERAL_ANIMATIONS],
	providers:[VisibilityRulesService]
})
export class DatasetProfileEditorComponent extends CheckDeactivateBaseComponent implements OnInit {

	canDeactivate(): boolean {
		return !this.form.dirty;
	}

	isNew = true;
	isNewVersion = false;
	isClone = false;
	isDeleted = false;
	dataModel: DatasetProfileEditorModel;
	form: FormGroup;
	previewerFormGroup: FormGroup;
	private datasetProfileId: string;
	newVersionId: string;
	dataWizardModel: DatasetWizardModel;
	breadCrumbs: Observable<BreadcrumbItem[]>;
	@ViewChild('stepper') stepper: MatHorizontalStepper;
	viewOnly = false;
	nestedCount: number[] = [];
	nestedIndex: number = 0;
	errorMessages: string[] = [];
	tocEntryEnumValues = ToCEntryType;
	public userChipList:any[] = [];
	displayedColumns: String[] = ['name', 'email', 'button'];

	colorizeInvalid:boolean = false;
	inputUserState: 'untriggered'| 'triggered' = 'untriggered';
	private _inputUserField$:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
	private _inputUserButton$:BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
	showScrollOnTopButton:boolean = true;

	private stepperNavigationObserver: IntersectionObserver;

	// customEditorValidators = new EditorCustomValidators();

	// sectionIdPreviewed:string = null;
	// currentSubForm:FormGroup = null;
	// currentSectionIndex: number = null;
	// currentSectionEditorModel: SectionEditorModel = null;

	constructor(
		private datasetProfileService: DatasetProfileService,
		private route: ActivatedRoute,
		private router: Router,
		private logger: LoggingService,
		private uiNotificationService: UiNotificationService,
		private language: TranslateService,
		private dialog: MatDialog,
		private languageInfoService: LanguageInfoService,
		private httpClient: HttpClient,
		private matomoService: MatomoService,
		private enumUtils: EnumUtils,
		private datasetWizardService: DatasetWizardService,
		private visibilityRulesService: VisibilityRulesService,
		private fb: FormBuilder,
		private sidenavService: SideNavService,
		private userService: UserService
	) {
		super();
		// this.profileID = route.snapshot.params['id'];
		// this.cloneId = route.snapshot.params['cloneid'];
	}

	ngOnDestroy(){
		this.sidenavService.setStatus(true);
		if(this.stepperNavigationObserver){
			this.stepperNavigationObserver.disconnect();
			this.stepperNavigationObserver = null;
		}
	}

	ngOnInit() {
		this.sidenavService.setStatus(false);
		this.matomoService.trackPageView('Admin: Dataset Profile Edit');
		this.route.paramMap.pipe(takeUntil(this._destroyed)).subscribe((paramMap: ParamMap) => {
			this.datasetProfileId = paramMap.get('id');
			const cloneId = paramMap.get('cloneid');
			this.newVersionId = paramMap.get('newversionid');

			if (this.datasetProfileId != null) {
				this.isNew = false;
				this.datasetProfileService.getDatasetProfileById(this.datasetProfileId)
					.pipe(map(data => data as DatasetProfile), takeUntil(this._destroyed))
					.subscribe(
						data => {
							try {
								this.dataModel = new DatasetProfileEditorModel().fromModel(data);
								// this.isDeleted = this.masterItem.isActive === IsActive.Inactive;
								if (this.dataModel.status === DatasetProfileEnum.FINALIZED) {
									this.form = this.dataModel.buildForm(true, skipDisable);
									this.viewOnly = true;
								} else {
									this.form = this.dataModel.buildForm();
								}
								this.prepareForm();
							} catch (error) {
								this.logger.error('Could not parse MasterItem: ' + data);
								console.log(error)
								this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR'), SnackBarNotificationLevel.Error);
							}
						},
						error => this.onCallbackError(error)
					);
				this.breadCrumbs = observableOf([{
					parentComponentName: 'DatasetProfileListingComponent',
					label: this.language.instant('NAV-BAR.TEMPLATE'),
					url: '/dataset-profiles/' + this.datasetProfileId
				}]);
			} else if (cloneId != null) {
				this.isClone = true;
				this.datasetProfileService.clone(cloneId)
					.pipe(map(data => data as DatasetProfile), takeUntil(this._destroyed))
					.subscribe(
						data => {
							try {
								this.dataModel = new DatasetProfileEditorModel().fromModel(data);
								// this.isDeleted = this.masterItem.isActive === IsActive.Inactive;
								this.dataModel.status = DatasetProfileEnum.SAVED;
								this.form = this.dataModel.buildForm();
								this.prepareForm();
							} catch (error){
								this.logger.error('Could not parse MasterItem: ' + data);
								this.logger.error(error);
								this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR'), SnackBarNotificationLevel.Error);
							}
						},
						error => this.onCallbackError(error)
					);
			} else if (this.newVersionId != null) {
				this.isNewVersion = true;
				this.datasetProfileService.getDatasetProfileById(this.newVersionId)
					.pipe(map(data => data as DatasetProfile), takeUntil(this._destroyed))
					.subscribe(
						data => {
							try {
								this.dataModel = new DatasetProfileEditorModel().fromModel(data);
								// this.isDeleted = this.masterItem.isActive === IsActive.Inactive;
								this.form = this.dataModel.buildForm();
								this.form.get('version').setValue(this.form.get('version').value + 1);
								// this.form.controls['label'].disable();
								// this.form.controls['description'].disable();
								// this.form.controls['language'].disable();
								this.prepareForm();
							} catch (error){
								this.logger.error('Could not parse MasterItem: ' + data);
								this.logger.error(error);
								this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.FORM-VALIDATION-DISPLAY-DIALOG.HAS-ERROR'), SnackBarNotificationLevel.Error);
							}
						},
						error => this.onCallbackError(error)
					);
			} else {
				this.dataModel = new DatasetProfileEditorModel();
				this.form = this.dataModel.buildForm();
				// this.form.setValidators([EditorCustomValidators.atLeastOneElementListValidator('pages'), EditorCustomValidators.pagesHaveAtLeastOneSection('pages', 'sections')]);

				if (this.dataModel.status === DatasetProfileEnum.FINALIZED) {
					this.form.disable();
					this.viewOnly = true;
				}
				// this.addSection();
				// this.addPage();
				this.visibilityRulesService.buildVisibilityRules([],this.form);
				setTimeout(() => {
					this.steps = this.stepper.steps;
				});
				this._initializeToCEntries();

			}
		});


		combineLatest(this._inputUserButton$.asObservable(),this._inputUserField$.asObservable())
		.pipe(takeUntil(this._destroyed))
		.pipe(debounceTime(400))
		.pipe(filter(_=> !_[0] && !_[1]))
		.subscribe(_=>{
			// if(!this.userFormDisabled)
			this.inputUserState = 'untriggered';
		});
	}

	private _initializeToCEntries(){
		const tocentries = this.refreshToCEntries();//tocentries are sorted based on their ordinal value

		this._updateOrdinals(tocentries);

		if(tocentries && tocentries.length){
			this.selectedTocEntry = tocentries[0];
		}
		// setTimeout(() => {
		// 	// const stepperNavigation = document.getElementById('stepper-navigation');
		// 	// const titleColumn = document.getElementById('title-column');
		// 	// const stepperNavigationWrapper = document.getElementById('stepper-navigation-wrapper');
		//
		// 	if(titleColumn){
		// 		if(this.stepperNavigationObserver){
		// 			this.stepperNavigationObserver.disconnect();
		// 			this.stepperNavigationObserver = null;
		// 		}
		// 		this.stepperNavigationObserver = new IntersectionObserver((e)=>{
		// 			e.forEach(_=>{
		// 				if(_.isIntersecting){
		// 					this.showScrollOnTopButton = false;
		// 					// stepperNavigation.classList.remove('fixed-navigation');
		// 					// stepperNavigationWrapper.classList.remove('fixed-navigation');
		// 				}else{
		// 					this.showScrollOnTopButton = true;
		// 					// stepperNavigation.classList.add('fixed-navigation');
		// 					// stepperNavigationWrapper.classList.add('fixed-navigation');
		// 				}
		// 			})
		// 		}, {root:null,  rootMargin:'0px', threshold:0});
		// 		this.stepperNavigationObserver.observe(titleColumn);
		// 	}else{
		// 		console.log('Could not load scroll On Top Observer')
		// 	}
		// }, 400);
		// this._initializeFormValidity(tocentries);

		//Checking invalid visibilty RULES
		const fieldsetEntries = this._getAllFieldSets(this.toCEntries);
		const fieldSetHavingInvalidVisibilityRules:ToCEntry[] = fieldsetEntries
		.filter(entry=>{
			const fieldsFormGroup = entry.form.get('fields');
			const invalid = (fieldsFormGroup as FormArray).controls.filter(field=>{
				return this.hasInvalidVisibilityRule(field as FormGroup);

			});
			if(invalid && invalid.length){
				return true;
			}
			return false;
		});


		if(fieldSetHavingInvalidVisibilityRules.length){
			const occurences = fieldSetHavingInvalidVisibilityRules.map(record=>record.numbering).join(' , ');
			this.dialog.open(ConfirmationDialogComponent, {
				data:{
					message: this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.MESSAGE-START')+occurences+ this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.MESSAGE-END'),
					confirmButton: this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.CONFIRM-YES'),
					cancelButton: this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.CONFIRM-NO')
				},
				maxWidth:'30em'
			})
			.afterClosed()
			.subscribe(confirm=>{
				if(confirm){
					this.removeFieldSetVisibilityRules(fieldSetHavingInvalidVisibilityRules);
					this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.ERRORS.INVALID-VISIBILITY-RULES.REMOVE-SUCCESS'), SnackBarNotificationLevel.Success);

				}else{
					console.log('User not confirmed');
				}
			})
		}


	}

	private removeFieldSetVisibilityRules(fieldsets:ToCEntry[]){

		if(!fieldsets || !fieldsets.length) return;

		fieldsets.forEach(fieldset=>{
			if(fieldset.type != ToCEntryType.FieldSet){
				return;
			}
			const fields = fieldset.form.get('fields') as FormArray;

			fields.controls.forEach(fieldControl=>{
				if(this.hasInvalidVisibilityRule(fieldControl as FormGroup)){
					try{
						(fieldControl.get('visible').get('rules') as FormArray).clear();
					}catch{}
				}
			})

		})

	}

	private hasInvalidVisibilityRule(field: FormGroup):boolean{
		const renderStyle = field.get('viewStyle').get('renderStyle').value;
		if(renderStyle && ![
			DatasetProfileFieldViewStyle.TextArea,
			DatasetProfileFieldViewStyle.RichTextArea,
			DatasetProfileFieldViewStyle.Upload,
			DatasetProfileFieldViewStyle.FreeText,
			DatasetProfileFieldViewStyle.BooleanDecision,
			DatasetProfileFieldViewStyle.RadioBox,
			DatasetProfileFieldViewStyle.CheckBox,
			DatasetProfileFieldViewStyle.DatePicker,
			DatasetProfileFieldViewStyle.ComboBox,
		].includes(renderStyle)){
			if(((renderStyle === DatasetProfileFieldViewStyle) && (field.get('data').get('type').value === DatasetProfileComboBoxType.WordList))){
				return false;
			}
			try{
				if(field.get('visible').get('rules').value.length){
					return true;
				}
				return false;

			}catch{
				return false;
			}
		}else{
			return false;
		}
	}


	prepareForm() {
		this.visibilityRulesService.buildVisibilityRules([],this.form);
		// this.form.setValidators([EditorCustomValidators.atLeastOneElementListValidator('pages'),EditorCustomValidators.pagesHaveAtLeastOneSection('pages', 'sections')]);
		// this.form.updateValueAndValidity();
		this.form.valueChanges
			.pipe(takeUntil(this._destroyed))
			.subscribe(change => {

				// this.datasetProfileService.preview(this.form.value)
				// 	.pipe(takeUntil(this._destroyed))
				// 	.subscribe(dataset => {
				// 		const datasetModel = new DatasetWizardModel();
				// 		datasetModel.datasetProfileDefinition = JsonSerializer.fromJSONObject(dataset, DatasetProfileDefinitionModel);
				// 		this.dataWizardModel = datasetModel;
				// 		this.previewerFormGroup = <FormGroup>this.dataWizardModel.buildForm().get('datasetProfileDefinition');
				// 	});
			});
		setTimeout(() => {
			this.steps = this.stepper.steps;
		});
		this._initializeToCEntries();
		// console.log(this.form.get('users').value);
		if (this.form.get('users').value !== null && this.form.get('users').value !== undefined) {
			this.userChipList = [...this.form.get('users').value];
		} else {
			this.userChipList = [];
		}

	}

	onIsMultiplicityEnabledChange(isMultiplicityEnabled: boolean) {
		if (!isMultiplicityEnabled) {
			(<FormControl>this.form.get('multiplicity').get('min')).setValue(0);
			(<FormControl>this.form.get('multiplicity').get('max')).setValue(0);
		}
	}

	// addSection() {
	// 	const section: SectionEditorModel = new SectionEditorModel();
	// 	this.dataModel.sections.push(section);
	// 	(<FormArray>this.form.get('sections')).push(section.buildForm());
	// }

	// addPage() {
	// 	const page: PageEditorModel = new PageEditorModel(this.dataModel.pages.length);
	// 	this.dataModel.pages.push(page);
	// 	(<FormArray>this.form.get('pages')).push(page.buildForm());
	// }

	// DeleteSection(index) {
	// 	this.dataModel.sections.splice(index, 1);
	// 	(<FormArray>this.form.get('sections')).removeAt(index);
	// }

	onSubmit(close: boolean = false) {
		let data = this.form.value;

		if (this.datasetProfileId) {
			this.datasetProfileService.updateForm(this.datasetProfileId, data)
				.pipe(takeUntil(this._destroyed))
				.subscribe(() => {
					this.afterSave();
					this.form.markAsPristine();//deactivate guard
					if(close) {
						this.router.navigate(['/dataset-profiles']);
					}
					this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success);
				},error=> this.onCallbackError(error));
		} else if (this.newVersionId) {
			data.label = this.form.get('label').value;
			data.description = this.form.get('description').value;
			this.datasetProfileService.newVersion(this.newVersionId, data)
				.pipe(takeUntil(this._destroyed))
				.subscribe((newVersionTemplateId: string) => {
						this.afterSave(newVersionTemplateId);
						this.form.markAsPristine();//deactivate guard
						if(close) {
							this.router.navigate(['/dataset-profiles']);
						}
						this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success);
				},
					error => this.onCallbackErrorNewVersion(error)
				);
		} else {
			if(this.form.get('status').value != DatasetStatus.Finalized){// forn created and finalized instantly
				this.form.get('status').setValue(DatasetStatus.Draft);
			}
			data = this.form.value;
			this.datasetProfileService.createForm(data)
				.pipe(takeUntil(this._destroyed))
				.subscribe(newTemplateId => {
					this.afterSave(newTemplateId);
					this.form.markAsPristine();//deactivate guard
					if(close) {
						this.router.navigate(['/dataset-profiles']);
					}
					this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success);
				}, error=> this.onCallbackError(error));
		}
	}

	afterSave(newId: string = null) {
		if(newId) {
			this.datasetProfileId = newId;
			this.form.value.id = newId;
		}
		this.isNew = false;
		this.newVersionId = null;

		// this.dataModel.fromModel(this.form.value);
		// if (this.dataModel.status === DatasetProfileEnum.FINALIZED) {
		// 	this.form = this.dataModel.buildForm(true, skipDisable);
		// 	this.viewOnly = true;
		// } else {
		// 	this.form = this.dataModel.buildForm();
		// }
		// this.prepareForm();
	}

	finalize() {
		//const data = this.form.value;
		this.form.get('status').setValue(DatasetProfileEnum.FINALIZED);

		this.onSubmit(true);
	}

	updateFinalized(close: boolean = false) {
		this.datasetProfileService.updateForm(this.datasetProfileId, this.form.getRawValue())
			.pipe(takeUntil(this._destroyed))
			.subscribe(() => {
				this.form.markAsPristine();//deactivate guard
				if(close) {
					this.router.navigate(['/dataset-profiles']);
				}
				this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.FEEDBACK-MESSAGES.SAVE-SUCCESS'), SnackBarNotificationLevel.Success)
			},error=>this.onCallbackError(error));
	}

	showUpdateButton() {
		return !this.isNew && this.dataModel.status === DatasetProfileEnum.FINALIZED;
	}

	// isStepActive(step: number) {
	// 	return this.stepper && this.stepper.selectedIndex === step;
	// }

	// onCallbackSuccess(): void {
	// 	this.uiNotificationService.snackBarNotification(this.isNew ? this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-CREATION') : this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-UPDATE'), SnackBarNotificationLevel.Success);
	// 	this.router.navigate(['/master-items']);
	// }

	onCallbackErrorNewVersion(errorResponse: HttpErrorResponse) {
		this.uiNotificationService.snackBarNotification(errorResponse.error.message, SnackBarNotificationLevel.Error);
	}

	onCallbackError(errorResponse: HttpErrorResponse) {
		// const error: HttpError = this.httpErrorHandlingService.getError(errorResponse);
		// if (error.statusCode === 400) {
		// 	this.masterItem.validationErrorModel.fromJSONObject(errorResponse.error);
		// 	this.formService.validateAllFormFields(this.formGroup);
		// } else {
		this.uiNotificationService.snackBarNotification(errorResponse.message, SnackBarNotificationLevel.Warning);
		// }
	}

	// DELETE Function
	public delete(): void {
		if (this.datasetProfileId && !this.isNew) {
			const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
				restoreFocus: false,
				data: {
					message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
					confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
					cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
					isDeleteConfirmation: true
				}
			});
			dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
				if (result) {
					//this.form.get('status').setValue(DatasetProfileEnum.DELETED);
					this.datasetProfileService.delete(this.datasetProfileId, this.form.value)
						.pipe(takeUntil(this._destroyed))
						.subscribe(
							complete => {
								this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.SUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Success);
								this.router.navigate(['/dataset-profiles']);
							},
							error => {
								this.onCallbackError(error);
								if (error.error.statusCode == 674) {
									this.uiNotificationService.snackBarNotification(this.language.instant('GENERAL.SNACK-BAR.UNSUCCESSFUL-DATASET-PROFILE-DELETE'), SnackBarNotificationLevel.Error);
								} else {
									this.uiNotificationService.snackBarNotification(this.language.instant(error.message), SnackBarNotificationLevel.Error);
								}
							}
						);
				}
			});
		}
	}

	downloadXML(): void {
		this.datasetProfileService.downloadXML(this.datasetProfileId)
			.pipe(takeUntil(this._destroyed))
			.subscribe(response => {
				const blob = new Blob([response.body], { type: 'application/xml' });
				const filename = this.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));

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

	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;
	}

	getLanguageInfos(): LanguageInfo[] {
		return this.languageInfoService.getLanguageInfoValues();
	}

	checkFormValidation() {
		this.colorizeInvalid = true;
		this.printMyErrors(this.form);


		// if (!this.form.valid) {
		// 	this.nestedIndex = -1;
		// 	this.form.markAllAsTouched();
		// 	this.printErrors(this.form);
		// 	this.showValidationErrorsDialog();
		// 	this.nestedCount = [];
		// 	this.nestedIndex = 0;
		// 	this.errorMessages = [];
		// }
	}


	//BEFORE REDESIGN
	// printErrors(rootform: FormGroup) {
	// 	if (!rootform.valid) {
	// 		Object.keys(rootform.controls).forEach(key => {
	// 			const errors = rootform.get(key).errors;
	// 			if (errors !== null) {
	// 				let numbering: string = '';
	// 				for (let j = 0; j < this.nestedCount.length; j++) {
	// 					numbering += this.nestedCount[j];
	// 					if (j < this.nestedIndex) {
	// 						numbering += '.';
	// 					} else {
	// 						break;
	// 					}
	// 				}
	// 				Object.keys(errors).forEach(keyError => {
	// 					if (typeof errors[keyError] === 'boolean') {
	// 						this.errorMessages.push(numbering + ' ' + key + ' is ' + keyError);
	// 					} else {
	// 						this.errorMessages.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError]));
	// 					}
	// 				});
	// 			} else {
	// 				if (rootform.get(key) instanceof FormGroup) {
	// 					this.printErrors(<FormGroup>rootform.get(key));
	// 				} else if (rootform.get(key) instanceof FormArray) {
	// 					this.nestedIndex++;
	// 					this.nestedCount[this.nestedIndex] = 0;
	// 					for (let childForm of (<FormArray>rootform.get(key)).controls) {
	// 						this.nestedCount[this.nestedIndex]++;
	// 						this.printErrors(<any>childForm);
	// 					}
	// 					this.nestedCount[this.nestedIndex] = 0;
	// 					this.nestedIndex--;

	// 				}
	// 			}
	// 		});
	// 	}
	// }

	// private showValidationErrorsDialog(projectOnly?: boolean) {
	// 	const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
	// 		disableClose: true,
	// 		autoFocus: false,
	// 		restoreFocus: false,
	// 		data: {
	// 			errorMessages: this.errorMessages,
	// 			projectOnly: projectOnly
	// 		},
	// 	});
	// }






	// links: Link[] = [];

	// getLinks(currentLinks: Link[]) {
	// 	this.links = currentLinks;
	// }


	datasetWizardModel: DatasetWizardEditorModel;
	formGroup: FormGroup;
	getPreview() {
		let data = this.form.getRawValue();
		this.datasetProfileService.preview(data).subscribe(x => {
			this.datasetWizardModel = new DatasetWizardEditorModel().fromModel({
				datasetProfileDefinition: x
			});
			this.updateVisibilityRules();
			this.formGroup = <FormGroup>this.datasetWizardModel.buildForm().get('datasetProfileDefinition');
		});
		//this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));

		//this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
		// if (this.datasetWizardModel.status === DatasetStatus.Finalized) {
		// 	this.formGroup.disable();
		// 	this.viewOnly = true;
		// }
		//if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
		// this.registerFormListeners();
		// this.dmpValueChanged(null);
		// this.breadCrumbs = observableOf([
		// 	{
		// 		parentComponentName: null,
		// 		label: this.language.instant('DATASET-LISTING.ACTIONS.CREATE-NEW').toUpperCase(),
		// 		url: '/datasets/new/'
		// 	}]);



		// this.datasetWizardService.updateDatasetProfile(this.profileUpdateId)
		// 		.pipe(takeUntil(this._destroyed))
		// 		.subscribe(data => {
		// 			this.datasetWizardModel = new DatasetWizardEditorModel().fromModel(data);
		// 			this.formGroupRawValue = JSON.parse(JSON.stringify(this.formGroup.getRawValue()));

		// 			this.needsUpdate();
		// 			this.breadCrumbs = observableOf([
		// 				{
		// 					parentComponentName: null,
		// 					label: this.language.instant('NAV-BAR.MY-DATASET-DESCRIPTIONS'),
		// 					url: '/datasets',
		// 					notFoundResolver: [
		// 						// {
		// 						// 	parentComponentName: null,
		// 						// 	label: this.datasetWizardModel.dmp.grant.label,
		// 						// 	url: '/grants/edit/' + this.datasetWizardModel.dmp.grant.id
		// 						// },
		// 						{
		// 							parentComponentName: null,
		// 							label: this.datasetWizardModel.dmp.label,
		// 							url: '/plans/edit/' + this.datasetWizardModel.dmp.id,
		// 						},
		// 					]
		// 				}]);
		// 			this.formGroup = this.datasetWizardModel.buildForm();
		// 			this.editMode = this.datasetWizardModel.status === DatasetStatus.Draft;
		// 			if (this.datasetWizardModel.status === DatasetStatus.Finalized) {
		// 				this.formGroup.disable();
		// 				this.viewOnly = true;
		// 			}
		// 			// if (this.viewOnly) { this.formGroup.disable(); } // For future use, to make Dataset edit like DMP.
		// 			this.loadDatasetProfiles();
		// 		});
	}

	private refreshToCEntries(): ToCEntry[]{
		this.toCEntries = this.getTocEntries();
		//update selected tocentry
		if(this.selectedTocEntry){
			this.selectedTocEntry = this._findTocEntryById(this.selectedTocEntry.id, this.toCEntries);
		}
		// this.updateOrdinals(this.toCEntries);
		// this._updateNumbering(this.toCEntries);
		return this.toCEntries;
	}

	/**
	 * 	Updates entries ordinal form value
	 * based on the index they have on the tocentry array.
	 * Tocentries that are on the same level have distinct ordinal value
	 *
	 * @param tocentries
	 *
	 */
	private _updateOrdinals(tocentries: ToCEntry[]){

		if(!tocentries || !tocentries.length) return;
		tocentries.forEach((e,idx)=>{
			const ordinalControl = e.form.get('ordinal');
			if(ordinalControl){
				ordinalControl.setValue(idx);
				ordinalControl.updateValueAndValidity();
			}
			this._updateOrdinals(e.subEntries);
		});
	}

	//sort tocentries based on their ordinality
	private _sortToCentries(entries: ToCEntry[]){
		if(!entries || !entries.length) return;
		entries.sort(this._compareOrdinals);
		entries.forEach(e=>{
			this._sortToCentries(e.subEntries)
		});
	}
	private _compareOrdinals(a, b){

		const aValue = a.form.get('ordinal').value as number;
		const bValue = b.form.get('ordinal').value as number;

		// if(!aValue || !bValue) return 0;
		return aValue - bValue;
	}
	private _updateNumbering(entries:ToCEntry[], parentNumbering:string){
		if(!entries || !entries.length) return;
		let prefix ='';
		if(parentNumbering.length){
			prefix = parentNumbering + '.';
		}
		entries.forEach((entry,index)=>{
			const numbering = prefix + (index+1);
			entry.numbering = numbering;
			this._updateNumbering(entry.subEntries, numbering);
		})
	}

	toCEntries:ToCEntry[];

	getTocEntries(): ToCEntry[] {
		if (this.form == null) { return []; }
		const result: ToCEntry[] = [];

		//build parent pages
		(this.form.get('pages') as FormArray).controls.forEach((pageElement, i) => {
			result.push({
				id: pageElement.get('id').value,
				label: pageElement.get('title').value,
				type: ToCEntryType.Page,
				form: pageElement,
				numbering: (i + 1).toString(),
				subEntriesType: ToCEntryType.Section
			} as ToCEntry)
		});

		// build first level sections
		(this.form.get('sections') as FormArray).controls.forEach((sectionElement, i) => {
			const currentSectionPageId = sectionElement.get('page').value;
			const pageToAdd = result.filter(x => x.id == currentSectionPageId)[0];
			if (pageToAdd.subEntries == null) pageToAdd.subEntries = [];

			const item = {
				id: sectionElement.get('id').value,
				label: sectionElement.get('title').value,
				type: ToCEntryType.Section,
				form: sectionElement,
				numbering: pageToAdd.numbering + '.' + (pageToAdd.subEntries.length +1)
			} as ToCEntry;
			const sectionItems = this.populateSections(sectionElement.get('sections') as FormArray, item.numbering);
			const fieldSetItems = this.populateFieldSets(sectionElement.get('fieldSets') as FormArray, item.numbering);
			if (sectionItems != null) {
				item.subEntries = sectionItems;
				item.subEntriesType = ToCEntryType.Section;
			}
			if (fieldSetItems != null) {
				if (item.subEntries == null) {
					item.subEntries = fieldSetItems;
				} else {
					item.subEntries.push(...fieldSetItems);
				}
				item.subEntriesType = ToCEntryType.FieldSet;

			}
			pageToAdd.subEntries.push(item);

		});
		this._sortToCentries(result);//ordeby ordinal
		this._updateNumbering(result, '');//update nubering if needed
		return result;
	}

	private populateSections(sections: FormArray, existingNumbering: string): ToCEntry[] {
		if (sections == null || sections.controls == null || sections.controls.length == 0) { return null; }

		const result: ToCEntry[] = [];
		sections.controls.forEach((sectionElement, i) => {

			const item = {
				id: sectionElement.get('id').value,
				label: sectionElement.get('title').value,
				type: ToCEntryType.Section,
				form: sectionElement,
				numbering: existingNumbering + '.' + (i + 1)
			} as ToCEntry;
			const sectionItems = this.populateSections(sectionElement.get('sections') as FormArray, item.numbering);
			const fieldSetItems = this.populateFieldSets(sectionElement.get('fieldSets') as FormArray, item.numbering);
			if (sectionItems != null) {
				item.subEntries = sectionItems;
				item.subEntriesType = ToCEntryType.Section;
			}
			if (fieldSetItems != null) {
				if (item.subEntries == null) {
					item.subEntries = fieldSetItems;
				} else {
					item.subEntries.push(...fieldSetItems);
				}
				item.subEntriesType = ToCEntryType.FieldSet;
			}
			result.push(item);
		});

		return result;
	}

	private populateFieldSets(fieldSets: FormArray, existingNumbering: string): ToCEntry[] {
		if (fieldSets == null || fieldSets.controls == null || fieldSets.controls.length == 0) { return null; }

		const result: ToCEntry[] = [];
		fieldSets.controls.forEach((fieldSetElement, i) => {

			result.push({
				id: fieldSetElement.get('id').value,
				label: fieldSetElement.get('title').value,
				type: ToCEntryType.FieldSet,
				//subEntries: this.populateSections((fieldSetElement.get('fieldSets') as FormArray), existingNumbering + '.' + i),
				form: fieldSetElement,
				numbering: existingNumbering + '.' + (i + 1)
			} as ToCEntry)

		});

		return result;
	}



	private _findTocEntryById(id: string, tocentries: ToCEntry[]): ToCEntry{
		if(!tocentries || !tocentries.length){
			return null;
		}

		let tocEntryFound = tocentries.find(entry=>entry.id === id);

		if(tocEntryFound){
			return tocEntryFound;
		}

		for(let entry of tocentries){
			const result = this._findTocEntryById(id, entry.subEntries);
			if(result){
				tocEntryFound = result;
				break;
			}
		}

		return tocEntryFound? tocEntryFound: null;
	}
	addNewEntry(tce: NewEntryType) {

		const parent = tce.parent;

		//define entry type
		switch (tce.childType) {
			case ToCEntryType.Page:
				const pagesArray = (this.form.get('pages') as FormArray);

				const page: PageEditorModel = new PageEditorModel(pagesArray.length);
				const pageForm = page.buildForm();
				// this.dataModel.pages.push(page);

				pagesArray.push(pageForm);
				// this.form.updateValueAndValidity();
				this.refreshToCEntries();
				this.selectedTocEntry = this._findTocEntryById(pageForm.get('id').value, this.toCEntries);

				break;
			case ToCEntryType.Section:

				const section: SectionEditorModel = new SectionEditorModel();
				section.id = Guid.create().toString();
				let sectionsArray:FormArray;

				if (parent.type === ToCEntryType.Page) {//FIRST LEVEL SECTION
					sectionsArray = this.form.get('sections') as FormArray;

					section.page = parent.id;

					try{
						const max = sectionsArray.controls.filter(control=>control.get('page').value === parent.id)
							.map(control=>control.get('ordinal').value)
							.reduce((a,b)=>Math.max(a,b));

						section.ordinal =  max + 1;
					}catch{
						section.ordinal =  sectionsArray.length;

					}
					sectionsArray.push(section.buildForm());
					// this.form.updateValueAndValidity();

				} else if( parent.type == ToCEntryType.Section) { //SUBSECTION OF SECTION
					sectionsArray = parent.form.get('sections') as FormArray;

					//adding page parent MAYBE NOT NEEDED
					section.page = parent.form.get('page').value;
					try{
						const maxOrdinal = sectionsArray.controls.map(control=>control.get('ordinal').value).reduce((a,b)=>Math.max(a, b));
						section.ordinal = maxOrdinal+1;
					}catch{
						section.ordinal = sectionsArray.length;
					}

					sectionsArray.push(section.buildForm());
					// (child.form.parent as FormArray).push(section.buildForm());

				}else{
					console.error('Section can only be child of a page or another section');
				}


				const sectionAdded = sectionsArray.at(sectionsArray.length -1) as FormGroup;
				// sectionAdded.setValidators(this.customEditorValidators.sectionHasAtLeastOneChildOf('fieldSets','sections'));
				// sectionAdded.updateValueAndValidity();


				this.refreshToCEntries();
				this.selectedTocEntry = this._findTocEntryById(sectionAdded.get('id').value, this.toCEntries);

				break;
			case ToCEntryType.FieldSet:

				//create one field form fieldset
				const field: FieldEditorModel = new FieldEditorModel();
				field.id = Guid.create().toString();
				field.ordinal = 0;//first filed in the fields list
				const fieldForm =  field.buildForm();
				// fieldForm.setValidators(this.customFieldValidator());
				// fieldForm.get('viewStyle').get('renderStyle').setValidators(Validators.required);

				// fieldSet.fields.push(field);
				// field.ordinal = fieldSet.fields.length-1;

				const fieldSetsArray = parent.form.get('fieldSets') as FormArray

				//give fieldset id and ordinal
				const fieldSet: FieldSetEditorModel = new FieldSetEditorModel();
				const fieldSetId = Guid.create().toString();
				fieldSet.id = fieldSetId;

				try{
					const maxOrdinal = fieldSetsArray.controls.map(control=>control.get('ordinal').value).reduce((a,b)=>Math.max(a, b));
					fieldSet.ordinal = maxOrdinal+1;
				}catch{
					fieldSet.ordinal = fieldSetsArray.length;
				}
				const fieldsetForm = fieldSet.buildForm();



				(fieldsetForm.get('fields') as FormArray).push(fieldForm);
				fieldSetsArray.push(fieldsetForm);

				this.refreshToCEntries();
				this.selectedTocEntry = this._findTocEntryById(fieldSetId, this.toCEntries);
				// fieldForm.updateValueAndValidity();

				break;

			default:
				break;
		}

		this.form.updateValueAndValidity();
	}


	onRemoveEntry(tce: ToCEntry){

		const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
			restoreFocus: false,
			data: {
				message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
				confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
				cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
				isDeleteConfirmation: true
			}
		});
		dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(result => {
			if (result) {
				this._deleteEntry(tce);
			}
		});

	}


	private _deleteEntry(tce: ToCEntry) {
		//define entry type
		switch (tce.type) {
			case ToCEntryType.Page:
				const pages = this.form.get('pages') as FormArray;

				let pageIndex = -1;
				//get the index
				for (let i = 0; i < pages.length; i++) {
					let page = pages.at(i) as FormGroup;

					if (page.controls.id.value === tce.id) {
						pageIndex = i;
						break;
					}
				}

				if (pageIndex >= 0) {
					//remove page
					this._updateSelectedItem(tce);
					pages.removeAt(pageIndex);
					//clean up sections of removed page

					const sections = (this.form.get('sections') as FormArray);

					const sectionsIndexToBeRemoved = [];

					sections.controls.forEach((section,idx)=>{
						if(section.get('page').value === tce.id){
							sectionsIndexToBeRemoved.push(idx);
						}
					});

					if(sectionsIndexToBeRemoved.length){
						sectionsIndexToBeRemoved.reverse().forEach(index=>{
							sections.removeAt(index);
						});
					}

					//update page ordinals
					for(let i=0; i<pages.length; i++){
						pages.at(i).get('ordinal').patchValue(i);
					}

					//update validity
					// this.form.controls.sections.updateValueAndValidity();
				}
				break;

			case ToCEntryType.Section:

				//FIRST LEVEL SECTION CASE
				let index = -1;


				const sections = (this.form.get('sections') as FormArray);

				for (let i = 0; i < sections.length; i++) {

					let section = sections.at(i);

					let sectionId = section.get('id').value;
					if (sectionId == tce.id) {
						index = i;
						break;
					}
				}


				if (index >= 0) { //section found

					const sections = (this.form.get('sections') as FormArray);

					//remove section
					this._updateSelectedItem(tce);
					sections.removeAt(index);

					//update ordinal
					for(let i=0; i< sections.length; i++){
						sections.at(i).get('ordinal').patchValue(i);
					}
				} else {//NOT FOUND IN FIRST LEVEL CASE

					//LOOK FOR SUBSECTION CASE
					let parentFormArray = tce.form.parent as FormArray;

					for (let i = 0; i < parentFormArray.length; i++) {
						let section = parentFormArray.at(i);

						if (section.get('id').value == tce.id) {
							index = i;
							break;
						}
					}
					if (index >= 0) {
						this._updateSelectedItem(tce);
						parentFormArray.removeAt(index);

						//update odrinal

						for(let i=0; i<parentFormArray.length; i++){
							parentFormArray.at(i).get('ordinal').patchValue(i);
						}
					}

				}

				break;
			case ToCEntryType.FieldSet:
				const parentFormArray =  tce.form.parent as FormArray;


				let idx = -1;

				for(let i =0; i< parentFormArray.length; i++){
					let inspectingField = parentFormArray.at(i);

					if(inspectingField.get('id').value === tce.id){
						//fieldset found
						idx = i;
						break;
					}
				}

				if(idx>=0){//fieldset found
					this._updateSelectedItem(tce);
					parentFormArray.removeAt(idx);

					//patching order
					for(let i=0; i<parentFormArray.length;i++){
						parentFormArray.at(i).get('ordinal').patchValue(i);
					}
				}
				break;
			default:
				break;
		}

		//in case selectedtocentrhy is child of the removed element

		// this.refreshToCEntries();
		this.onDataNeedsRefresh();
		this.form.updateValueAndValidity();

	}


	private _updateSelectedItem(tce: ToCEntry){

		if(this.selectedTocEntry ){

			if(this.tocEntryIsChildOf(this.selectedTocEntry,tce)){
				if(this.selectedTocEntry.type ==  ToCEntryType.Page){
					this.selectedTocEntry = null;
				}else{

					//if first level section
					const firstLevelSections = (this.form.get('sections') as FormArray);
					let isFirstLevel: boolean = false;
					firstLevelSections.controls.forEach(section=>{
						if(section.get('id').value === tce.id){
							isFirstLevel = true;
						}
					});

					let parentId = null;
					if(isFirstLevel){
						parentId = tce.form.get('page').value;
					}else{
						parentId = tce.form.parent.parent.get('id').value
					}

					// const parentId = tce.form.parent.parent.get('id').value;
					if(parentId){
						const tocentries = this.getTocEntries();
						const parent = this._findTocEntryById(parentId, tocentries);

						if(parent){
							this.selectedTocEntry = parent;
						}else{
							this.selectedTocEntry = null;
						}
					}else{
						this.selectedTocEntry = null;
					}
				}
			}
		}
	}

	tocEntryIsChildOf(testingChild: ToCEntry,parent: ToCEntry): boolean{

		if(!testingChild || !parent) return false;

		if(testingChild.id == parent.id){return true;}

		if(parent.subEntries){
			let childFound:boolean = false;

			parent.subEntries.forEach(subEntry=>{
				if(this.tocEntryIsChildOf(testingChild, subEntry)){
					childFound = true;
					return true;
				}
			})

			return childFound;
		}
		return false;
	}

	selectedTocEntry: ToCEntry
	displayItem(entry: ToCEntry): void {
		this.selectedTocEntry = entry;
	}

	get numOfPages(){
		return (<FormArray>this.form.get('pages')).length;
	}

	// getSectionIndex(): number{
	// 	// if(this.sectionIdPreviewed == null) return;
	// 	const valuesArray = this.form.get('sections').value;
	// 	let currentVal = this.sectionIdPreviewed;
	// 	let indexArray:string[] = valuesArray.map(element=> element.page);
	// 	let index = indexArray.indexOf(currentVal);
	// 	console.log(index);
	// 	return index ? index :-1;
	// }

	// getCurrentEditorModel(): SectionEditorModel{
	// 	let currentEditor = this.dataModel.sections.filter(section=> section.page == this.sectionIdPreviewed)[0];
	// 	return currentEditor;

	// }


	// subForm(){
	// 	const valuesArray = this.form.get('sections').value;
	// 	let currentVal = this.sectionIdPreviewed;
	// 	let indexArray:string[] = valuesArray.map(element=> element.page);
	// 	let index = indexArray.indexOf(currentVal);
	// 	let subForm = (this.form.get('sections') as FormArray).controls[index];
	// 	console.log(subForm);
	// 	return subForm;
	// }

	getFieldTile(formGroup: FormGroup, index: number) {
		if (formGroup.get('title') && formGroup.get('title').value && formGroup.get('title').value.length > 0) { return formGroup.get('title').value; }
		return "Field " + (index + 1);
	}

	deleteFieldSet(formArray: FormArray, index: number) {
		formArray.removeAt(index);
	}



	printForm(){
		// console.log(this.form.value);
		console.log(this.form);
	}

	get barPercentage(){
		if(!this.stepper || !this.steps){
			return 0;
		}
		const selectedIndex = this.stepper.selectedIndex + 1;
		return (selectedIndex / this.stepper.steps.length) * 100;
	}


	get progressStyle(){
		// return {'transform': 'translateX('+this.barPercentage+'%) skewX(-25deg)'}
		const diff = 3;

		return {
			'clip-path': `polygon(0 0, ${Math.round(this.barPercentage + diff)}% 0, ${Math.round(this.barPercentage)}% 100%, 0 100%)`
		}
	}

	steps:QueryList<CdkStep>;
	// get steps(){
	// 	if(!this.stepper){
	// 		return [];
	// 	}

	// 	return this.stepper.steps;
	// }


	// generatePreviewForm(){


	// 	const model =  new DatasetDescriptionFormEditorModel();

	// 	const toCentries = this.getTocEntries();


	// 	//first level is always pages
	// 	model.pages = toCentries.map((entry,idx)=>{
	// 		if( !(entry.type == ToCEntryType.Page)){
	// 			return null;
	// 		}
	// 		const pageModel = new DatasetDescriptionPageEditorModel();

	// 		pageModel.ordinal = entry.form.get('ordinal').value;
	// 		pageModel.title = entry.label;

	// 		if(entry.subEntries){
	// 			pageModel.sections = entry.subEntries.map(section=>{
	// 				const sectionModel = new DatasetDescriptionSectionEditorModel();

	// 				sectionModel.id = section.id;
	// 				sectionModel.ordinal = section.form.get('ordinal').value;
	// 				sectionModel.description = section.form.get('description').value;
	// 				sectionModel.page = entry.form.get('ordinal').value;
	// 				sectionModel.title = section.label;
	// 				sectionModel.numbering = (idx+1).toString();


	// 				if(section.subEntriesType == ToCEntryType.Section){
	// 					sectionModel.sections = this._buildSectionsRecursively(section.subEntries, sectionModel.numbering);
	// 				}else{
	// 					sectionModel.compositeFields = this._buildFormFields(section.subEntries, sectionModel.numbering)
	// 				}

	// 				return sectionModel;
	// 			});
	// 		};
	// 		return pageModel;

	// 	});


	// 	//populate rules
	// 	const rules:Rule[] =[];
	// 	const fieldSets = this._getFieldSets(toCentries);

	// 	fieldSets.forEach(fs=>{
	// 		const fields = fs.form.get('fields') as FormArray;
	// 		if(fields){
	// 			fields.controls.forEach(field=>{
	// 				const rulesArray = field.get('visible').get('rules').value;
	// 				if(rulesArray){
	// 					rulesArray.forEach(ruleElement => {
	// 						const rule: Rule = new Rule();
	// 						rule.targetField = ruleElement.target;
	// 						rule.sourceField = field.get('id').value;
	// 						rule.requiredValue = ruleElement.value;
	// 						rules.push(rule);
	// 					});
	// 				}
	// 			});
	// 		}
	// 	});

	// 	model.rules = rules;
	// 	this.visibilityRules = rules;

	// 	this.previewForm = model.buildForm();
	// }


	updateVisibilityRules(){
		const rules:Rule[] =[];
		const fieldSets = this._getFieldSets(this.getTocEntries());

		fieldSets.forEach(fs=>{
			const fields = fs.form.get('fields') as FormArray;
			if(fields){
				fields.controls.forEach(field=>{
					const rulesArray = field.get('visible').get('rules').value;
					if(rulesArray){
						rulesArray.forEach(ruleElement => {
							const rule: Rule = new Rule();
							rule.targetField = ruleElement.target;
							rule.sourceField = field.get('id').value;
							rule.requiredValue = ruleElement.value;
							rules.push(rule);
						});
					}
				});
			}
		});

		this.visibilityRules = rules;

	}

	visibilityRules:Rule[];
	private _buildSectionsRecursively( tocentries: ToCEntry[], parentNumbering:string): DatasetDescriptionSectionEditorModel[]{


		if(!tocentries) return null;


		const result: Array<DatasetDescriptionSectionEditorModel> = [];

		tocentries.forEach((tocentry, idx)=>{

			const sectionModel = new DatasetDescriptionSectionEditorModel();
			sectionModel.id = tocentry.id;
			sectionModel.ordinal = tocentry.form.get('ordinal').value;
			sectionModel.description = tocentry.form.get('description').value;
			// sectionModel.page = entry.form.get('ordinal').value;
			sectionModel.title = tocentry.label;
			// sectionModel.numbering = tocentry.numbering;
			sectionModel.numbering = parentNumbering+"."+(idx+1);;

			if(tocentry.subEntriesType == ToCEntryType.Section){
				sectionModel.sections = this._buildSectionsRecursively(tocentry.subEntries, sectionModel.numbering);

			}else{
				sectionModel.compositeFields = this._buildFormFields(tocentry.subEntries, sectionModel.numbering);
			}

			result.push(sectionModel);
		})

		return result;
	}

	private _buildFormFields(tocentries: ToCEntry[], parentNumbering: string):DatasetDescriptionCompositeFieldEditorModel[]{
		if(!tocentries) return null;

		const fieldsets:DatasetDescriptionCompositeFieldEditorModel[] = [];

		tocentries.forEach((fs, idx)=>{

			const fieldset = new DatasetDescriptionCompositeFieldEditorModel();

			fieldset.description = fs.form.get('description').value;
			fieldset.extendedDescription = fs.form.get('extendedDescription').value;
			fieldset.id = fs.form.get('id').value;
			fieldset.multiplicity = fs.form.get('multiplicity').value;
			fieldset.additionalInformation = fs.form.get('additionalInformation').value;
			fieldset.ordinal = fs.form.get('ordinal').value;
			// fieldset.numbering = fs.numbering;
			fieldset.numbering = parentNumbering+"."+(idx+1);
			fieldset.hasCommentField = fs.form.get('hasCommentField').value;
			fieldset.title = fs.label;
			// fieldset.fields = (fs.form.get('fields') as FormArray).getRawValue();
			fieldset.fields = (fs.form.get('fields') as FormArray).controls.map(field=>{

				const fieldModel = new DatasetDescriptionFieldEditorModel();

				fieldModel.data = (field.get('data') as FormGroup).getRawValue();
				fieldModel.id = field.get('id').value;
				fieldModel.viewStyle = (field.get('viewStyle') as FormGroup).getRawValue();
				// fieldModel.defaultValue = (field.get('defaultValue') as FormGroup).getRawValue();
				fieldModel.value = (field.get('defaultValue') as FormGroup).get('value').value;
				fieldModel.defaultValue = fieldModel.value;
				fieldModel.page = field.get('page').value;
				fieldModel.validations = field.get('validations').value;

				return fieldModel;
			});



			fieldsets.push(fieldset);
		});

		return fieldsets;
	}

	private _getFieldSets(tocentries: ToCEntry[]):ToCEntry[]{

		const fieldsets:ToCEntry[] = [];

		if(!tocentries) return fieldsets;

		tocentries.forEach(entry=>{
			if(entry.type == ToCEntryType.FieldSet){
				fieldsets.push(entry);
			}else{
				fieldsets.push(...this._getFieldSets(entry.subEntries));
			}
		});

		return fieldsets;
	}



	// get basicInfo(){

	// 	const label = this.form.get('label');
	// 	const description = this.form.get('description');
	// 	const language = this.form.get('language');



	// 	const fg = new FormGroup({
	// 		label: label,
	// 		description: description,
	// 		language: language
	// 	})

	// 	return fg;
	// }





	onMatStepperSelectionChange(event: StepperSelectionEvent){

		if(event.selectedIndex === (this.steps.length -1)){//preview selected
			// this.generatePreviewForm();//TODO LAZY LOADING IN THE TEMPLATE
			this.getPreview();
		}else{
			// this.previewForm = null;
			this.formGroup = null;
		}
		this.form.markAsUntouched();

	}

	// previewForm:FormGroup;
	onDataNeedsRefresh(params?){

		const tocentries = this.refreshToCEntries();

		if(params && params.draggedItemId){
			if(params.draggedItemId){
				this.displayItem(this._findTocEntryById(params.draggedItemId, tocentries));
			}
		}
		this.form.markAsDirty();
	}

	cloneFieldSet(fieldset: FormGroup){
		const values = fieldset.getRawValue();
		const parentArray = fieldset.parent as FormArray;

		values.id = Guid.create().toString();
		values.ordinal = parentArray.length;

		values.fields.forEach(element => {
			element.id = Guid.create().toString()
		});


		const clonedModel = new FieldSetEditorModel().fromModel(values);
		const clonedForm = clonedModel.buildForm();
		parentArray.push(clonedForm);

		//update tocentries and make selected tocentry the cloedn
		let entries = this.refreshToCEntries();

		const entryfound = this._findTocEntryById(clonedForm.get('id').value, entries);
		if(entryfound){
			this.selectedTocEntry = entryfound;
		}

		// 		//create one field form fieldset
		// const field: FieldEditorModel = new FieldEditorModel(); //to ask
		// field.id = Guid.create().toString();
		// field.ordinal = 0;//first filed in the fields list
		// fieldSet.fields.push(field);
		// // field.ordinal = fieldSet.fields.length-1;

		// //give fieldset id and ordinal
		// fieldSet.id = Guid.create().toString();
		// fieldSet.ordinal = (parent.form.get('fieldSets') as FormArray).length;

		// (<FormArray>parent.form.get('fieldSets')).push(fieldSet.buildForm());

		// // const parentArray = parent.form.get('fieldSets') as FormArray;
		// const addedFieldSet = parentArray.at(parentArray.length - 1);




	}

	isStepCompleted(stepIndex: number){

		let stepCompleted = false;
		this.steps.forEach((step,index)=>{
			if(stepIndex === index){
				stepCompleted = step.completed;
			}
		});

		return stepCompleted;
	}

	isStepUnlocked(stepIndex: number): boolean{
		if(stepIndex === 0) return true;
		if(stepIndex <0 ) return false;
		//if previous step is valid then unlock
		let stepUnlocked: boolean = false;

		if(!this.isStepUnlocked(stepIndex -1)) return false;

		this.steps.forEach((step,index)=>{

			if(index+1 == stepIndex){//previous step

				if(step.completed){
					stepUnlocked = true;
				}
			}
		});

		return stepUnlocked;
	}

	validateStep(selectedIndex){

		if(selectedIndex === 1){//form description
			if(this.form.invalid){
				this.checkFormValidation();
			}
		}


		// if(step.hasError){
		// 	this.printMyErrors(this.form);
		// }
	}

	// getFormValidationErrors() {
	// 	Object.keys(this.form.controls).forEach(key => {

	// 		const controlErrors: ValidationErrors = this.form.get(key).errors;
	// 		if (controlErrors != null) {
	// 				Object.keys(controlErrors).forEach(keyError => {
	// 				console.log('Key control: ' + key + ', keyError: ' + keyError + ', err value: ', controlErrors[keyError]);
	// 				});
	// 			}
	// 	});

	// 	if(this.form.invalid){
	// 		console.log('this form is invalid!');
	// 		console.log(this.form.errors);
	// 	}
	// }



	private _buildErrorMessage(errors, numbering, key):string[]{
		const errmess: string[] = [];

		Object.keys(errors).forEach(keyError => {

			switch(keyError){
				case EditorCustomValidatorsEnum.atLeastOneSectionInPage:
					errmess.push( this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.PAGE-MUST-HAVE-SECTION'));
					break;
				case EditorCustomValidatorsEnum.emptyArray:
					errmess.push(numbering+this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.NEEDS-MORE-INFORMATION'))
					break;
				case EditorCustomValidatorsEnum.sectionMustHaveOneChild:
					errmess.push(numbering+this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.MUST-HAVE-SECTION-OR-FIELDSET'))
					break;
				default:
				if (typeof errors[keyError] === 'boolean') {
					errmess.push(numbering + ' ' + key + ' is ' + keyError);
				} else {
					errmess.push(numbering + ' ' + key + ': ' + keyError + ': ' + JSON.stringify(errors[keyError]));
				}

			}

		});

		return errmess;
	}


	printMyErrors(form: AbstractControl){
		// this._printToCentriesErrrors(this.toCEntries);
		const result = this._getErrors(form);

		// console.log('got errors ');
		// console.log(result);

		if(result && form.invalid){
			const errmess:string[] = [];
			if(result.length){
				form.markAllAsTouched();

				let indexes:number[] = [];
				///search in pages,sections and fieldsets  for the id
				result.forEach((err,i)=>{
					const entry = this._findTocEntryById(err.id, this.toCEntries);
					if(entry){

						// errmess.push(`Error on ${entry.numbering} ${entry.label} . ${err.key}`);
						errmess.push(...this._buildErrorMessage(err.errors, entry.numbering, err.key));
						indexes.push(i);
					}
				});
				indexes.reverse().forEach(index=>{
					result.splice(index,1);
				});

				indexes = [];
				//searching in fields
				const fieldsets = this._getAllFieldSets(this.toCEntries);
				result.forEach((err,i)=>{
					fieldsets.filter(fs=>{
						let fieldFound = false;
						(fs.form.get('fields') as FormArray).controls.forEach(field=>{
							if(field.get('id').value === err.id){
								fieldFound = true;
								indexes.push(i);
							}
						});
						return fieldFound;
					})
					//printing fieldsets that the field missing
					.forEach(fs=>{
						// errmess.push(`Missing input in ${fs.numbering} ${fs.label} . ${err.key}`);
						errmess.push(...this._buildErrorMessage(err.errors, fs.numbering, err.key));
					});
				});

				indexes.reverse().forEach(index=>{
					result.splice(index,1);
				});

				result.forEach(err=>{
					// console.log(err);
					if(err.key){
						errmess.push(`${this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.MISSING')} ${err.key}` );
					}else{

						errmess.push(this.language.instant('DATASET-PROFILE-EDITOR.STEPS.FORM.FORM-VALIDATION.ERROR-MESSAGES.PROVIDE-PAGE-AND-SECTION'));
					}
					// errmess.push(...this._buildErrorMessage(err.errors,"", err.key) );

				})
			}

			const dialogRef = this.dialog.open(FormValidationErrorsDialogComponent, {
				disableClose: true,
				autoFocus: false,
				restoreFocus: false,
				data: {
					errorMessages: errmess,
					projectOnly: false
				},
			});
		}
	}

	/**
	 * Get all filedsets in a tocentry array;
	 * @param entries Tocentries to search in
	 * @returns The tocentries that are Fieldsets provided in the entries
	 */
	private _getAllFieldSets(entries: ToCEntry[]):ToCEntry[]{

		const fieldsets:ToCEntry[] = [];
		if(!entries || !entries.length) return fieldsets;


		entries.forEach(e=>{
			if(e.type === ToCEntryType.FieldSet){
				fieldsets.push(e);
			}else{
				fieldsets.push(...this._getAllFieldSets(e.subEntries));
			}
		});
		return fieldsets;
	}


	private _getErrors(aControl: AbstractControl):InvalidControl[]{


		if(aControl.valid) return;

		let controlType = 'control';

		if(aControl instanceof FormGroup) controlType="fg"
		if(aControl instanceof FormControl) controlType="fc";
		if(aControl instanceof FormArray) controlType="fa";


		const invalidControls:InvalidControl[] = [];
		//invalid
		switch (controlType){
			case 'fg':

				const controls = (aControl as FormGroup).controls;
				const keys = Object.keys(controls);
				keys.forEach(key=>{
					const control = controls[key];
					if(!control.invalid) return; //// !!!!! Important to be !invalid. (In case the template is finalized)

					if(control instanceof FormControl){
						const ctrl = control as FormControl;

						invalidControls.push({
							errors:ctrl.errors,
							id: ctrl.get('id')? ctrl.get('id').value: null,
							invalidSubControls: [],
							key: key
						});

					}else{
						// if(aControl.errors){
						// 	invalidControls.push({
						// 		id: aControl.get('id')? aControl.get('id').value: null,
						// 		errors:aControl.errors,
						// 		key: aControl.get('title')? aControl.get('title').value: 'unspecified',
						// 		invalidSubControls:[]//TODO TO CHECK
						// 	});
						// }


						//THE ONE WE REMOVED
						// if(control.errors){
						// 	// invalidControls.push({
						// 	// 	id: aControl.get('id')? aControl.get('id').value: null,
						// 	// 	errors:aControl.errors,
						// 	// 	key: aControl.get('title')? aControl.get('title').value: 'unspecified',
						// 	// 	invalidSubControls:[]//TODO TO CHECK
						// 	// });

						// 	invalidControls.push({
						// 		errors:control.errors,
						// 		id: control.get('id')? control.get('id').value: null,
						// 		invalidSubControls: [],
						// 		key: key
						// 	});
						// }
						invalidControls.push(...this._getErrors(control)) ;

					}
				});

				/**In case there is an error in a formgroup then the validator probably is custom */
				if(aControl.errors){
					invalidControls.push({
						errors:aControl.errors,
						id: aControl.get('id')? aControl.get('id').value: null,
						invalidSubControls: [],
						key: aControl.get('title')?aControl.get('title').value: null
					});
				}

				break;
			case 'fa':
				// const fa = (aControl as FormArray);
				const ctrls = (aControl as FormArray).controls;
				const keys_ = Object.keys(ctrls);
				keys_.forEach(key=>{
					const control = ctrls[key];
					if(control.valid) return;


					if(control instanceof FormControl){ //for completion purposes. should never run this case
						const ctrl = control as FormControl;
						invalidControls.push({
							errors:ctrl.errors,
							id: ctrl.get('id')? ctrl.get('id').value: null,
							invalidSubControls: [],
							key: key
						});

					}else{
						invalidControls.push(... this._getErrors(control));
					}
				});

				break;
		}

		invalidControls.forEach(e=>{
			if(!e.id){
				e.id = aControl.get('id')? aControl.get('id').value : null;
			}
		})
		return invalidControls;

	}
	userFormDisabled:boolean = false;
	addUser(email:MatInput){

		// email.focus();
		if(this.userFormDisabled) return;

		// console.log('user add');
		if(this.inputUserState === 'triggered'){
			// this.checkAndAdd(email);

			of(email.value)
			.pipe(tap(_=> {this.userFormDisabled = true; email.focus()}))
			.pipe(mergeMap(email=>this.userService.getFromEmail(email)))
			.pipe(takeUntil(this._destroyed))
			.subscribe((result) => {
				this.userChipList.push(result);
				this.form.patchValue({'users': this.userChipList});

				email.value = '';
				this.userFormDisabled = false;
				this.form.markAsDirty();
				// email.focus();
				// this.inputUserState = 'triggered';


			},
			error=>{
				// console.log(error.message);
				this.uiNotificationService.snackBarNotification(this.language.instant('DATASET-PROFILE-EDITOR.STEPS.GENERAL-INFO.ERRORS.USER-NOT-FOUND'), SnackBarNotificationLevel.Error);
				this.userFormDisabled = false;
				// this.inputUserState = 'triggered';//when it loses focus(when disabled) it becomes untriggered
				// email.focus();
			});
			// this.inputUserState = 'untriggered';
		}else{
			this.inputUserState = 'triggered';
			email.focus();

		}
	}
	onUserButtonFocus(){
		this._inputUserButton$.next(true);
	}
	onUserButtonBlur(){
		this._inputUserButton$.next(false);
	}
	onUserFieldFocus(){
		this._inputUserField$.next(true);
	}
	onUserFieldBlur(){
		this._inputUserField$.next(false);
	}



	//Temporary patch
	/**
	 * Append custom validators to fields. Some validators are applied on template. In case they are never rendereed,
	 * he form might be valid when it shouldnt.
	 * @param
	 */
	private _initializeFormValidity(tocentries: ToCEntry[]) {
		const fieldsets = this._getAllFieldSets(tocentries);

		try{
			fieldsets.forEach(fs=>{
				fs.form.get('title').setValidators(Validators.required);
				const fieldsF = fs.form.get('fields') as FormArray;
				if(fieldsF){
					fieldsF.controls.forEach(field=>{
						const renderStyleValue = field.get('viewStyle').get('renderStyle').value;

						if(renderStyleValue === DatasetProfileFieldViewStyle.CheckBox){
							field.get('defaultValue').get('value').setValidators(Validators.required);
						}else if(renderStyleValue === 'combobox'){

							const comboType = field.get('data').get('type').value;
							if(comboType === DatasetProfileComboBoxType.Autocomplete){//As 'Other' in UI
								field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('autoCompleteSingleDataList'));
							}else if(comboType === DatasetProfileComboBoxType.WordList){
								field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options'));
							}

						}else if(renderStyleValue === DatasetProfileFieldViewStyle.RadioBox){
							field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('options'));
						} else if(renderStyleValue === DatasetProfileFieldViewStyle.Upload) {
							field.get('data').setValidators(EditorCustomValidators.atLeastOneElementListValidator('types'));
							field.get('data').get('maxFileSizeInMB').setValidators(Validators.required);
						}
					});
				}
			});
		}catch(e){
			console.error('Error initializing validators.');
			console.error(e);
		}

	}

	checkAndAdd(ev: any) {
		this.userService.getFromEmail(ev).pipe(takeUntil(this._destroyed)).subscribe((result) => {
			this.userChipList.push(result);
			this.form.patchValue({'users': this.userChipList});
		});
	}

	removeUser(user: any) {
		this.userChipList.splice(this.userChipList.indexOf(user), 1);
		this.form.patchValue({'users': this.userChipList});
		this.form.markAsDirty();//deactivate guard
	}


	verifyAndRemoveUser(user:any){
		const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
			restoreFocus: false,
			data: {
				message: this.language.instant('GENERAL.CONFIRMATION-DIALOG.DELETE-ITEM'),
				confirmButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CONFIRM'),
				cancelButton: this.language.instant('GENERAL.CONFIRMATION-DIALOG.ACTIONS.CANCEL'),
				isDeleteConfirmation: true
			}
		});
		dialogRef.afterClosed().pipe(takeUntil(this._destroyed)).subscribe(approve => {
			if (approve) {
				this.removeUser(user);
			}
		});
	}

	scrollOnTop(){
		try{
			const topPage = document.getElementById('main-content');
			topPage.scrollIntoView({behavior:'smooth'});
		}catch{
			console.log('coulnd not scroll');
		}
	}

	updateAndFinalize(close: boolean = false){
		if(this.form.get('status').value == DatasetProfileEnum.FINALIZED ){
			//UPDATE FORM
			if(this.newVersionId){
				this.onSubmit(close);
			}else{
				this.updateFinalized(close);
			}
		}else{
			//finalize
			this.finalize();
		}

	}
	discardChanges(){
		this.router.navigate([
			'dataset-profiles'
		]);
	}

}

interface InvalidControl{
	key: string,
	errors: any,
	id: string,
	invalidSubControls: InvalidControl[]
}
