import { SelectedScript } from './SelectedScript'; import { IUserSelection } from './IUserSelection'; import { InMemoryRepository } from '@/infrastructure/Repository/InMemoryRepository'; import { IScript } from '@/domain/IScript'; import { EventSource } from '@/infrastructure/Events/EventSource'; import { IRepository } from '@/infrastructure/Repository/IRepository'; import { ICategory } from '@/domain/ICategory'; import { ICategoryCollection } from '@/domain/ICategoryCollection'; export class UserSelection implements IUserSelection { public readonly changed = new EventSource>(); private readonly scripts: IRepository; constructor( private readonly collection: ICategoryCollection, selectedScripts: ReadonlyArray) { this.scripts = new InMemoryRepository(); if (selectedScripts && selectedScripts.length > 0) { for (const script of selectedScripts) { this.scripts.addItem(script); } } } public areAllSelected(category: ICategory): boolean { if (this.selectedScripts.length === 0) { return false; } const scripts = category.getAllScriptsRecursively(); if (this.selectedScripts.length < scripts.length) { return false; } return scripts.every((script) => this.selectedScripts.some((selected) => selected.id === script.id)); } public isAnySelected(category: ICategory): boolean { if (this.selectedScripts.length === 0) { return false; } return this.selectedScripts.some((s) => category.includes(s.script)); } public removeAllInCategory(categoryId: number): void { const category = this.collection.findCategory(categoryId); const scriptsToRemove = category.getAllScriptsRecursively() .filter((script) => this.scripts.exists(script.id)); if (!scriptsToRemove.length) { return; } for (const script of scriptsToRemove) { this.scripts.removeItem(script.id); } this.changed.notify(this.scripts.getItems()); } public addOrUpdateAllInCategory(categoryId: number, revert: boolean = false): void { const category = this.collection.findCategory(categoryId); const scriptsToAddOrUpdate = category.getAllScriptsRecursively() .filter((script) => !this.scripts.exists(script.id) || this.scripts.getById(script.id).revert !== revert, ); if (!scriptsToAddOrUpdate.length) { return; } for (const script of scriptsToAddOrUpdate) { const selectedScript = new SelectedScript(script, revert); this.scripts.addOrUpdateItem(selectedScript); } this.changed.notify(this.scripts.getItems()); } public addSelectedScript(scriptId: string, revert: boolean): void { const script = this.collection.findScript(scriptId); if (!script) { throw new Error(`Cannot add (id: ${scriptId}) as it is unknown`); } const selectedScript = new SelectedScript(script, revert); this.scripts.addItem(selectedScript); this.changed.notify(this.scripts.getItems()); } public addOrUpdateSelectedScript(scriptId: string, revert: boolean): void { const script = this.collection.findScript(scriptId); const selectedScript = new SelectedScript(script, revert); this.scripts.addOrUpdateItem(selectedScript); this.changed.notify(this.scripts.getItems()); } public removeSelectedScript(scriptId: string): void { this.scripts.removeItem(scriptId); this.changed.notify(this.scripts.getItems()); } public isSelected(scriptId: string): boolean { return this.scripts.exists(scriptId); } /** Get users scripts based on his/her selections */ public get selectedScripts(): ReadonlyArray { return this.scripts.getItems(); } public selectAll(): void { for (const script of this.collection.getAllScripts()) { if (!this.scripts.exists(script.id)) { const selection = new SelectedScript(script, false); this.scripts.addItem(selection); } } this.changed.notify(this.scripts.getItems()); } public deselectAll(): void { const selectedScriptIds = this.scripts.getItems().map((script) => script.id); for (const scriptId of selectedScriptIds) { this.scripts.removeItem(scriptId); } this.changed.notify([]); } public selectOnly(scripts: readonly IScript[]): void { if (!scripts || scripts.length === 0) { throw new Error('Scripts are empty. Use deselectAll() if you want to deselect everything'); } // Unselect from selected scripts if (this.scripts.length !== 0) { this.scripts.getItems() .filter((existing) => !scripts.some((script) => existing.id === script.id)) .map((script) => script.id) .forEach((scriptId) => this.scripts.removeItem(scriptId)); } // Select from unselected scripts const unselectedScripts = scripts.filter((script) => !this.scripts.exists(script.id)); for (const toSelect of unselectedScripts) { const selection = new SelectedScript(toSelect, false); this.scripts.addItem(selection); } this.changed.notify(this.scripts.getItems()); } }