/* eslint-disable prettier/prettier */
/* eslint-disable jsx-a11y/control-has-associated-label */
import mermaid from 'mermaid';
import { action, makeObservable, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { Doc, DocListCast } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { RichTextField } from '../../../fields/RichTextField';
import { DocCast,BoolCast } from '../../../fields/Types';
import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT';
import { DocumentType } from '../../documents/DocumentTypes';
import { Docs } from '../../documents/Documents';
import { DocumentManager } from '../../util/DocumentManager';
import { LinkManager } from '../../util/LinkManager';
import { ViewBoxAnnotatableComponent } from '../DocComponent';
import { InkingStroke} from '../InkingStroke';
import './DiagramBox.scss';
import { FieldView, FieldViewProps } from './FieldView';
import { PointData } from '../../../pen-gestures/GestureTypes';
import { InkField } from '../../../fields/InkField';

enum menuState {
    option,
    mermaidCode,
    drawing,
    gpt,
    justCreated,
}

@observer
export class DiagramBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
    public static LayoutString(fieldKey: string) {
        return FieldView.LayoutString(DiagramBox, fieldKey);
    }
    private _ref: React.RefObject<HTMLDivElement> = React.createRef();
    private _dragRef = React.createRef<HTMLDivElement>();
    constructor(props: FieldViewProps) {
        super(props);
        makeObservable(this);
    }
    @observable menuState = menuState.justCreated;
    @observable renderDiv: React.ReactNode;
    @observable inputValue = '';
    @observable createInputValue = '';
    @observable loading = false;
    @observable errorMessage = '';
    @observable mermaidCode = '';
    @observable isExampleMenuOpen = false;

    @action handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
        this.inputValue = e.target.value;
        console.log(e.target.value);
    };
    async componentDidMount() {
        this._props.setContentViewBox?.(this);
        mermaid.initialize({
            securityLevel: 'loose',
            startOnLoad: true,
            darkMode: true,
            flowchart: { useMaxWidth: false, htmlLabels: true, curve: 'cardinal' },
            gantt: { useMaxWidth: true, useWidth: 2000 },
        });
        if (!this.Document.testValue) {
            this.Document.height = 500;
            this.Document.width = 500;
        }
        this.Document.testValue = 'a';
        this.mermaidCode = 'a';
        if (typeof this.Document.drawingMermaidCode === 'string' && this.Document.menuState === 'drawing') {
            this.renderMermaidAsync(this.Document.drawingMermaidCode);
        }
        this.renderMermaidAsync(this.timeline);
        // this is so that ever time a new doc, text node or ink node, is created, this.createMermaidCode will run which will create a save
        // reaction(
        //     () => DocListCast(this.Document.data),
        //     () => this.lockInkStroke(),
        //     { fireImmediately: true }
        // );
        // reaction(
        //     () =>
        //         DocListCast(this.Document.data)
        //             .filter(doc => doc.type === 'rich text')
        //             .map(doc => (doc.text as RichTextField).Text),
        //     () => this.convertDrawingToMermaidCode(),
        //     { fireImmediately: true }
        // );
        this.lockInkStroke();
    }
    componentDidUpdate = () => {
        if (typeof this.Document.drawingMermaidCode === 'string' && this.Document.menuState === 'drawing') {
            this.renderMermaidAsync(this.Document.drawingMermaidCode);
        }
        if (typeof this.Document.gptMermaidCode === 'string' && this.Document.menuState === 'gpt') {
            this.renderMermaidAsync(this.Document.gptMermaidCode);
        }
    };
    switchRenderDiv() {
        switch (this.Document.menuState) {
            case 'option':
                this.renderDiv = this.renderOption();
                break;
            case 'drawing':
                this.renderDiv = this.renderDrawing();
                break;
            case 'gpt':
                this.renderDiv = this.renderGpt();
                break;
            case 'mermaidCode':
                this.renderDiv = this.renderMermaidCode();
                break;
            default:
                this.menuState = menuState.option;
                this.renderDiv = this.renderOption();
        }
    }
    renderMermaid = async (str: string) => {
        try {
            const { svg, bindFunctions } = await this.mermaidDiagram(str);
            return { svg, bindFunctions };
        } catch (error) {
            // console.error('Error rendering mermaid diagram:', error);
            return { svg: '', bindFunctions: undefined };
        }
    };
    mermaidDiagram = async (str: string) => mermaid.render('graph' + Date.now(), str);

    async renderMermaidAsync(mermaidCode: string) {
        try {
            const { svg, bindFunctions } = await this.renderMermaid(mermaidCode);
            const dashDiv = document.getElementById('dashDiv' + this.Document.title);
            if (dashDiv) {
                dashDiv.innerHTML = svg;
                // this.changeHeightWidth(svg);
                if (bindFunctions) {
                    bindFunctions(dashDiv);
                }
            }
        } catch (error) {
            console.error('Error rendering Mermaid:', error);
        }
    }
    changeHeightWidth(svgString: string) {
        const pattern = /width="([\d.]+)"\s*height="([\d.]+)"/;

        const match = svgString.match(pattern);

        if (match) {
            const width = parseFloat(match[1]);
            const height = parseFloat(match[2]);
            console.log(width);
            console.log(height);
            this.Document.width = width;
            this.Document.height = height;
        }
    }
    @action handleRenderClick = () => {
        this.mermaidCode = '';
        if (this.inputValue) {
            this.generateMermaidCode();
        }
    };
    @action async generateMermaidCode() {
        console.log('Generating Mermaid Code');
        const dashDiv = document.getElementById('dashDiv' + this.Document.title);
        if (dashDiv) {
            dashDiv.innerHTML = '';
        }
        this.loading = true;
        let prompt = '';
        prompt = 'Write this in mermaid code and only give me the mermaid code: ' + this.inputValue;
        console.log('there is no text save');
        // }
        const res = await gptAPICall(prompt, GPTCallType.MERMAID);
        this.loading = true;
        if (res === 'Error connecting with API.') {
            // If GPT call failed
            console.error('GPT call failed');
            this.errorMessage = 'GPT call failed; please try again.';
        } else if (res !== null) {
            // If GPT call succeeded, set htmlCode;;; TODO: check if valid html
            this.mermaidCode = res;
            console.log('GPT call succeeded:' + res);
            this.errorMessage = '';
        }
        this.renderMermaidAsync.call(this, this.removeWords(this.mermaidCode));
        this.Document.gptMermaidCode = this.removeWords(this.mermaidCode);
    }
    removeWords(inputStrIn: string) {
        const inputStr = inputStrIn.replace('```mermaid', '');
        return inputStr.replace('```', '');
    }
    // method to convert the drawings on collection node side the mermaid code
    async convertDrawingToMermaidCode() {
        let mermaidCode = '';
        let diagramExists = false;
        if (this.Document.data instanceof List) {
            const docArray: Doc[] = DocListCast(this.Document.data);
            const rectangleArray = docArray.filter(doc => doc.title === 'rectangle' || doc.title === 'circle');
            const lineArray = docArray.filter(doc => doc.title === 'line' || doc.title === 'stroke');
            const textArray = docArray.filter(doc => doc.type === 'rich text');
            const timeoutPromise = () =>
                new Promise(resolve => {
                    setTimeout(resolve, 0);
                });
            await timeoutPromise();
            const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke);
            if (inkStrokeArray[0] && inkStrokeArray.length === lineArray.length) {
                // if (this.isLeftRightDiagram(docArray)) {
                //     mermaidCode = 'graph LR;';
                // } else {
                //     mermaidCode = 'graph TD;';
                // }
                const inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView);
                for (let i = 0; i < rectangleArray.length; i++) {
                    const rectangle = rectangleArray[i];
                    for (let j = 0; j < lineArray.length; j++) {
                        const inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX;
                        const inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY;
                        const inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)
                            ?.inkScaledData()
                            .inkData.map(coord => coord.X)
                            .map(doc => doc * inkScaleX);
                        const inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)
                            ?.inkScaledData()
                            .inkData.map(coord => coord.Y)
                            .map(doc => doc * inkScaleY);
                        // need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations
                        const minX: number = Math.min(...inkStrokeXArray);
                        const minY: number = Math.min(...inkStrokeYArray);
                        const startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number);
                        const startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number);
                        const endX = inkStrokeXArray[inkStrokeXArray.length - 1] - minX + (lineArray[j].x as number);
                        const endY = inkStrokeYArray[inkStrokeYArray.length - 1] - minY + (lineArray[j].y as number);
                        if (this.isPointInBox(rectangle, [startX, startY])) {
                            for (let k = 0; k < rectangleArray.length; k++) {
                                const rectangle2 = rectangleArray[k];
                                if (this.isPointInBox(rectangle2, [endX, endY]) && typeof rectangle.x === 'number' && typeof rectangle2.x === 'number') {
                                    diagramExists = true;
                                    const linkedDocs: Doc[] = LinkManager.Instance.getAllRelatedLinks(lineArray[j]).map(d => DocCast(LinkManager.getOppositeAnchor(d, lineArray[j])));
                                    if (linkedDocs.length !== 0) {
                                        const linkedText = (linkedDocs[0].text as RichTextField).Text;
                                        mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---|' + linkedText + '|' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';';
                                    } else {
                                        mermaidCode += Math.abs(rectangle.x) + this.getTextInBox(rectangle, textArray) + '---' + Math.abs(rectangle2.x) + this.getTextInBox(rectangle2, textArray) + ';';
                                    }
                                }
                            }
                        }
                    }
                }
                // this will save the text
                if (diagramExists) {
                    this.Document.drawingMermaidCode = mermaidCode;
                } else {
                    this.Document.drawingMermaidCode = '';
                }
            }
        }
    }
    async lockInkStroke() {
        if (this.Document.data instanceof List) {
            const docArray: Doc[] = DocListCast(this.Document.data);
            const rectangleArray = docArray.filter(doc => doc.title === 'rectangle' || doc.title === 'circle');
            if(rectangleArray[0]){
                console.log(rectangleArray[0].x)
            }
            const lineArray = docArray.filter(doc => doc.title === 'line' || doc.title === 'stroke');
            const timeoutPromise = () =>
                new Promise(resolve => {
                    setTimeout(resolve, 0);
                });
            await timeoutPromise();
            const inkStrokeArray = lineArray.map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke);
            const inkingStrokeArray = inkStrokeArray.map(stroke => stroke?.ComponentView);
            for (let j = 0; j < lineArray.length; j++) {
                const inkScaleX = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleX;
                const inkScaleY = (inkingStrokeArray[j] as InkingStroke)?.inkScaledData().inkScaleY;
                const inkStrokeXArray = (inkingStrokeArray[j] as InkingStroke)
                    ?.inkScaledData()
                    .inkData.map(coord => coord.X)
                    .map(doc => doc * inkScaleX);
                const inkStrokeYArray = (inkingStrokeArray[j] as InkingStroke)
                    ?.inkScaledData()
                    .inkData.map(coord => coord.Y)
                    .map(doc => doc * inkScaleY);
                // need to minX and minY to since the inkStroke.x and.y is not relative to the doc. so I have to do some calcluations
                const minX: number = Math.min(...inkStrokeXArray);
                const minY: number = Math.min(...inkStrokeYArray);
                const startX = inkStrokeXArray[0] - minX + (lineArray[j]?.x as number);
                const startY = inkStrokeYArray[0] - minY + (lineArray[j]?.y as number);
                const endX = inkStrokeXArray[inkStrokeXArray.length - 1] - minX + (lineArray[j].x as number);
                const endY = inkStrokeYArray[inkStrokeYArray.length - 1] - minY + (lineArray[j].y as number);
                let closestStartRect:Doc=lineArray[0];
                let closestStartDistance=9999999;
                let closestEndRect:Doc=lineArray[0];
                let closestEndDistance=9999999;
                rectangleArray.forEach(rectangle => {
                    const midPoint=this.getMidPoint(rectangle)
                    if(this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY)<closestStartDistance&&this.euclideanDistance(midPoint.X,midPoint.Y,endX,endY)<closestEndDistance){
                        if(this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY)<this.euclideanDistance(midPoint.X,midPoint.Y,endX,endY)){
                            closestStartDistance=this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY);
                            closestStartRect=rectangle
                        }
                        else{
                            closestEndDistance=this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY);
                            closestEndRect=rectangle
                        }
                    }
                    else if(this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY)<closestStartDistance){
                        closestStartDistance=this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY);
                        closestStartRect=rectangle
                    }
                    else if(this.euclideanDistance(midPoint.X,midPoint.Y,endX,endY)<closestEndDistance){
                        closestEndDistance=this.euclideanDistance(midPoint.X,midPoint.Y,startX,startY);
                        closestEndRect=rectangle
                    }
                    
                });
                const inkToDelete:Doc=lineArray[j];
                if(typeof closestStartRect.x==='number'&&typeof closestStartRect.y==='number'&&typeof closestEndRect.x==='number'&&typeof closestEndRect.y==='number'&&typeof closestStartRect.width==='number'&&typeof closestStartRect.height==='number'){
                    const points: PointData[] = [
                        { X: closestStartRect.x, Y: closestStartRect.y },
                        { X: closestStartRect.x, Y: closestStartRect.y },
                        { X: closestEndRect.x, Y: closestEndRect.y },
                        { X: closestEndRect.x, Y: closestEndRect.y }
                    ];
                    const newInkDoc:Doc=Docs.Create.InkDocument(
                        points,
                        { title: 'stroke',
                        x: closestStartRect.x+closestStartRect.width/2,
                        y: closestStartRect.y+closestStartRect.height/2,
                        _width: closestStartRect.width,
                        _height: closestStartRect.height,
                        stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
                        1)
                    
                    DocumentManager.Instance.AddViewRenderedCb(this.Document, (docViewForYourCollection) => {
                        if (docViewForYourCollection && docViewForYourCollection.ComponentView) {
                            if (docViewForYourCollection.ComponentView.addDocument&&docViewForYourCollection.ComponentView.removeDocument) {
                                if(!inkToDelete.transformed){
                                    docViewForYourCollection.ComponentView?.removeDocument(inkToDelete)
                                    docViewForYourCollection.ComponentView?.addDocument(newInkDoc);
                                    newInkDoc.transformed=true;
    
                                }
                                const bruh2= DocListCast(this.Document.data).filter(doc => doc.title === 'line' || doc.title === 'stroke').map(doc => DocumentManager.Instance.getDocumentView(doc, this.DocumentView?.())).filter(inkView => inkView?.ComponentView instanceof InkingStroke).map(stroke => stroke?.ComponentView);
                                console.log(bruh2)
                                console.log((bruh2[0] as InkingStroke)?.inkScaledData())
                            }
                        }
                    });    
                }           
            }
        }
    }
    getMidPoint(rectangle:Doc){
        let midPoint={X:0,Y:0}
        if(typeof rectangle.x ==='number' && typeof rectangle.width==='number'&&typeof rectangle.y ==='number' && typeof rectangle.height==='number'){
            midPoint={X:rectangle.x+rectangle.width/2,Y:rectangle.y+rectangle.height/2};
        }
        return midPoint
    }
    euclideanDistance(x1: number, y1: number, x2: number, y2: number): number {
        const deltaX = x2 - x1;
        const deltaY = y2 - y1;
        return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
    }
    // isLeftRightDiagram = (docArray: Doc[]) => {
    //     const filteredDocs = docArray.filter(doc => doc.title === 'rectangle' || doc.title === 'circle');
    //     const xDoc = filteredDocs.map(doc => doc.x) as number[];
    //     const minX = Math.min(...xDoc);
    //     const xWidthDoc = filteredDocs.map(doc => {
    //         if (typeof doc.x === 'number' && typeof doc.width === 'number') {
    //             return doc.x + doc.width;
    //         }
    //     }) as number[];
    //     const maxX = Math.max(...xWidthDoc);
    //     const yDoc = filteredDocs.map(doc => doc.y) as number[];
    //     const minY = Math.min(...yDoc);
    //     const yHeightDoc = filteredDocs.map(doc => {
    //         if (typeof doc.x === 'number' && typeof doc.width === 'number') {
    //             return doc.x + doc.width;
    //         }
    //     }) as number[];
    //     const maxY = Math.max(...yHeightDoc);
    //     if (maxX - minX > maxY - minY) {
    //         return true;
    //     }
    //     return false;
    // };
    getTextInBox = (box: Doc, richTextArray: Doc[]): string => {
        for (let i = 0; i < richTextArray.length; i++) {
            const textDoc = richTextArray[i];
            if (typeof textDoc.x === 'number' && typeof textDoc.y === 'number' && typeof box.x === 'number' && typeof box.height === 'number' && typeof box.width === 'number' && typeof box.y === 'number') {
                if (textDoc.x > box.x && textDoc.x < box.x + box.width && textDoc.y > box.y && textDoc.y < box.y + box.height) {
                    if (box.title === 'rectangle') {
                        return '(' + ((textDoc.text as RichTextField)?.Text ?? '') + ')';
                    }
                    if (box.title === 'circle') {
                        return '((' + ((textDoc.text as RichTextField)?.Text ?? '') + '))';
                    }
                }
            }
        }
        return '( )';
    };
    isPointInBox = (box: Doc, line: number[]): boolean => {
        if (typeof line[0] === 'number' && typeof box.x === 'number' && typeof box.width === 'number' && typeof box.height === 'number' && typeof box.y === 'number' && typeof line[1] === 'number') {
            return line[0] < box.x + box.width && line[0] > box.x && line[1] > box.y && line[1] < box.y + box.height;
        }
        return false;
    };
    drawingButton = () => {
        this.Document.menuState = 'drawing';
    };
    gptButton = () => {
        this.Document.menuState = 'gpt';
    };
    mermaidButton = () => {
        this.Document.menuState = 'mermaidCode';
    };
    optionButton = () => {
        this.Document.menuState = 'option';
    };
    renderOption(): React.ReactNode {
        return (
            <div className="buttonCollections">
                <button type="button" onClick={this.drawingButton}>
                    Drawing - Create diagram from ink drawing
                </button>
                <button type="button" onClick={this.gptButton}>
                    GPT - Generate diagram with AI prompt
                </button>
                <button type="button" onClick={this.mermaidButton}>
                    Mermaid Editor - Create diagram with mermaid code
                </button>
            </div>
        );
    }
    renderDrawing(): React.ReactNode {
        return (
            <div ref={this._dragRef} className="DiagramBox-wrapper">
                <div className="content">
                    <div className="topBar">
                        <button className="backButtonDrawing" type="button" onClick={this.optionButton}>
                            Back
                        </button>
                        {!this.Document.mermaidCode && <p>Click the red pen icon to flip onto the collection side and draw a diagram with ink</p>}
                    </div>
                    <div id={'dashDiv' + this.Document.title} className="diagramBox" />
                </div>
            </div>
        );
    }

    renderGpt(): React.ReactNode {
        return (
            <div ref={this._dragRef} className="DiagramBox-wrapper">
                <div className="content">
                    <div className="search-bar">
                        <button className="backButton" type="button" onClick={this.optionButton}>
                            Back
                        </button>
                        <textarea value={this.inputValue} placeholder="Enter GPT prompt" onChange={this.handleInputChange} />
                        <button className="generateButton" type="button" onClick={this.handleRenderClick}>
                            Generate
                        </button>
                    </div>
                    {this.mermaidCode ? (
                        <div id={'dashDiv' + this.Document.title} className="diagramBox" />
                    ) : (
                        <div>{this.loading ? <div className="loading-circle" /> : <div>{this.errorMessage ? this.errorMessage : 'Insert prompt to generate diagram'}</div>}</div>
                    )}
                </div>
            </div>
        );
    }

    renderMermaidCode(): React.ReactNode {
        return (
            <div ref={this._dragRef} className="DiagramBox-wrapper">
                <div className="contentCode">
                    <div className="search-bar">
                        <button className="backButton" type="button" onClick={this.optionButton}>
                            Back
                        </button>
                        <button className="exampleButton" type="button" onClick={this.exampleButton}>
                            Examples
                        </button>
                    </div>
                    {this.isExampleMenuOpen && (
                        <div className="exampleButtonContainer">
                            <button type="button" onClick={this.flowButton}>
                                Flow
                            </button>
                            <button type="button" onClick={this.pieButton}>
                                Pie
                            </button>
                            <button type="button" onClick={this.timelineButton}>
                                Timeline
                            </button>
                            <button type="button" onClick={this.classButton}>
                                Class
                            </button>
                            <button type="button" onClick={this.mindmapButton}>
                                Mindmap
                            </button>
                        </div>
                    )}
                    <textarea value={this.createInputValue} placeholder="Enter Mermaid Code" onChange={this.handleInputChangeEditor} />
                    <div id={'dashDiv' + this.Document.title} className="diagramBox" />
                </div>
            </div>
        );
    }
    exampleButton = () => {
        if (this.isExampleMenuOpen) {
            this.isExampleMenuOpen = false;
        } else {
            this.isExampleMenuOpen = true;
        }
    };
    flowButton = () => {
        this.createInputValue = `flowchart TD
        A[Christmas] -->|Get money| B(Go shopping)
        B --> C{Let me think}
        C -->|One| D[Laptop]
        C -->|Two| E[iPhone]
        C -->|Three| F[fa:fa-car Car]`;
        this.renderMermaidAsync(this.createInputValue);
    };
    pieButton = () => {
        this.createInputValue = `pie title Pets adopted by volunteers
        "Dogs" : 386
        "Cats" : 85
        "Rats" : 15`;
        this.renderMermaidAsync(this.createInputValue);
    };
    timelineButton = () => {
        this.createInputValue = `gantt
        title A Gantt Diagram
        dateFormat  YYYY-MM-DD
        section Section
        A task           :a1, 2014-01-01, 30d
        Another task     :after a1  , 20d
        section Another
        Task in sec      :2014-01-12  , 12d
        another task      : 24d`;
        this.renderMermaidAsync(this.createInputValue);
    };
    classButton = () => {
        this.createInputValue = `classDiagram
        Animal <|-- Duck
        Animal <|-- Fish
        Animal <|-- Zebra
        Animal : +int age
        Animal : +String gender
        Animal: +isMammal()
        Animal: +mate()
        class Duck{
            +String beakColor
            +swim()
            +quack()
        }
        class Fish{
            -int sizeInFeet
            -canEat()
        }
        class Zebra{
            +bool is_wild
            +run()
        }`;
        this.renderMermaidAsync(this.createInputValue);
    };
    mindmapButton = () => {
        this.createInputValue = `mindmap
        root((mindmap))
            Origins
            Long history
            ::icon(fa fa-book)
            Popularisation
                British popular psychology author Tony Buzan
            Research
            On effectivness<br/>and features
            On Automatic creation
                Uses
                    Creative techniques
                    Strategic planning
                    Argument mapping
            Tools
            Pen and paper
            Mermaid`;
        this.renderMermaidAsync(this.createInputValue);
    };
    handleInputChangeEditor = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
        if (typeof e.target.value === 'string') {
            this.createInputValue = e.target.value;
            this.renderMermaidAsync(e.target.value);
        }
    };
    timeline = `gantt
    title College Timeline
    dateFormat  YYYY-MM-DD
    section Semester 1
    Orientation           :done,    des1, 2023-08-01, 2023-08-03
    Classes Start         :active,  des2, 2023-08-04, 2023-12-15
    Midterm Exams         :         des3, 2023-10-15, 2023-10-20
    End of Semester       :         des4, 2023-12-16, 2023-12-20
    section Semester 2
    Classes Start         :         des5, 2024-01-10, 2024-05-15
    Spring Break          :         des6, 2024-03-15, 2024-03-22
    Midterm Exams         :         des7, 2024-03-25, 2024-03-30
    Final Exams           :         des8, 2024-05-10, 2024-05-15
    section Summer Break
    Internship            :         des9, 2024-06-01, 2024-08-31
    section Semester 3
    Classes Start         :         des10, 2024-09-01, 2025-12-15
    Midterm Exams         :         des11, 2024-11-15, 2024-11-20
    End of Semester       :         des12, 2025-12-16, 2025-12-20
    section Semester 4
    Classes Start         :         des13, 2025-01-10, 2025-05-15
    Spring Break          :         des14, 2025-03-15, 2025-03-22
    Midterm Exams         :         des15, 2025-03-25, 2025-03-30
    Final Exams           :         des16, 2025-05-10, 2025-05-15
    Graduation            :         des17, 2025-05-20, 2025-05-21`;
    render() {
        this.switchRenderDiv();
        return (
            <div ref={this._ref} className="DiagramBox">
                {this.renderDiv}
            </div>
        );
    }
}

Docs.Prototypes.TemplateMap.set(DocumentType.DIAGRAM, {
    layout: { view: DiagramBox, dataField: 'dadta' },
    options: { _height: 700, _width: 700, _layout_fitWidth: false, _layout_nativeDimEditable: true, _layout_reflowVertical: true, waitForDoubleClickToClick: 'always', _layout_reflowHorizontal: true, systemIcon: 'BsGlobe' },
});
