import { IsArray, IsOptional, IsString, ValidateNested } from "class-validator"; import { Type } from "class-transformer"; import { ISkillView } from "../../features/behavior_tree_builder/presentation/ui/skill_tree/skill_tree"; import { v4 } from "uuid"; import { Result } from "../helper/result"; import clone from "just-clone"; export interface IDependency { skills: ISkillDependency[]; } export interface ISkillDependency { sid: string; dependency: Object; } export interface ISkill { sid?: string; SkillPackage: ISkillPackage; Module: IModule; Launch: ILaunch; ROS2: IRos2; BTAction: IBTAction[]; Interface: IInterface; Settings: ISetting[]; xxx: IXxx; } export interface IWeightsDependency { weights_name:string; object_name: string; weights_file: string; dimensions: number[]; } export interface IParam { type: string; dependency: Object; } export interface IBTAction { name: string; format: string; // TODO: Нужно выпилить его отсюда // sid?: string; type: string; param: IParam[]; result: string[]; } export interface IInterface { Input: IPut[]; Output: IPut[]; } export interface IPut { name: string; type: string; } export interface ILaunch { executable: string; } export interface IModule { name: string; description: string; } export interface IRos2 { node_name: string; } export interface ISetting { name: string; value: number | string; } export interface ISkillPackage { name: string; version: string; format: string; } export interface IXxx { cameraLink: string; topicImage: string; topicCameraInfo: string; } export class SkillPackage implements ISkillPackage { @IsString() name: string; @IsString() version: string; @IsString() format: string; } export class Module implements IModule { @IsString() name: string; @IsString() description: string; } export class BTAction implements IBTAction { @IsString() name: string; @IsString() format: string; @IsString() type: string; sid?: string; @IsArray() param: IParam[]; @IsArray() result: string[]; } export class Launch implements ILaunch { @IsString() executable: string; } export class Ros2 implements IRos2 { @IsString() node_name: string; } export class Put implements IPut { @IsString() name: string; @IsString() type: string; } export class Interface implements IInterface { @ValidateNested() @Type(() => Put) Input: IPut[]; @ValidateNested() @Type(() => Put) Output: IPut[]; } export class Setting implements ISetting { name: string; value: string | number; } export class Xxx implements IXxx { cameraLink: string; topicImage: string; topicCameraInfo: string; } export class SkillModel implements ISkill { @IsOptional() @IsString() sid?: string; @ValidateNested() @Type(() => SkillPackage) SkillPackage: ISkillPackage; @ValidateNested() @Type(() => Module) Module: IModule; @ValidateNested() @Type(() => Launch) Launch: ILaunch; @ValidateNested() @Type(() => Ros2) ROS2: IRos2; @ValidateNested() @IsArray() @Type(() => BTAction) BTAction: IBTAction[]; @ValidateNested() @Type(() => Interface) Interface: IInterface; @ValidateNested() @IsArray() @Type(() => Setting) Settings: ISetting[]; @ValidateNested() @Type(() => Xxx) xxx: IXxx; static empty() { const skillModel = new SkillModel(); skillModel.BTAction = []; return skillModel; } public static isEmpty(skill: SkillModel): Result { if (skill.BTAction.isEmpty()) { return Result.error(undefined); } return Result.ok(Object.assign(skill, {})); } public getSid = () => this.sid; public setSid = (sid: string) => { const result = clone(this); result.sid = sid; return result; }; } export class SkillDependency implements IDependency { constructor(public skills: ISkillDependency[]) {} static empty() { return new SkillDependency([]); } static isEmpty = (skill: SkillDependency) => { if (skill.skills.isEmpty()) { return Result.error(undefined); } return Result.ok(skill); }; } export class Skills { @IsArray() @Type(() => SkillModel) skills: SkillModel[]; validation = (): Result => { const errors: string[] = []; this.skills.forEach((skill) => { skill.BTAction.forEach((action) => { if (action.param.isNotEmpty()) { action.param.forEach((param) => { if (Object.keys(param.dependency).isEmpty()) { errors.push(param.type); } }); } }); }); if (errors.isNotEmpty()) { return Result.error(errors); } return Result.ok(undefined); }; skillBySid = (sid: string) => SkillModel.isEmpty( this.skills.reduce((acc, el) => { if (el.sid?.isEqual(sid)) { acc = el; } return acc; }, SkillModel.empty()) ); toSkillView = (): ISkillView[] => this.skills.map((el) => { return { name: el.Module.name, children: el.BTAction.map((act) => { return { name: act.name, uuid: v4() }; }), }; }); getSkill = (name: string) => SkillModel.isEmpty( this.skills.reduce((acc, el) => { if (el.BTAction.find((el) => el.name.isEqual(name))) { el.BTAction.map((action) => { action.param.map((param) => { return param; }); }); acc = el; } return acc; }, SkillModel.empty()) ); getSkilsOut = (name: string) => this.skills .reduce((acc, el) => { if (el.BTAction.find((el) => el.name.isEqual(name))) { acc = el.BTAction.filter((f) => f.name.isEqual(name)).map((z) => z.result); } return acc; }, []) .flat(1); getSkillParams = (name: string) => this.skills .reduce((acc, el) => { if (el.BTAction.find((el) => el.name.isEqual(name))) { acc = el.BTAction.filter((f) => f.name.isEqual(name)).map((z) => z.param); } return acc; }, []) .flat(1); getSkillDo = (name: string) => this.skills.reduce((acc, el) => { if (el.BTAction.find((el) => el.name.isEqual(name))) { acc = el.Module.name; } return acc; }, "error"); getSkillsNames = () => this.skills .map((el) => { return el.BTAction.map((act) => { return { name: act.name }; }); }) .flat(1); getForms = (skillLabel: string) => this.skills .reduce((acc, el) => { if (el.BTAction.find((el) => el.name.isEqual(skillLabel))) { acc.push(el); } return acc; }, []) .map((el) => el.BTAction.map((act) => act.param.map((el) => el.type).flat(1))) .flat(1) .flat(1) .filter((el) => el !== ""); getDependencyBySkillLabelAndType = (skillType: string, sid: string) => this.skills .reduce((acc, skill) => { if (skill.sid?.isEqual(sid)) { skill.BTAction.map((action) => { action.param.map((param) => { if (param.type.isEqual(skillType)) { acc.push(param.dependency); } return param; }); return action; }); } return acc; }, []) .at(0) as T; static isEmpty(model: Skills): Result { if (model.skills.isEmpty()) { return Result.error(undefined); } return Result.ok(undefined); } static empty() { const skills = new Skills(); skills.skills = []; return skills; } public dependencyIsFilled = (skillType: string, sid: string) => this.skills.reduce((acc, skill) => { if (skill.sid?.isEqual(sid)) { skill.BTAction.forEach((action) => { action.param.forEach((param) => { if (param.type.isEqual(skillType)) { // console.log('SKILL TYPE') // console.log(skillType); // console.log("SID") // console.log(sid) // console.log("DEPENDENCY") // console.log(param.dependency) acc = Object.keys(param.dependency).isNotEmpty(); } }); }); } return acc; }, false); getAllSids = () => this.skills.reduce((acc, skill) => { skill.BTAction.forEach((action) => action.param.forEach((param) => { // acc.incrementValue(param.sid ?? "empty"); return param; }) ); return acc; }, new Map()); deleteSid(sid: string): SkillModel[] { return this.skills.filter((skill) => !skill.sid?.isEqual(sid)); } updateSkill = (skill: SkillModel) => { console.log(skill); this.skills = this.skills.map((el) => { if (el.sid?.isEqual(skill.sid ?? "")) { el = skill; } return el; }); }; skillHasForm = (label: string): boolean => { // TODO:NEED IMPLEMENTS return true; }; }