aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/DataVizBox/DocCreatorMenu/Template.ts
blob: cf6e145cb4770e34b2a048449bb7d4ab3317c20f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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;
            console.log('title: ', field.getTitle(), ' width: ', doc?.width);
        });
    };

    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;
    };
}