67df3e46e197efa9f7be903b99a0f21e246ac9d1
[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     parentListTypeFlag : boolean;
67
68     private isInitialized: boolean = false;
69     private componentMetadata: ComponentMetadata;
70
71     constructor(private topologyTemplateService: TopologyTemplateService,
72                 private workspaceService: WorkspaceService,
73                 private propertiesService: PropertiesService,
74                 private dataTypeService: DataTypeService,
75                 private translateService: TranslateService) {
76     }
77
78     ngOnInit(): void {
79         this.componentMetadata = this.workspaceService.metadata;
80         this.indexListValues = [];
81         if (this.property != null) {
82             this.parentListTypeFlag = (this.property.type != PROPERTY_TYPES.LIST && (!this.isComplexType(this.property.type) || (this.isComplexType(this.property.type) 
83                                     && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty && this.property.input.type != PROPERTY_TYPES.LIST)));
84         }
85         this.formGroup.valueChanges.subscribe(() => {
86             this.formValidation();
87         });
88         this.loadPropertySourceDropdown();
89         this.loadPropertyDropdownLabel();
90         this.initToscaGetFunction().subscribe(() => {
91             this.isInitialized = true;
92         });
93     }
94
95     ngOnChanges(_changes: SimpleChanges): void {
96         if (!this.isInitialized) {
97             return;
98         }
99         this.isInitialized = false;
100         this.resetForm();
101         this.loadPropertySourceDropdown();
102         this.loadPropertyDropdownLabel();
103         this.initToscaGetFunction().subscribe(() => {
104             this.isInitialized = true;
105         });
106     }
107
108     private initToscaGetFunction(): Observable<void> {
109         return new Observable(subscriber => {
110             if (!this.toscaGetFunction) {
111                 if (this.isGetInput()) {
112                     this.setSelfPropertySource();
113                     this.loadPropertyDropdown();
114                 }
115                 subscriber.next();
116                 return;
117             }
118             if (this.toscaGetFunction.propertySource == PropertySource.SELF) {
119                 this.propertySource.setValue(PropertySource.SELF);
120             } else if (this.toscaGetFunction.propertySource == PropertySource.INSTANCE) {
121                 this.propertySource
122                 .setValue(this.propertySourceList.find(source => this.toscaGetFunction.sourceName === source));
123             }
124             if (this.propertySource.valid) {
125                 this.loadPropertyDropdown(() => {
126                     this.selectedProperty
127                     .setValue(this.propertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.propertyName));
128                     if (this.toscaGetFunction.toscaIndexList && this.toscaGetFunction.toscaIndexList.length > 0) {
129                         let tempSelectedProperty : PropertyDropdownValue = this.selectedProperty.value;
130                         this.toscaGetFunction.toscaIndexList.forEach((indexValue: string, index) => {
131                             let tempIndexFlag = false;
132                             let tempNestedFlag = false;
133                             let tempIndexValue = "0";
134                             let tempIndexProperty = tempSelectedProperty;
135                             let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
136                             if (!isNaN(Number(indexValue)) || indexValue.toLowerCase() === 'index') {
137                                 tempIndexFlag = true;
138                                 tempIndexValue = indexValue;
139                                 tempSelectedProperty = null;
140                                 if (this.toscaGetFunction.toscaIndexList[index+1]) {
141                                     tempNestedFlag = true;
142                                     if (tempIndexProperty.schemaType != null) {
143                                         const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, tempIndexProperty.schemaType);
144                                         this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
145                                         tempSelectedProperty = subPropertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.toscaIndexList[index+1])
146                                         if (tempSelectedProperty == null && this.toscaGetFunction.toscaIndexList[index+2]) {
147                                             tempSelectedProperty = subPropertyDropdownList.find(property => property.propertyName === this.toscaGetFunction.toscaIndexList[index+2])
148                                         }
149                                     }
150                                 }
151                                 let tempIndexValueMap : ToscaIndexObject = {indexFlag : tempIndexFlag, nestedFlag : tempNestedFlag, indexValue: tempIndexValue, indexProperty: tempSelectedProperty, subPropertyArray: subPropertyDropdownList};
152                                 this.indexListValues.push(tempIndexValueMap);
153                             }
154                         });
155                     }
156                     subscriber.next();
157                 });
158             } else {
159                 subscriber.next();
160             }
161         });
162     }
163
164     private buildGetFunctionFromForm() {
165         const toscaGetFunction = new ToscaGetFunction();
166         toscaGetFunction.type = ToscaGetFunctionTypeConverter.convertToToscaFunctionType(this.functionType);
167         toscaGetFunction.functionType = this.functionType;
168         const propertySource = this.propertySource.value;
169         if (this.isPropertySourceSelf()) {
170             toscaGetFunction.propertySource = propertySource
171             toscaGetFunction.sourceName = this.componentMetadata.name;
172             toscaGetFunction.sourceUniqueId = this.componentMetadata.uniqueId;
173         } else {
174             toscaGetFunction.propertySource = PropertySource.INSTANCE;
175             toscaGetFunction.sourceName = propertySource;
176             toscaGetFunction.sourceUniqueId = this.instanceNameAndIdMap.get(propertySource);
177         }
178
179         const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
180         toscaGetFunction.propertyUniqueId = selectedProperty.propertyId;
181         toscaGetFunction.propertyName = selectedProperty.propertyName;
182         toscaGetFunction.propertyPathFromSource = selectedProperty.propertyPath;
183         if (this.indexListValues.length > 0) {
184             let indexAndProperty : Array<string> = [];
185             this.indexListValues.forEach((indexObject : ToscaIndexObject) => {
186                 indexAndProperty.push(indexObject.indexValue);
187                 if(indexObject.nestedFlag && indexObject.indexProperty != null) {
188                     indexAndProperty.push(...indexObject.indexProperty.propertyPath);
189                 }
190             });
191             toscaGetFunction.toscaIndexList = indexAndProperty;
192         }
193         return toscaGetFunction;
194     }
195
196     private loadPropertySourceDropdown(): void {
197         if (this.isGetInput()) {
198             return;
199         }
200         this.propertySourceList = [];
201         this.propertySourceList.push(PropertySource.SELF);
202         this.componentInstanceMap.forEach((value, key) => {
203             const instanceName = value.name;
204             this.instanceNameAndIdMap.set(instanceName, key);
205             if (instanceName !== PropertySource.SELF) {
206                 this.addToPropertySource(instanceName);
207             }
208         });
209     }
210
211     private addToPropertySource(source: string): void {
212         this.propertySourceList.push(source);
213         this.propertySourceList.sort((a, b) => {
214             if (a === PropertySource.SELF) {
215                 return -1;
216             } else if (b === PropertySource.SELF) {
217                 return 1;
218             }
219
220             return a.localeCompare(b);
221         });
222     }
223
224     private formValidation(): void {
225         if (!this.isInitialized) {
226             return;
227         }
228         let formGroupStatus : boolean = this.formGroup.valid;
229         const selectedProperty: PropertyDropdownValue = this.formGroup.value.selectedProperty;
230         if (selectedProperty != null && selectedProperty.isList && formGroupStatus && this.indexListValues.length > 0) {
231             this.indexListValues.forEach((indexObject : ToscaIndexObject, index) => {
232                 if (indexObject.indexValue == '') {
233                     formGroupStatus = false;
234                     return;
235                 }
236                 if (indexObject.nestedFlag && indexObject.indexProperty == null) {
237                     formGroupStatus = false;
238                     return;
239                 }
240             });
241         }
242         this.onValidityChange.emit({
243             isValid: formGroupStatus,
244             toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
245         });
246         if (this.formGroup.valid) {
247             this.onValidFunction.emit(this.buildGetFunctionFromForm());
248         }
249     }
250
251     private loadPropertyDropdown(onComplete?: () => any): void  {
252         this.loadPropertyDropdownLabel();
253         this.loadPropertyDropdownValues(onComplete);
254     }
255
256     private resetForm(): void {
257         this.formGroup.reset();
258     }
259
260     private loadPropertyDropdownLabel(): void {
261         if (!this.functionType) {
262             return;
263         }
264         if (this.isGetInput()) {
265             this.dropdownValuesLabel = this.translateService.translate('INPUT_DROPDOWN_LABEL');
266         } else if (this.isGetProperty()) {
267             this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_PROPERTY_DROPDOWN_LABEL');
268         } else if (this.isGetAttribute()) {
269             this.dropdownValuesLabel = this.translateService.translate('TOSCA_FUNCTION_ATTRIBUTE_DROPDOWN_LABEL');
270         }
271     }
272
273     private loadPropertyDropdownValues(onComplete?: () => any): void {
274         if (!this.functionType) {
275             return;
276         }
277         this.resetPropertyDropdown();
278         this.fillPropertyDropdownValues(onComplete);
279     }
280
281     private resetPropertyDropdown(): void {
282         this.dropDownErrorMsg = undefined;
283         this.selectedProperty.reset();
284         this.indexListValues = [];
285         this.propertyDropdownList = [];
286     }
287
288     private fillPropertyDropdownValues(onComplete?: () => any): void {
289         this.startLoading();
290         const propertiesObservable: Observable<ComponentGenericResponse> = this.getPropertyObservable();
291         propertiesObservable.subscribe( (response: ComponentGenericResponse) => {
292             const properties: Array<PropertyBEModel | AttributeBEModel> = this.extractProperties(response);
293             if (!properties || properties.length === 0) {
294                 const msgCode = this.getNotFoundMsgCode();
295                 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
296                 return;
297             }
298             this.addPropertiesToDropdown(properties, this.propertyDropdownList);
299             if (this.propertyDropdownList.length == 0) {
300                 const msgCode = this.getNotFoundMsgCode();
301                 this.dropDownErrorMsg = this.translateService.translate(msgCode, {type: this.overridingType != undefined ? this.overridingType : this.propertyTypeToString()});
302             }
303         }, (error) => {
304             console.error('An error occurred while loading properties.', error);
305             this.stopLoading();
306         }, () => {
307             if (onComplete) {
308                 onComplete();
309             }
310             this.stopLoading();
311         });
312     }
313
314     private getNotFoundMsgCode(): string {
315         if (this.isGetInput()) {
316             return 'TOSCA_FUNCTION_NO_INPUT_FOUND';
317         }
318         if (this.isGetAttribute()) {
319             return 'TOSCA_FUNCTION_NO_ATTRIBUTE_FOUND';
320         }
321         if (this.isGetProperty()) {
322             return 'TOSCA_FUNCTION_NO_PROPERTY_FOUND';
323         }
324
325         return undefined;
326     }
327
328     private propertyTypeToString() {
329             if (this.isSubProperty()){
330             if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty)
331                 || this.compositionMap) {
332                 if(this.isComplexType(this.property.schemaType)){
333                     let mapChildProp : DerivedFEProperty = (<DerivedFEProperty> (<PropertyDeclareAPIModel> this.property).input);
334                     let propertySchemaType = mapChildProp.type;
335                     if (this.property.type == PROPERTY_TYPES.MAP || propertySchemaType == PROPERTY_TYPES.MAP) {
336                         if (mapChildProp.mapKey != '' && mapChildProp.mapKey != null && mapChildProp.schema.property.type != null) {
337                             propertySchemaType = mapChildProp.schema.property.type;
338                         }
339                     }
340                     if ((propertySchemaType == PROPERTY_TYPES.MAP || (propertySchemaType == PROPERTY_TYPES.LIST && mapChildProp.schema.property.type == PROPERTY_TYPES.MAP))
341                         && mapChildProp.isChildOfListOrMap) {
342                         propertySchemaType = PROPERTY_TYPES.STRING;
343                     }
344                     return  propertySchemaType;
345                 }else{
346                     return this.property.schema.property.type;
347                 }
348             }
349                 return this.getType((<PropertyDeclareAPIModel>this.property).propertiesName.split("#").slice(1),  this.property.type);
350         }
351         if (this.property.schemaType) {
352             return `${this.property.type} of ${this.property.schemaType}`;
353         }
354         return this.property.type;
355     }
356
357     private isSubProperty(): boolean{
358             return this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName && (<PropertyDeclareAPIModel>this.property).propertiesName.length > 1;
359     }
360
361     private extractProperties(componentGenericResponse: ComponentGenericResponse): Array<PropertyBEModel | AttributeBEModel> {
362         if (this.isGetInput()) {
363             return componentGenericResponse.inputs;
364         }
365         const instanceId = this.instanceNameAndIdMap.get(this.propertySource.value);
366         if (this.isGetProperty()) {
367             if (this.isPropertySourceSelf()) {
368                 return componentGenericResponse.properties;
369             }
370             return this.removeSelectedProperty(componentGenericResponse.componentInstancesProperties[instanceId]);
371         }
372         if (this.isPropertySourceSelf()) {
373             return [...(componentGenericResponse.attributes || []), ...(componentGenericResponse.properties || [])];
374         }
375         return [...(componentGenericResponse.componentInstancesAttributes[instanceId] || []),
376             ...(componentGenericResponse.componentInstancesProperties[instanceId] || [])];
377     }
378
379     private isPropertySourceSelf() {
380         return this.propertySource.value === PropertySource.SELF;
381     }
382
383     private getPropertyObservable(): Observable<ComponentGenericResponse> {
384         if (this.isGetInput()) {
385             return this.topologyTemplateService.getComponentInputsValues(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
386         }
387         if (this.isGetProperty()) {
388             if (this.isPropertySourceSelf()) {
389                 return this.topologyTemplateService.findAllComponentProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
390             }
391             return this.topologyTemplateService.getComponentInstanceProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
392         }
393         if (this.isGetAttribute()) {
394             if (this.isPropertySourceSelf()) {
395                 return this.topologyTemplateService.findAllComponentAttributesAndProperties(this.componentMetadata.componentType, this.componentMetadata.uniqueId);
396             }
397             return this.topologyTemplateService.getComponentInstanceAttributesAndProperties(this.componentMetadata.uniqueId, this.componentMetadata.componentType);
398         }
399     }
400
401     private removeSelectedProperty(componentInstanceProperties: PropertyModel[]): PropertyModel[] {
402         if (!componentInstanceProperties) {
403             return [];
404         }
405         return componentInstanceProperties.filter(property =>
406             (property.uniqueId !== this.property.uniqueId) ||
407             (property.uniqueId === this.property.uniqueId && property.resourceInstanceUniqueId !== this.property.parentUniqueId)
408         );
409     }
410
411     private addPropertyToDropdown(propertyDropdownValue: PropertyDropdownValue, propertyList: Array<PropertyDropdownValue>): void {
412         if (!propertyList.find(prop => prop.propertyName === propertyDropdownValue.propertyName)) {
413             propertyList.push(propertyDropdownValue);
414             propertyList.sort((a, b) => a.propertyLabel.localeCompare(b.propertyLabel));
415         }
416     }
417
418     private addPropertiesToDropdown(properties: Array<PropertyBEModel | AttributeBEModel>, propertyList: Array<PropertyDropdownValue>): void {
419         for (const property of properties) {
420             if (this.hasSameType(property)) {
421                 this.addPropertyToDropdown({
422                     propertyName: property.name,
423                     propertyId: property.uniqueId,
424                     propertyLabel: property.name,
425                     propertyPath: [property.name],
426                     isList: property.type === PROPERTY_TYPES.LIST,
427                     schemaType: (property.type === PROPERTY_TYPES.LIST && this.isComplexType(property.schema.property.type)) ? property.schema.property.type : null
428                 },propertyList);
429             } else if (this.isComplexType(property.type)) {
430                 this.fillPropertyDropdownWithMatchingChildProperties(property,propertyList);
431             }
432         }
433     }
434
435     private fillPropertyDropdownWithMatchingChildProperties(inputProperty: PropertyBEModel | AttributeBEModel, propertyList: Array<PropertyDropdownValue>,
436                                                             parentPropertyList: Array<PropertyBEModel | AttributeBEModel> = []): void {
437         const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, inputProperty.type);
438         if (!dataTypeFound || !dataTypeFound.properties) {
439             return;
440         }
441         parentPropertyList.push(inputProperty);
442         dataTypeFound.properties.forEach(dataTypeProperty => {
443             if (this.hasSameType(dataTypeProperty)) {
444                 this.addPropertyToDropdown({
445                     propertyName: dataTypeProperty.name,
446                     propertyId: parentPropertyList[0].uniqueId,
447                     propertyLabel: parentPropertyList.map(property => property.name).join('->') + '->' + dataTypeProperty.name,
448                     propertyPath: [...parentPropertyList.map(property => property.name), dataTypeProperty.name],
449                     isList : dataTypeProperty.type === PROPERTY_TYPES.LIST,
450                     schemaType: (dataTypeProperty.type === PROPERTY_TYPES.LIST && this.isComplexType(dataTypeProperty.schema.property.type)) ? dataTypeProperty.schema.property.type : null
451                 }, propertyList);
452             } else if (this.isComplexType(dataTypeProperty.type)) {
453                 this.fillPropertyDropdownWithMatchingChildProperties(dataTypeProperty, propertyList, [...parentPropertyList])
454             }
455         });
456     }
457
458     private hasSameType(property: PropertyBEModel | AttributeBEModel): boolean {
459         if (this.overridingType != undefined) {
460             return property.type === this.overridingType;
461         }
462         if (this.property.type === PROPERTY_TYPES.ANY) {
463             return true;
464         }
465         let validPropertyType = (this.parentListTypeFlag && property.type === PROPERTY_TYPES.LIST) ? property.schema.property.type : property.type;
466         if (this.parentListTypeFlag && property.type === PROPERTY_TYPES.LIST && this.isComplexType(validPropertyType)) {
467             let returnFlag : boolean = false;
468             const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, validPropertyType);
469             if (dataTypeFound && dataTypeFound.properties) {
470                 dataTypeFound.properties.forEach(dataTypeProperty => {
471                     if (this.hasSameType(dataTypeProperty)) {
472                         returnFlag =  true;
473                     }
474                     if (!returnFlag && this.isComplexType(dataTypeProperty.type)) {
475                         const nestedDataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, dataTypeProperty.type);
476                         if (nestedDataTypeFound && nestedDataTypeFound.properties) {
477                             nestedDataTypeFound.properties.forEach( nestedDateTypeProperty => {
478                                 if (this.hasSameType(nestedDateTypeProperty)) {
479                                     returnFlag =  true;
480                                 }
481                             });
482                         }
483                     }
484                 });
485             }
486             return returnFlag;
487         }
488         if (this.typeHasSchema(this.property.type)) {
489             if ((this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel> this.property).input instanceof DerivedFEProperty) || this.compositionMap) {
490                 let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
491                 let childSchemaType = (this.property != null && this.property.schemaType != null) ? this.property.schemaType : childObject.type;
492                 if(this.isComplexType(childSchemaType)){
493                     if (childObject.type == PROPERTY_TYPES.MAP && childObject.isChildOfListOrMap) {
494                         return validPropertyType === PROPERTY_TYPES.STRING;
495                     }
496                     return validPropertyType === childObject.type;
497                 }else{
498                     return validPropertyType === this.property.schema.property.type;
499                 }
500             }
501             if (!property.schema || !property.schema.property) {
502                 return false;
503             }
504             return validPropertyType === this.property.type && this.property.schema.property.type === property.schema.property.type;
505         }
506         if ((this.property.schema.property.isDataType || this.isComplexType(this.property.type)) && this.property instanceof PropertyDeclareAPIModel && (<PropertyDeclareAPIModel>this.property).propertiesName){
507             let typeToMatch = (<PropertyDeclareAPIModel> this.property).input.type;
508             let childObject : DerivedFEProperty = (<DerivedFEProperty>(<PropertyDeclareAPIModel> this.property).input);
509             if (childObject.type == PROPERTY_TYPES.MAP && childObject.isChildOfListOrMap) {
510                 typeToMatch = PROPERTY_TYPES.STRING;
511             }
512             if ((typeToMatch === PROPERTY_TYPES.LIST || typeToMatch === PROPERTY_TYPES.MAP) && (<PropertyDeclareAPIModel> this.property).input.schema.property.type && this.compositionMap && !isNaN(Number(this.compositionMapKey))) {
513                 typeToMatch = (<PropertyDeclareAPIModel> this.property).input.schema.property.type;
514             }
515             return validPropertyType === typeToMatch;
516         }
517
518         return validPropertyType === this.property.type;
519     }
520
521     private getType(propertyPath:string[], type: string): string {
522             const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, type);
523         let nestedProperty = dataTypeFound.properties.find(property => property.name === propertyPath[0]);
524         if (propertyPath.length === 1){
525                 return nestedProperty.type;
526         } 
527         return this.getType(propertyPath.slice(1), nestedProperty.type);
528     }
529
530     private isGetProperty(): boolean {
531         return this.functionType === ToscaGetFunctionType.GET_PROPERTY;
532     }
533
534     private isGetAttribute(): boolean {
535         return this.functionType === ToscaGetFunctionType.GET_ATTRIBUTE;
536     }
537
538     private isGetInput(): boolean {
539         return this.functionType === ToscaGetFunctionType.GET_INPUT;
540     }
541
542     private isComplexType(propertyType: string): boolean {
543         return PROPERTY_DATA.SIMPLE_TYPES.indexOf(propertyType) === -1;
544     }
545
546     private typeHasSchema(propertyType: string): boolean {
547         return PROPERTY_TYPES.MAP === propertyType || PROPERTY_TYPES.LIST === propertyType;
548     }
549
550     private stopLoading(): void {
551         this.isLoading = false;
552     }
553
554     private startLoading(): void {
555         this.isLoading = true;
556     }
557
558     showPropertyDropdown(): boolean {
559         if (this.isGetProperty() || this.isGetAttribute()) {
560             return this.propertySource.valid && !this.isLoading && !this.dropDownErrorMsg;
561         }
562
563         return this.functionType && !this.isLoading && !this.dropDownErrorMsg;
564     }
565
566     onPropertySourceChange(): void {
567         this.selectedProperty.reset();
568         this.indexListValues = [];
569         if (!this.functionType || !this.propertySource.valid) {
570             return;
571         }
572         this.loadPropertyDropdown();
573     }
574
575     onPropertyValueChange(): void {
576         let toscaIndexFlag = false;
577         let nestedToscaFlag = false;
578         this.indexListValues = [];
579         let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
580         const selectedProperty: PropertyDropdownValue = this.selectedProperty.value;
581         if (this.parentListTypeFlag && selectedProperty.isList) {
582             toscaIndexFlag = true;
583             if (selectedProperty.schemaType != null) {
584                 nestedToscaFlag = true;
585                 const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
586                 this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
587             }
588         }
589         if (toscaIndexFlag || nestedToscaFlag) {
590             let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
591             this.indexListValues.push(indexValueMap);
592         }
593         this.formValidation();
594     }
595
596     onSubPropertyValueChange(indexObject : ToscaIndexObject, elementIndex: number): void {
597         let toscaIndexFlag = false;
598         let nestedToscaFlag = false;
599         let subPropertyDropdownList : Array<PropertyDropdownValue> = [];
600         let selectedProperty: PropertyDropdownValue = indexObject.indexProperty;
601         if (selectedProperty.isList) {
602             toscaIndexFlag = true;
603             if (selectedProperty.schemaType != null) {
604                 nestedToscaFlag = true;
605                 const dataTypeFound: DataTypeModel = this.dataTypeService.getDataTypeByModelAndTypeName(this.componentMetadata.model, selectedProperty.schemaType);
606                 this.addPropertiesToDropdown(dataTypeFound.properties, subPropertyDropdownList);
607             }
608         }
609         if (toscaIndexFlag || nestedToscaFlag) {
610             let indexValueMap : ToscaIndexObject = {indexFlag : toscaIndexFlag, nestedFlag : nestedToscaFlag, indexValue: "0", indexProperty: null, subPropertyArray: subPropertyDropdownList};
611             if(!this.indexListValues[elementIndex+1]) {
612                 this.indexListValues.push(indexValueMap);
613             } else {
614                 this.indexListValues[elementIndex+1] = indexValueMap;
615             }
616         } else {
617             if(this.indexListValues[elementIndex+1]) {
618                 this.indexListValues.splice((elementIndex+1),1);
619             }
620         }
621         this.formValidation();
622     }
623
624     indexTokenChange(indexObject : ToscaIndexObject): void {
625         if ((indexObject.indexValue).toLowerCase() === 'index' ) {
626             this.formValidation();
627         }
628
629         const regEx = /^[0-9]*$/;
630         const error = document.getElementById('error');
631
632         if (!(regEx.test(indexObject.indexValue)) && (indexObject.indexValue).toLowerCase() !== 'index') {
633             error.textContent='Invalid value - must be an integer or INDEX';
634             this.onValidityChange.emit({
635                 isValid: false,
636                 toscaGetFunction: this.formGroup.valid ? this.buildGetFunctionFromForm() : undefined
637             });
638         } else {
639             error.textContent='';
640             this.formValidation();
641         }
642     }
643
644     showPropertySourceDropdown(): boolean {
645         return this.isGetProperty() || this.isGetAttribute();
646     }
647
648     private setSelfPropertySource(): void {
649         this.propertySource.setValue(PropertySource.SELF);
650     }
651
652     private get propertySource(): FormControl {
653         return this.formGroup.get('propertySource') as FormControl;
654     }
655
656     private get selectedProperty(): FormControl {
657         return this.formGroup.get('selectedProperty') as FormControl;
658     }
659
660     onChangeIndexValue(index: ToscaIndexObject, value: any) {
661         this.indexTokenChange(index);
662     }
663 }
664
665 export interface PropertyDropdownValue {
666     propertyName: string;
667     propertyId: string;
668     propertyLabel: string;
669     propertyPath: Array<string>;
670     isList: boolean;
671     schemaType: string;
672 }
673
674 export interface ToscaIndexObject {
675     indexFlag: boolean;
676     nestedFlag: boolean;
677     indexValue: string;
678     indexProperty: PropertyDropdownValue;
679     subPropertyArray: Array<PropertyDropdownValue>;
680 }
681
682 export interface ToscaGetFunctionValidationEvent {
683     isValid: boolean,
684     toscaGetFunction: ToscaGetFunction,
685 }