Provide index token to tosca function for nested lists
[sdc.git] / catalog-ui / src / app / ng2 / pages / properties-assignment / tosca-function / tosca-get-function / tosca-get-function.component.ts
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2021 Nordix Foundation
4  *  ================================================================================
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 import {Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges} from '@angular/core';
21 import {AttributeBEModel, ComponentMetadata, DataTypeModel, PropertyBEModel, PropertyModel, PropertyDeclareAPIModel, DerivedFEProperty} from 'app/models';
22 import {TopologyTemplateService} from "../../../../services/component-services/topology-template.service";
23 import {WorkspaceService} from "../../../workspace/workspace.service";
24 import {PropertiesService} from "../../../../services/properties.service";
25 import {PROPERTY_DATA, PROPERTY_TYPES} from "../../../../../utils/constants";
26 import {DataTypeService} from "../../../../services/data-type.service";
27 import {ToscaGetFunctionType} from "../../../../../models/tosca-get-function-type";
28 import {TranslateService} from "../../../../shared/translator/translate.service";
29 import {ComponentGenericResponse} from '../../../../services/responses/component-generic-response';
30 import {Observable} from 'rxjs/Observable';
31 import {PropertySource} from "../../../../../models/property-source";
32 import {InstanceFeDetails} from "../../../../../models/instance-fe-details";
33 import {ToscaGetFunction} from "../../../../../models/tosca-get-function";
34 import {FormControl, FormGroup, Validators} from "@angular/forms";
35 import {ToscaGetFunctionTypeConverter} from "../../../../../models/tosca-get-function-type-converter";
36
37 @Component({
38     selector: 'app-tosca-get-function',
39     templateUrl: './tosca-get-function.component.html',
40     styleUrls: ['./tosca-get-function.component.less']
41 })
42 export class ToscaGetFunctionComponent implements OnInit, OnChanges {
43
44     @Input() property: PropertyBEModel;
45     @Input() overridingType: PROPERTY_TYPES;
46     @Input() toscaGetFunction: ToscaGetFunction;
47     @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
48     @Input() functionType: ToscaGetFunctionType;
49     @Input() compositionMap: boolean;
50     @Input() compositionMapKey: string;
51     @Output() onValidFunction: EventEmitter<ToscaGetFunction> = new EventEmitter<ToscaGetFunction>();
52     @Output() onValidityChange: EventEmitter<ToscaGetFunctionValidationEvent> = new EventEmitter<ToscaGetFunctionValidationEvent>();
53
54     formGroup: FormGroup = new FormGroup({
55         'selectedProperty': new FormControl(undefined, Validators.required),
56         'propertySource': new FormControl(undefined, Validators.required)
57     });
58
59     isLoading: boolean = false;
60     propertyDropdownList: Array<PropertyDropdownValue> = [];
61     propertySourceList: Array<string> = [];
62     instanceNameAndIdMap: Map<string, string> = new Map<string, string>();
63     dropdownValuesLabel: string;
64     dropDownErrorMsg: string;
65     indexListValues:Array<ToscaIndexObject>;
66
67     private isInitialized: boolean = false;
68     private componentMetadata: ComponentMetadata;
69
70     constructor(private topologyTemplateService: TopologyTemplateService,
71                 private workspaceService: WorkspaceService,
72                 private propertiesService: PropertiesService,
73                 private dataTypeService: DataTypeService,
74                 private translateService: TranslateService) {
75     }
76
77     ngOnInit(): void {
78         this.componentMetadata = this.workspaceService.metadata;
79         this.indexListValues = [];
80         this.formGroup.valueChanges.subscribe(() => {
81             this.formValidation();
82         });
83         this.loadPropertySourceDropdown();
84         this.loadPropertyDropdownLabel();
85         this.initToscaGetFunction().subscribe(() => {
86             this.isInitialized = true;
87         });
88     }
89
90     ngOnChanges(_changes: SimpleChanges): void {
91         if (!this.isInitialized) {
92             return;
93         }
94         this.isInitialized = false;
95         this.resetForm();
96         this.loadPropertySourceDropdown();
97         this.loadPropertyDropdownLabel();
98         this.initToscaGetFunction().subscribe(() => {
99             this.isInitialized = true;
100         });
101     }
102
103     private initToscaGetFunction(): Observable<void> {
104         return new Observable(subscriber => {
105             if (!this.toscaGetFunction) {
106                 if (this.isGetInput()) {
107                     this.setSelfPropertySource();
108                     this.loadPropertyDropdown();
109                 }
110                 subscriber.next();
111                 return;
112             }
113             if (this.toscaGetFunction.propertySource == PropertySource.SELF) {
114                 this.propertySource.setValue(PropertySource.SELF);
115             } else if (this.toscaGetFunction.propertySource == PropertySource.INSTANCE) {
116                 this.propertySource
117                 .setValue(this.propertySourceList.find(source => this.toscaGetFunction.sourceName === source));
118             }
119             if (this.propertySource.valid) {
120                 this.loadPropertyDropdown(() => {
121                     this.selectedProperty
122                     .setValue(this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName));
123                     if (this.toscaGetFunction.toscaIndexList.length > 0) {
124                         let tempSelectedProperty : PropertyDropdownValue = this.selectedProperty.value;
125                         this.toscaGetFunction.toscaIndexList.forEach((indexValue: string, index) => {
126                             let tempIndexFlag = false;
127                             let tempNestedFlag = false;
128                             let tempIndexValue = "0";
129                             let tempIndexProperty = tempSelectedProperty;
130                             let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
131                             if (index%2 == 0) {
132                                 tempIndexFlag = true;
133                                 tempIndexValue = indexValue;
134                                 tempSelectedProperty = null;
135                                 if (this.toscaGetFunction.toscaIndexList[index+1]) {
136                                     tempNestedFlag = true;
137                                     if (tempIndexProperty.schemaType != null) {
138                                         const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, tempIndexProperty.schemaType);
139                                         this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
140                                         tempSelectedProperty = subPropertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.toscaIndexList[index+1])
141                                     }
142                                 }
143                                 let tempIndexValueMap : ToscaIndexObject = {indexFlag : tempIndexFlag, nestedFlag : tempNestedFlag, indexValue: tempIndexValue, indexProperty: tempSelectedProperty, subPropertyArray: subPropertyDropdownList};
144                                 this.indexListValues.push(tempIndexValueMap);
145                             }
146                         });
147                     }
148                     subscriber.next();
149                 });
150             } else {
151                 subscriber.next();
152             }
153         });
154     }
155
156     private buildGetFunctionFromForm() {
157         const toscaGetFunction = new ToscaGetFunction();
158         toscaGetFunction.type = ToscaGetFunctionTypeConverter.convertToToscaFunctionType(this.functionType);
159         toscaGetFunction.functionType = this.functionType;
160         const propertySource = this.propertySource.value;
161         if (this.isPropertySourceSelf()) {
162             toscaGetFunction.propertySource = propertySource
163             toscaGetFunction.sourceName = this.componentMetadata.name;
164             toscaGetFunction.sourceUniqueId = this.componentMetadata.uniqueId;
165         } else {
166             toscaGetFunction.propertySource = PropertySource.INSTANCE;
167             toscaGetFunction.sourceName = propertySource;
168             toscaGetFunction.sourceUniqueId = this.instanceNameAndIdMap.get(propertySource);
169         }
170
171         const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
172         toscaGetFunction.propertyUniqueId = selectedProperty.propertyId;
173         toscaGetFunction.propertyName = selectedProperty.propertyName;
174         toscaGetFunction.propertyPathFromSource = selectedProperty.propertyPath;
175         if (this.indexListValues.length > 0) {
176             let indexAndProperty : Array<string> = [];
177             this.indexListValues.forEach((indexObject : ToscaIndexObject) => {
178                 indexAndProperty.push(indexObject.indexValue);
179                 if(indexObject.nestedFlag && indexObject.indexProperty != null) {
180                     indexAndProperty.push(indexObject.indexProperty.propertyName);
181                 }
182             });
183             toscaGetFunction.toscaIndexList = indexAndProperty;
184         }
185         return toscaGetFunction;
186     }
187
188     private loadPropertySourceDropdown(): void {
189         if (this.isGetInput()) {
190             return;
191         }
192         this.propertySourceList = [];
193         this.propertySourceList.push(PropertySource.SELF);
194         this.componentInstanceMap.forEach((value, key) => {
195             const instanceName = value.name;
196             this.instanceNameAndIdMap.set(instanceName, key);
197             if (instanceName !== PropertySource.SELF) {
198                 this.addToPropertySource(instanceName);
199             }
200         });
201     }
202
203     private addToPropertySource(source: string): void {
204         this.propertySourceList.push(source);
205         this.propertySourceList.sort((a, b) => {
206             if (a === PropertySource.SELF) {
207                 return -1;
208             } else if (b === PropertySource.SELF) {
209                 return 1;
210             }
211
212             return a.localeCompare(b);
213         });
214     }
215
216     private formValidation(): void {
217         if (!this.isInitialized) {
218             return;
219         }
220         let formGroupStatus : boolean = this.formGroup.valid;
221         const selectedProperty: PropertyDropdownValue = this.formGroup.value.selectedProperty;
222         if (selectedProperty != null && selectedProperty.isList && formGroupStatus && this.indexListValues.length > 0) {
223             this.indexListValues.forEach((indexObject : ToscaIndexObject, index) => {
224                 if (indexObject.indexValue == null) {
225                     formGroupStatus = false;
226                     return;
227                 }
228                 if (indexObject.nestedFlag && indexObject.indexProperty == null) {
229                     formGroupStatus = false;
230                     return;
231                 }
232             });
233         }
234         this.onValidityChange.emit({
235             isValid: formGroupStatus,
236             toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
237         });
238         if (this.formGroup.valid) {
239             this.onValidFunction.emit(this.buildGetFunctionFromForm());
240         }
241     }
242
243     private loadPropertyDropdown(onComplete?: () => any): void  {
244         this.loadPropertyDropdownLabel();
245         this.loadPropertyDropdownValues(onComplete);
246     }
247
248     private resetForm(): void {
249         this.formGroup.reset();
250     }
251
252     private loadPropertyDropdownLabel(): void {
253         if (!this.functionType) {
254             return;
255         }
256         if (this.isGetInput()) {
257             this.dropdownValuesLabel = this.translateService.translate('INPUT_DROPDOWN_LABEL');
258         } else if (this.isGetProperty()) {
259             this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_PROPERTY_DROPDOWN_LABEL');
260         } else if (this.isGetAttribute()) {
261             this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_ATTRIBUTE_DROPDOWN_LABEL');
262         }
263     }
264
265     private loadPropertyDropdownValues(onComplete?: () => any): void {
266         if (!this.functionType) {
267             return;
268         }
269         this.resetPropertyDropdown();
270         this.fillPropertyDropdownValues(onComplete);
271     }
272
273     private resetPropertyDropdown(): void {
274         this.dropDownErrorMsg = undefined;
275         this.selectedProperty.reset();
276         this.indexListValues = [];
277         this.propertyDropdownList = [];
278     }
279
280     private fillPropertyDropdownValues(onComplete?: () => any): void {
281         this.startLoading();
282         const propertiesObservable: Observable<ComponentGenericResponse> = this.getPropertyObservable();
283         propertiesObservable.subscribe( (response: ComponentGenericResponse) => {
284             const properties: Array<PropertyBEModel | AttributeBEModel> = this.extractProperties(response);
285             if (!properties || properties.length === 0) {
286                 const msgCode = this.getNotFoundMsgCode();
287                 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
288                 return;
289             }
290             this.addPropertiesToDropdown(properties, this.propertyDropdownList);
291             if (this.propertyDropdownList.length == 0) {
292                 const msgCode = this.getNotFoundMsgCode();
293                 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
294             }
295         }, (error) => {
296             console.error('An error occurred while loading properties.', error);
297             this.stopLoading();
298         }, () => {
299             if (onComplete) {
300                 onComplete();
301             }
302             this.stopLoading();
303         });
304     }
305
306     private getNotFoundMsgCode(): string {
307         if (this.isGetInput()) {
308             return 'TOSCA_FUNCTION_NO_INPUT_FOUND';
309         }
310         if (this.isGetAttribute()) {
311             return 'TOSCA_FUNCTION_NO_ATTRIBUTE_FOUND';
312         }
313         if (this.isGetProperty()) {
314             return 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
315         }
316
317         return undefined;
318     }
319
320     private propertyTypeToString() {
321             if (this.isSubProperty()){
322             if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty)
323                 || this.compositionMap) {
324                 if(this.isComplexType(this.property.schemaType) && !this.compositionMap){
325                     let mapChildProp : DerivedFEProperty = (<DerivedFEProperty> (<PropertyDeclareAPIModel> this.property).input);
326                     let propertySchemaType = mapChildProp.type;
327                     if (this.property.type == PROPERTY_TYPES.MAP || propertySchemaType == PROPERTY_TYPES.MAP) {
328                         if (mapChildProp.mapKey != '' && mapChildProp.mapKey != null && mapChildProp.schema.property.type != null) {
329                             propertySchemaType = mapChildProp.schema.property.type;
330                         }
331                     }
332                     if ((propertySchemaType == PROPERTY_TYPES.MAP || (propertySchemaType == PROPERTY_TYPES.LIST && mapChildProp.schema.property.type == PROPERTY_TYPES.MAP))
333                         && mapChildProp.isChildOfListOrMap) {
334                         propertySchemaType = PROPERTY_TYPES.STRING;
335                     }
336                     return  propertySchemaType;
337                 }else{
338                     return this.property.schema.property.type;
339                 }
340             }
341                 return this.getType((<PropertyDeclareAPIModel>this.property).propertiesName.split("#").slice(1),  this.property.type);
342         }
343         if (this.property.schemaType) {
344             return `${this.property.type} of ${this.property.schemaType}`;
345         }
346         return this.property.type;
347     }
348
349     private isSubProperty(): boolean{
350             return this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName && (<PropertyDeclareAPIModel>this.property).propertiesName.length > 1;
351     }
352
353     private extractProperties(componentGenericResponse: ComponentGenericResponse): Array<PropertyBEModel | AttributeBEModel> {
354         if (this.isGetInput()) {
355             return componentGenericResponse.inputs;
356         }
357         const instanceId = this.instanceNameAndIdMap.get(this.propertySource.value);
358         if (this.isGetProperty()) {
359             if (this.isPropertySourceSelf()) {
360                 return componentGenericResponse.properties;
361             }
362             return this.removeSelectedProperty(componentGenericResponse.componentInstancesProperties[instanceId]);
363         }
364         if (this.isPropertySourceSelf()) {
365             return [...(componentGenericResponse.attributes || []), ...(componentGenericResponse.properties || [])];
366         }
367         return [...(componentGenericResponse.componentInstancesAttributes[instanceId] || []),
368             ...(componentGenericResponse.componentInstancesProperties[instanceId] || [])];
369     }
370
371     private isPropertySourceSelf() {
372         return this.propertySource.value === PropertySource.SELF;
373     }
374
375     private getPropertyObservable(): Observable<ComponentGenericResponse> {
376         if (this.isGetInput()) {
377             return this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
378         }
379         if (this.isGetProperty()) {
380             if (this.isPropertySourceSelf()) {
381                 return this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
382             }
383             return this.topologyTemplateService.getComponentInstanceProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
384         }
385         if (this.isGetAttribute()) {
386             if (this.isPropertySourceSelf()) {
387                 return this.topologyTemplateService.findAllComponentAttributesAndProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
388             }
389             return this.topologyTemplateService.getComponentInstanceAttributesAndProperties(this.componentMetadata.uniqueId, this.componentMetadata.componentType);
390         }
391     }
392
393     private removeSelectedProperty(componentInstanceProperties: PropertyModel[]): PropertyModel[] {
394         if (!componentInstanceProperties) {
395             return [];
396         }
397         return componentInstanceProperties.filter(property =>
398             (property.uniqueId !== this.property.uniqueId) ||
399             (property.uniqueId === this.property.uniqueId && property.resourceInstanceUniqueId !== this.property.parentUniqueId)
400         );
401     }
402
403     private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue, propertyList: Array<PropertyDropdownValue>): void {
404         propertyList.push(propertyDropdownValue);
405         propertyList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
406     }
407
408     private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeBEModel>, propertyList: Array<PropertyDropdownValue>): void {
409         for (const property of properties) {
410             if (this.hasSameType(property)) {
411                 this.addPropertyToDropdown({
412                     propertyName: property.name,
413                     propertyId: property.uniqueId,
414                     propertyLabel: property.name,
415                     propertyPath: [property.name],
416                     isList: property.type === PROPERTY_TYPES.LIST,
417                     schemaType: (property.type === PROPERTY_TYPES.LIST && this.isComplexType(property.schema.property.type)) ? property.schema.property.type : null
418                 },propertyList);
419             } else if (this.isComplexType(property.type)) {
420                 this.fillPropertyDropdownWithMatchingChildProperties(property,propertyList);
421             }
422         }
423     }
424
425     private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeBEModel, propertyList: Array<PropertyDropdownValue>,
426                                                             parentPropertyList: Array<PropertyBEModel | AttributeBEModel> = []): void {
427         const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
428         if (!dataTypeFound || !dataTypeFound.properties) {
429             return;
430         }
431         parentPropertyList.push(inputProperty);
432         dataTypeFound.properties.forEach(dataTypeProperty => {
433             if (this.hasSameType(dataTypeProperty)) {
434                 this.addPropertyToDropdown({
435                     propertyName: dataTypeProperty.name,
436                     propertyId: parentPropertyList[0].uniqueId,
437                     propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
438                     propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name],
439                     isList : dataTypeProperty.type === PROPERTY_TYPES.LIST,
440                     schemaType: (dataTypeProperty.type === PROPERTY_TYPES.LIST && this.isComplexType(dataTypeProperty.schema.property.type)) ? dataTypeProperty.schema.property.type : null
441                 }, propertyList);
442             } else if (this.isComplexType(dataTypeProperty.type)) {
443                 this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, propertyList, [...parentPropertyList])
444             }
445         });
446     }
447
448     private hasSameType(property: PropertyBEModel | AttributeBEModel): boolean {
449         if (this.overridingType != undefined) {
450             return property.type === this.overridingType;
451         }
452         if (this.property.type === PROPERTY_TYPES.ANY) {
453             return true;
454         }
455         let validPropertyType = (this.property.type != PROPERTY_TYPES.LIST && property.type === PROPERTY_TYPES.LIST) ? property.schema.property.type : property.type;
456         if (this.property.type != PROPERTY_TYPES.LIST && property.type === PROPERTY_TYPES.LIST && this.isComplexType(validPropertyType)) {
457             let returnFlag : boolean = false;
458             const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, validPropertyType);
459             if (dataTypeFound && dataTypeFound.properties) {
460                 dataTypeFound.properties.forEach(dataTypeProperty => {
461                     if (this.hasSameType(dataTypeProperty)) {
462                         returnFlag =  true;
463                     }
464                 });
465             }
466             return returnFlag;
467         }
468         if (this.typeHasSchema(this.property.type)) {
469             if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty) || this.compositionMap) {
470                 let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
471                 let childSchemaType = this.property.schemaType != null ? this.property.schemaType : childObject.type;
472                 if(this.isComplexType(childSchemaType) && !this.compositionMap){
473                     if (childObject.type == PROPERTY_TYPES.MAP && childObject.isChildOfListOrMap) {
474                         return validPropertyType === PROPERTY_TYPES.STRING;
475                     }
476                     return validPropertyType === childObject.type;
477                 }else{
478                     return validPropertyType === this.property.schema.property.type;
479                 }
480             }
481             if (!property.schema || !property.schema.property) {
482                 return false;
483             }
484             return validPropertyType === this.property.type && this.property.schema.property.type === property.schema.property.type;
485         }
486         if (this.property.schema.property.isDataType && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName){
487             let typeToMatch = (<PropertyDeclareAPIModel> this.property).input.type;
488             let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
489             if (childObject.type == PROPERTY_TYPES.MAP && childObject.isChildOfListOrMap) {
490                 typeToMatch = PROPERTY_TYPES.STRING;
491             }
492             return validPropertyType === typeToMatch;
493         }
494
495         return validPropertyType === this.property.type;
496     }
497
498     private getType(propertyPath:string[], type: string): string {
499             const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, type);
500         let nestedProperty = dataTypeFound.properties.find(property => property.name === propertyPath[0]);
501         if (propertyPath.length === 1){
502                 return nestedProperty.type;
503         } 
504         return this.getType(propertyPath.slice(1), nestedProperty.type);
505     }
506
507     private isGetProperty(): boolean {
508         return this.functionType === ToscaGetFunctionType.GET_PROPERTY;
509     }
510
511     private isGetAttribute(): boolean {
512         return this.functionType === ToscaGetFunctionType.GET_ATTRIBUTE;
513     }
514
515     private isGetInput(): boolean {
516         return this.functionType === ToscaGetFunctionType.GET_INPUT;
517     }
518
519     private isComplexType(propertyType: string): boolean {
520         return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
521     }
522
523     private typeHasSchema(propertyType: string): boolean {
524         return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
525     }
526
527     private stopLoading(): void {
528         this.isLoading = false;
529     }
530
531     private startLoading(): void {
532         this.isLoading = true;
533     }
534
535     showPropertyDropdown(): boolean {
536         if (this.isGetProperty() || this.isGetAttribute()) {
537             return this.propertySource.valid && !this.isLoading && !this.dropDownErrorMsg;
538         }
539
540         return this.functionType && !this.isLoading && !this.dropDownErrorMsg;
541     }
542
543     onPropertySourceChange(): void {
544         this.selectedProperty.reset();
545         this.indexListValues = [];
546         if (!this.functionType || !this.propertySource.valid) {
547             return;
548         }
549         this.loadPropertyDropdown();
550     }
551
552     onPropertyValueChange(): void {
553         let toscaIndexFlag = false;
554         let nestedToscaFlag = false;
555         this.indexListValues = [];
556         let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
557         const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
558         if (selectedProperty.isList) {
559             toscaIndexFlag = true;
560             if (selectedProperty.schemaType != null) {
561                 nestedToscaFlag = true;
562                 const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
563                 this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
564             }
565         }
566         if (toscaIndexFlag || nestedToscaFlag) {
567             let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
568             this.indexListValues.push(indexValueMap);
569         }
570         this.formValidation();
571     }
572
573     onSubPropertyValueChange(indexObject : ToscaIndexObject, elementIndex: number): void {
574         let toscaIndexFlag = false;
575         let nestedToscaFlag = false;
576         let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
577         let selectedProperty: PropertyDropdownValue = indexObject.indexProperty;
578         if (selectedProperty.isList) {
579             toscaIndexFlag = true;
580             if (selectedProperty.schemaType != null) {
581                 nestedToscaFlag = true;
582                 const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
583                 this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
584             }
585         }
586         if (toscaIndexFlag || nestedToscaFlag) {
587             let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
588             if(!this.indexListValues[elementIndex+1]) {
589                 this.indexListValues.push(indexValueMap);
590             } else {
591                 this.indexListValues[elementIndex+1] = indexValueMap;
592             }
593         } else {
594             if(this.indexListValues[elementIndex+1]) {
595                 this.indexListValues.splice((elementIndex+1),1);
596             }
597         }
598         this.formValidation();
599     }
600
601     indexTokenChange(indexObject : ToscaIndexObject): void {
602         if ((indexObject.indexValue).toLowerCase() === 'index') {
603             this.formValidation();
604             return;
605         }
606         let indexTokenValue = Number(indexObject.indexValue);
607         if (isNaN(indexTokenValue)) {
608             indexObject.indexValue = "0";
609             this.formValidation();
610             return;
611         }
612         this.formValidation();
613     }
614
615     showPropertySourceDropdown(): boolean {
616         return this.isGetProperty() || this.isGetAttribute();
617     }
618
619     private setSelfPropertySource(): void {
620         this.propertySource.setValue(PropertySource.SELF);
621     }
622
623     private get propertySource(): FormControl {
624         return this.formGroup.get('propertySource') as FormControl;
625     }
626
627     private get selectedProperty(): FormControl {
628         return this.formGroup.get('selectedProperty') as FormControl;
629     }
630
631 }
632
633 export interface PropertyDropdownValue {
634     propertyName: string;
635     propertyId: string;
636     propertyLabel: string;
637     propertyPath: Array<string>;
638     isList: boolean;
639     schemaType: string;
640 }
641
642 export interface ToscaIndexObject {
643     indexFlag: boolean;
644     nestedFlag: boolean;
645     indexValue: string;
646     indexProperty: PropertyDropdownValue;
647     subPropertyArray: Array<PropertyDropdownValue>;
648 }
649
650 export interface ToscaGetFunctionValidationEvent {
651     isValid: boolean,
652     toscaGetFunction: ToscaGetFunction,
653 }