import {Injectable} from "@angular/core";
import {ILevelNodeInfo} from "../models/basic.model.info";
import {ObjectToTreeService} from "../objectToTree.service";
import {DefaultDataGeneratorService} from "../../../../shared/services/defaultDataServiceGenerator/default.data.generator.service";
import * as _ from "lodash";
import {ServiceInstanceActions} from "../../../../shared/models/serviceInstanceActions";
import {ErrorMsgService} from "../../../../shared/components/error-msg/error-msg.service";
import {FeatureFlagsService, Features} from "../../../../shared/services/featureFlag/feature-flags.service";
import {NgRedux} from "@angular-redux/store";
import {AppState} from "../../../../shared/store/reducers";
import {SharedTreeService} from "../shared.tree.service";
@Injectable()
export class ObjectToInstanceTreeService {
constructor(private _objectToTreeService: ObjectToTreeService, private _errorMsgService: ErrorMsgService,
private store: NgRedux<AppState>, private _sharedTreeService: SharedTreeService) {
this.numberOfFailed = 0;
this.numberOfElements = 0;
}
/** store number of failed ******** ONLY IN RETRY MODE ******** **/
numberOfFailed: number = 0;
/** store number of existing elements **/
numberOfElements: number = 0;
/*****************************************************************
* return array of first level node with there child's
* @param serviceInstance - The service instance object from store
* @param serviceHierarchy - The service Hierarchy store
****************************************************************/
convertServiceInstanceToTreeData(serviceInstance, serviceHierarchy): any[] {
this._errorMsgService.triggerClearError.next();
let nodes = [];
this.numberOfFailed = 0;
this.numberOfElements = 0;
let _this = this;
const serviceModelId:string = serviceInstance.modelInfo.modelVersionId;
const firstLevelOptions: ILevelNodeInfo[] = _this._objectToTreeService.getFirstLevelOptions();
for (let option of firstLevelOptions) {
_.forOwn(serviceInstance[option.name], function (instance, modelName) {
nodes.push(_this.getNodeInstance(modelName, null, instance, serviceHierarchy, option, serviceModelId));
});
}
return this.sortElementsByPosition(nodes);
}
/*****************************************************************
* should increase number of failed
* @param node - the current node
****************************************************************/
increaseNumberOfFailed(node) {
if (node && node.isFailed) {
this.numberOfFailed++;
node['errors'] = !_.isNil(node['errors']) ? node['errors'] : {};
node['errors']["isFailed"] = true;
this._errorMsgService.triggerShowError.next(this._errorMsgService.getRetryErrorObject(this.numberOfFailed));
}
}
/*****************************************************************
* should increase number of existing elements
* @param node - the current node
****************************************************************/
increaseNumberOfExcitingElements() {
this.numberOfElements++;
}
/*****************************************************************
* return array of first level node with there child's
* @param modelName
* @param parentModel
* @param instance
* @param serviceHierarchy - The service Hierarchy store
* @param option
* @param serviceModelId
* @param parentType
****************************************************************/
getNodeInstance(modelName: string, parentModel: any, instance: any, serviceHierarchy, option: ILevelNodeInfo, serviceModelId: string, parentType ?: string) {
const instanceModel = this._sharedTreeService.modelByIdentifiers(
serviceHierarchy, option.name,
this._sharedTreeService.modelUniqueNameOrId(instance), modelName
);
const model = option.getModel(instanceModel);
let optionalNodes = option.createInstanceTreeNode(instance, model, parentModel, modelName, serviceModelId);
this.increaseNumberOfFailed(optionalNodes);
this.increaseNumberOfExcitingElements();
let nodes: any[] = _.isArray(optionalNodes) ? optionalNodes : [optionalNodes];
for (let node of nodes) {
node = this.addingExtraDataToNode(node, modelName, parentModel, instance, serviceHierarchy, option, parentType);
let children = this.addNextInstanceTreeNode(instance, model, option, node, serviceHierarchy, serviceModelId);
if (!_.isNil(children) && children.length > 0) {
node.children = this.sortElementsByPosition(children);
}
this.updateScalingPolicy(node);
}
return nodes.length === 1 ? nodes[0] : nodes;
}
addingExtraDataToNode(node, modelName: string, parentModel: any, instance: any, serviceHierarchy, option: ILevelNodeInfo, parentType ?: string) {
if(!_.isNil(node)){
node.trackById = _.isNil(node.trackById) ? DefaultDataGeneratorService.createRandomTrackById() : node['trackById'];
node.parentType = !_.isNil(parentType) ? parentType : "";
node.updatePoistionFunction = option.updatePosition;
node.position = option.getNodePosition(instance, node.dynamicModelName);
node.modelTypeName = option.name;
node.getModel = option.getModel.bind(option);
node.getInfo = !_.isNil(option.getInfo) ? option.getInfo.bind(option) : ()=>{};
node.componentInfoType = option.componentInfoType;
}
return node;
}
sortElementsByPosition(nodes: any[]): any[] {
if (!FeatureFlagsService.getFlagState(Features.FLAG_1911_INSTANTIATION_ORDER_IN_ASYNC_ALACARTE, this.store)) return nodes;
return nodes.sort((nodeA, nodeB) => {
return nodeA.position - nodeB.position;
});
}
/*****************************************************************
* return next level node with there child's
* @param parentInstance
* @param parentModel
* @param levelNodeInfo
* @param parentNode
* @param serviceHierarchy - The service Hierarchy store
* @param serviceModelId
****************************************************************/
addNextInstanceTreeNode(parentInstance, parentModel, levelNodeInfo: ILevelNodeInfo, parentNode, serviceHierarchy, serviceModelId: string): any[] {
if (!_.isNil(levelNodeInfo.childNames)&& levelNodeInfo.childNames.length > 0) {
const that = this;
parentNode.children = [];
levelNodeInfo.childNames.forEach(function (childName) {
if (!_.isNil(parentInstance[childName])) {
let parentType = levelNodeInfo.type;
let nextLevelNodeInfo = levelNodeInfo.getNextLevelObject.apply(that, [childName]);
Object.keys(parentInstance[childName]).map((modelName) => {
let nextLevelInstance = parentInstance[childName][modelName];
let nodes: any[] | any = that.getNodeInstance(modelName, parentModel, nextLevelInstance, serviceHierarchy, nextLevelNodeInfo, serviceModelId, parentType);
if (_.isArray(nodes)) {
parentNode.children = parentNode.children.concat(nodes);
} else {
parentNode.children.push(nodes);
}
});
}
});
return this.sortElementsByPosition(parentNode.children);
}
return !_.isNil(parentNode) ? parentNode.children : null;
}
/************************************************************************************
* update instance scaling policy according to instance limit and existing children
* @param node
*********************************************************************************/
updateScalingPolicy(node): void {
if(_.isNil(node)) return node;
node['errors'] = !_.isNil(node['errors']) ? node['errors'] : {};
if (!_.isNil(node['limitMembers']) && !_.isNil(node.children)) {
let effectiveChildren = (node.children).filter(child => [
ServiceInstanceActions.Create,
ServiceInstanceActions.None,
ServiceInstanceActions.Update
].includes(child.action));
if (effectiveChildren.length > node.limitMembers) {
node['errors']["scalingError"] = true;
this._errorMsgService.triggerShowError.next(this._errorMsgService.getScalingErrorObject());
} else {
delete node['errors']["scalingError"];
}
}
}
}