import { makeAutoObservable } from 'mobx'; import { Col } from './DocCreatorMenu'; import { TemplateLayouts } from './TemplateBackend'; import { DynamicField } from './TemplateFieldTypes/DynamicField'; import { FieldSettings, TemplateField } from './TemplateFieldTypes/TemplateField'; export class Template { _mainField: DynamicField | undefined; /** * A Template can be created from a description of its fields (FieldSettings) or from a DynamicField * @param definition definition of template as settings or DynamicField */ constructor(definition: FieldSettings | DynamicField) { makeAutoObservable(this); this._mainField = definition instanceof DynamicField ? definition : this.setupMainField(definition); } get childFields(): TemplateField[] { return this._mainField?.getSubfields ?? []; } get allFields(): TemplateField[] { return this._mainField?.getAllSubfields ?? []; } get contentFields(): TemplateField[] { return this.allFields.filter(field => field.isContentField); } get doc() { return this._mainField?.renderedDoc; } get title() { return this._mainField?.getTitle(); } get descriptionSummary(): string { let summary: string = ''; this.contentFields.forEach(field => { summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getDescription ?? ''} ---`; }); return summary; } get compiledContent(): string { let summary: string = ''; this.contentFields.forEach(field => { summary += `--- Field #${field.getID} (title: ${field.getTitle()}): ${field.getContent() ?? ''} ---`; }); return summary; } cleanup = () => { //dispose each subfields disposers, etc. }; cloneBase = () => new Template(this._mainField?.makeClone(undefined) ?? TemplateLayouts.BasicSettings); getRenderedDoc = () => this.doc; getFieldByID = (id: number): TemplateField => this.allFields.filter(field => field.getID === id)[0]; getFieldByTitle = (title: string) => this.allFields.filter(field => field.getTitle() === title)[0]; setupMainField = (templateInfo: FieldSettings) => TemplateField.CreateField(templateInfo, 1, undefined) as DynamicField; printFieldInfo = () => { this.allFields.forEach(field => { const doc = field.renderedDoc; }); }; isValidTemplate = (cols: Col[]) => { const maxMatches = this.maxMatches(this.getMatches(cols)); return maxMatches === this.contentFields.length; }; getMatches = (cols: Col[]): number[][] => { const numFields = this.contentFields.length; if (cols.length !== numFields) return []; const matches: number[][] = Array(numFields) .fill([]) .map(() => []); this.contentFields.forEach((field, i) => (matches[i] = field.matches(cols))); return matches; }; maxMatches = (matches: number[][]) => { if (matches.length === 0) return 0; const fieldsCt = this.contentFields.length; const used: boolean[] = Array(fieldsCt).fill(false); const mt: number[] = Array(fieldsCt).fill(-1); const augmentingPath = (v: number): boolean => { if (!used[v]) { used[v] = true; for (const to of matches[v]) { if (mt[to] === -1 || augmentingPath(mt[to])) { mt[to] = v; return true; } } } return false; }; for (let v = 0; v < fieldsCt; ++v) { used.fill(false); augmentingPath(v); } let count: number = 0; for (let i = 0; i < fieldsCt; ++i) { if (mt[i] !== -1) ++count; } return count; }; }