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