import * as React from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@mui/material';
import { Toggle, ToggleType, Type } from 'browndash-components';
import { action, computed, Lambda, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { List } from '../../../fields/List';
import { ObjectField } from '../../../fields/ObjectField';
import { RichTextField } from '../../../fields/RichTextField';
import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../../fields/Types';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, Utils } from '../../../Utils';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { SelectionManager } from '../../util/SelectionManager';
import { SettingsManager } from '../../util/SettingsManager';
import { Transform } from '../../util/Transform';
import { undoBatch } from '../../util/UndoManager';
import { AntimodeMenu } from '../AntimodeMenu';
import { EditableView } from '../EditableView';
import { MainView } from '../MainView';
import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
import { DefaultStyleProvider } from '../StyleProvider';
import { CollectionLinearView } from './collectionLinear';
import './CollectionMenu.scss';

interface CollectionMenuProps {
    panelHeight: () => number;
    panelWidth: () => number;
}

@observer
export class CollectionMenu extends AntimodeMenu<CollectionMenuProps> {
    @observable static Instance: CollectionMenu;

    @observable SelectedCollection: DocumentView | undefined = undefined;
    @observable FieldKey: string;

    private _docBtnRef = React.createRef<HTMLDivElement>();

    constructor(props: any) {
        super(props);
        this.FieldKey = '';
        CollectionMenu.Instance = this;
        this._canFade = false; // don't let the inking menu fade away
        runInAction(() => (this.Pinned = Cast(Doc.UserDoc()['menuCollections-pinned'], 'boolean', true)));
        this.jumpTo(300, 300);
    }

    componentDidMount() {
        reaction(
            () => SelectionManager.Views.lastElement(),
            view => view && this.SetSelection(view)
        );
    }

    @action
    SetSelection(view: DocumentView) {
        this.SelectedCollection = view;
    }

    @action
    toggleMenuPin = (e: React.MouseEvent) => {
        Doc.UserDoc()['menuCollections-pinned'] = this.Pinned = !this.Pinned;
        if (!this.Pinned && this._left < 0) {
            this.jumpTo(300, 300);
        }
    };

    @action
    toggleTopBar = () => {
        if (SettingsManager.Instance.headerBarHeight > 0) {
            SettingsManager.Instance.headerBarHeight = 0;
        } else {
            SettingsManager.Instance.headerBarHeight = 60;
        }
    };

    @action
    toggleProperties = () => {
        if (MainView.Instance.propertiesWidth() > 0) {
            SettingsManager.Instance.propertiesWidth = 0;
        } else {
            SettingsManager.Instance.propertiesWidth = 300;
        }
    };

    buttonBarXf = () => {
        if (!this._docBtnRef.current) return Transform.Identity();
        const { scale, translateX, translateY } = Utils.GetScreenTransform(this._docBtnRef.current);
        return new Transform(-translateX, -translateY, 1 / scale);
    };

    @computed get contMenuButtons() {
        const selDoc = Doc.MyContextMenuBtns;
        return !(selDoc instanceof Doc) ? null : (
            <div className="collectionMenu-contMenuButtons" ref={this._docBtnRef} style={{ height: this._props.panelHeight() }}>
                <CollectionLinearView
                    Document={selDoc}
                    fieldKey="data"
                    dropAction="embed"
                    setHeight={returnFalse}
                    styleProvider={DefaultStyleProvider}
                    bringToFront={emptyFunction}
                    select={emptyFunction}
                    isContentActive={returnTrue}
                    isAnyChildContentActive={returnFalse}
                    isSelected={returnFalse}
                    docViewPath={returnEmptyDoclist}
                    moveDocument={returnFalse}
                    addDocument={returnFalse}
                    addDocTab={DocumentViewInternal.addDocTabFunc}
                    pinToPres={emptyFunction}
                    removeDocument={returnFalse}
                    ScreenToLocalTransform={this.buttonBarXf}
                    PanelWidth={this._props.panelWidth}
                    PanelHeight={this._props.panelHeight}
                    renderDepth={0}
                    focus={emptyFunction}
                    whenChildContentsActiveChanged={emptyFunction}
                    childFilters={returnEmptyFilter}
                    childFiltersByRanges={returnEmptyFilter}
                    searchFilterDocs={returnEmptyDoclist}
                />
            </div>
        );
    }

    render() {
        const headerIcon = SettingsManager.Instance.headerBarHeight > 0 ? 'angle-double-up' : 'angle-double-down';
        const headerTitle = SettingsManager.Instance.headerBarHeight > 0 ? 'Close Header Bar' : 'Open Header Bar';
        const propIcon = SettingsManager.Instance.propertiesWidth > 0 ? 'angle-double-right' : 'angle-double-left';
        const propTitle = SettingsManager.Instance.propertiesWidth > 0 ? 'Close Properties' : 'Open Properties';

        const hardCodedButtons = (
            <div className={`hardCodedButtons`}>
                <Toggle
                    toggleType={ToggleType.BUTTON}
                    type={Type.PRIM}
                    color={SettingsManager.userColor}
                    onClick={this.toggleTopBar}
                    toggleStatus={SettingsManager.Instance.headerBarHeight > 0}
                    icon={<FontAwesomeIcon icon={headerIcon} size="lg" />}
                    tooltip={headerTitle}
                />
                <Toggle
                    toggleType={ToggleType.BUTTON}
                    type={Type.PRIM}
                    color={SettingsManager.userColor}
                    onClick={this.toggleProperties}
                    toggleStatus={SettingsManager.Instance.propertiesWidth > 0}
                    icon={<FontAwesomeIcon icon={propIcon} size="lg" />}
                    tooltip={propTitle}
                />
            </div>
        );

        //dash col linear view buttons
        const contMenuButtons = (
            <div
                className="collectionMenu-container"
                style={{
                    background: SettingsManager.userBackgroundColor,
                    // borderColor: SettingsManager.userColor
                }}>
                {this.contMenuButtons}
                {hardCodedButtons}
            </div>
        );

        return contMenuButtons;
    }
}

interface CollectionViewMenuProps {
    type: CollectionViewType;
    fieldKey: string;
    docView: DocumentView;
}

const stopPropagation = (e: React.SyntheticEvent) => e.stopPropagation();

@observer
export class CollectionViewBaseChrome extends React.Component<CollectionViewMenuProps> {
    //(!)?\(\(\(doc.(\w+) && \(doc.\w+ as \w+\).includes\(\"(\w+)\"\)

    get document() {
        return this.props.docView?.Document;
    }
    get target() {
        return this.document;
    }
    _templateCommand = {
        params: ['target', 'source'],
        title: 'item view',
        script: 'this.target.childLayoutTemplate = getDocTemplate(this.source?.[0])',
        immediate: undoBatch((source: Doc[]) => {
            let formatStr = source.length && Cast(source[0].text, RichTextField, null)?.Text;
            try {
                formatStr && JSON.parse(formatStr);
            } catch (e) {
                formatStr = '';
            }
            if (source.length === 1 && formatStr) {
                Doc.SetInPlace(this.target, 'childLayoutString', formatStr, false);
            } else if (source.length) {
                this.target.childLayoutTemplate = Doc.getDocTemplate(source?.[0]);
            } else {
                Doc.SetInPlace(this.target, 'childLayoutString', undefined, true);
                Doc.SetInPlace(this.target, 'childLayoutTemplate', undefined, true);
            }
        }),
        initialize: emptyFunction,
    };
    _narrativeCommand = {
        params: ['target', 'source'],
        title: 'child click view',
        script: 'this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])',
        immediate: undoBatch((source: Doc[]) => source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))),
        initialize: emptyFunction,
    };
    _contentCommand = {
        params: ['target', 'source'],
        title: 'set content',
        script: 'getProto(this.target).data = copyField(this.source);',
        immediate: undoBatch((source: Doc[]) => (Doc.GetProto(this.target).data = new List<Doc>(source))),
        initialize: emptyFunction,
    };
    _onClickCommand = {
        params: ['target', 'proxy'],
        title: 'copy onClick',
        script: `{ if (this.proxy?.[0]) {
             getProto(this.proxy[0]).onClick = copyField(this.target.onClick); 
             getProto(this.proxy[0]).target = this.target.target;
             getProto(this.proxy[0]).source = copyField(this.target.source); 
            }}`,
        immediate: undoBatch((source: Doc[]) => {}),
        initialize: emptyFunction,
    };
    _viewCommand = {
        params: ['target'],
        title: 'bookmark view',
        script: "this.target._freeform_panX = self['target-freeform_panX']; this.target._freeform_panY = this['target-freeform_panY']; this.target._freeform_scale = this['target_freeform_scale']; gotoFrame(this.target, this['target-currentFrame']);",
        immediate: undoBatch((source: Doc[]) => {
            this.target._freeform_panX = 0;
            this.target._freeform_panY = 0;
            this.target._freeform_scale = 1;
            this.target._currentFrame = this.target._currentFrame === undefined ? undefined : 0;
        }),
        initialize: (button: Doc) => {
            button['target-panX'] = this.target._freeform_panX;
            button['target-panY'] = this.target._freeform_panY;
            button['target-_ayout_scale'] = this.target._freeform_scale;
            button['target-currentFrame'] = this.target._currentFrame;
        },
    };
    _clusterCommand = {
        params: ['target'],
        title: 'fit content',
        script: 'this.target._freeform_fitContentsToBox = !this.target._freeform_fitContentsToBox;',
        immediate: undoBatch((source: Doc[]) => (this.target._freeform_fitContentsToBox = !this.target._freeform_fitContentsToBox)),
        initialize: emptyFunction,
    };
    _fitContentCommand = {
        params: ['target'],
        title: 'toggle clusters',
        script: 'this.target._freeform_useClusters = !this.target._freeform_useClusters;',
        immediate: undoBatch((source: Doc[]) => (this.target._freeform_useClusters = !this.target._freeform_useClusters)),
        initialize: emptyFunction,
    };
    _saveFilterCommand = {
        params: ['target'],
        title: 'save filter',
        script: `this.target._childFilters = compareLists(this['target-childFilters'],this.target._childFilters) ? undefined : copyField(this['target-childFilters']); 
        this.target._searchFilterDocs = compareLists(this['target-searchFilterDocs'],this.target._searchFilterDocs) ? undefined: copyField(this['target-searchFilterDocs']);`,
        immediate: undoBatch((source: Doc[]) => {
            this.target._childFilters = undefined;
            this.target._searchFilterDocs = undefined;
        }),
        initialize: (button: Doc) => {
            const activeDash = Doc.ActiveDashboard;
            if (activeDash) {
                button['target-childFilters'] = (Doc.MySearcher._childFilters || activeDash._childFilters) instanceof ObjectField ? ObjectField.MakeCopy((Doc.MySearcher._childFilters || activeDash._childFilters) as any as ObjectField) : undefined;
                button['target-searchFilterDocs'] = activeDash._searchFilterDocs instanceof ObjectField ? ObjectField.MakeCopy(activeDash._searchFilterDocs as any as ObjectField) : undefined;
            }
        },
    };

    @computed get _freeform_commands() {
        return Doc.noviceMode ? [this._viewCommand, this._saveFilterCommand] : [this._viewCommand, this._saveFilterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand];
    }
    @computed get _stacking_commands() {
        return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
    }
    @computed get _notetaking_commands() {
        return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
    }
    @computed get _masonry_commands() {
        return Doc.noviceMode ? undefined : [this._contentCommand, this._templateCommand];
    }
    @computed get _schema_commands() {
        return Doc.noviceMode ? undefined : [this._templateCommand, this._narrativeCommand];
    }
    @computed get _doc_commands() {
        return Doc.noviceMode ? undefined : [this._onClickCommand];
    }
    @computed get _tree_commands() {
        return undefined;
    }
    private get _buttonizableCommands() {
        switch (this.props.type) {
            default:
                return this._doc_commands;
            case CollectionViewType.Freeform:
                return this._freeform_commands;
            case CollectionViewType.Tree:
                return this._tree_commands;
            case CollectionViewType.Schema:
                return this._schema_commands;
            case CollectionViewType.Stacking:
                return this._stacking_commands;
            case CollectionViewType.NoteTaking:
                return this._notetaking_commands;
            case CollectionViewType.Masonry:
                return this._stacking_commands;
            case CollectionViewType.Time:
                return this._freeform_commands;
            case CollectionViewType.Carousel:
                return this._freeform_commands;
            case CollectionViewType.Carousel3D:
                return this._freeform_commands;
        }
    }
    private _commandRef = React.createRef<HTMLInputElement>();
    private _viewRef = React.createRef<HTMLInputElement>();
    @observable private _currentKey: string = '';

    componentDidMount = action(() => {
        this._currentKey = this._currentKey || (this._buttonizableCommands?.length ? this._buttonizableCommands[0]?.title : '');
    });

    @undoBatch
    viewChanged = (e: React.ChangeEvent) => {
        const target = this.document !== Doc.MyLeftSidebarPanel ? this.document : DocCast(this.document.proto);
        //@ts-ignore
        target._type_collection = e.target.selectedOptions[0].value;
    };

    commandChanged = (e: React.ChangeEvent) => {
        //@ts-ignore
        runInAction(() => (this._currentKey = e.target.selectedOptions[0].value));
    };

    @action closeViewSpecs = () => {
        this.document._facetWidth = 0;
    };

    private dropDisposer?: DragManager.DragDropDisposer;
    protected createDropTarget = (ele: HTMLDivElement) => {
        this.dropDisposer?.();
        if (ele) {
            this.dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.document);
        }
    };

    @undoBatch
    @action
    protected drop(e: Event, de: DragManager.DropEvent): boolean {
        const docDragData = de.complete.docDragData;
        if (docDragData?.draggedDocuments.length) {
            this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate(docDragData.draggedDocuments || []));
            e.stopPropagation();
            return true;
        }
        return false;
    }

    dragViewDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(
            this,
            e,
            (e, down, delta) => {
                const vtype = this.props.type;
                const c = {
                    params: ['target'],
                    title: vtype,
                    script: `this.target._type_collection = '${StrCast(this.props.type)}'`,
                    immediate: (source: Doc[]) => (this.document._type_collection = Doc.getDocTemplate(source?.[0])),
                    initialize: emptyFunction,
                };
                DragManager.StartButtonDrag([this._viewRef.current!], c.script, StrCast(c.title), { target: this.document }, c.params, c.initialize, e.clientX, e.clientY);
                return true;
            },
            emptyFunction,
            emptyFunction
        );
    };
    dragCommandDown = (e: React.PointerEvent) => {
        setupMoveUpEvents(
            this,
            e,
            (e, down, delta) => {
                this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title, { target: this.document }, c.params, c.initialize, e.clientX, e.clientY));
                return true;
            },
            emptyFunction,
            () => {
                this._buttonizableCommands?.filter(c => c.title === this._currentKey).map(c => c.immediate([]));
            }
        );
    };

    @computed get templateChrome() {
        return (
            <div className="collectionViewBaseChrome-template" ref={this.createDropTarget}>
                <Tooltip title={<div className="dash-tooltip">drop document to apply or drag to create button</div>} placement="bottom">
                    <div className="commandEntry-outerDiv" ref={this._commandRef} onPointerDown={this.dragCommandDown}>
                        <button className={'antimodeMenu-button'}>
                            <FontAwesomeIcon icon="bullseye" size="lg" />
                        </button>
                        <select className="collectionViewBaseChrome-cmdPicker" onPointerDown={stopPropagation} onChange={this.commandChanged} value={this._currentKey}>
                            <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={'empty'} value={''} />
                            {this._buttonizableCommands?.map(cmd => (
                                <option className="collectionViewBaseChrome-viewOption" onPointerDown={stopPropagation} key={cmd.title} value={cmd.title}>
                                    {cmd.title}
                                </option>
                            ))}
                        </select>
                    </div>
                </Tooltip>
            </div>
        );
    }
    render() {
        return (
            <div className="collectionMenu-cont">
                <div className="collectionMenu">
                    <div className="collectionViewBaseChrome">{!this._buttonizableCommands ? null : this.templateChrome}</div>
                </div>
            </div>
        );
    }
}

@observer
export class CollectionNoteTakingViewChrome extends React.Component<CollectionViewMenuProps> {
    @observable private _currentKey: string = '';
    @observable private suggestions: string[] = [];

    get document() {
        return this.props.docView.props.Document;
    }

    @computed private get descending() {
        return StrCast(this.document._columnsSort) === 'descending';
    }
    @computed get pivotField() {
        return StrCast(this.document._pivotField);
    }

    getKeySuggestions = async (value: string): Promise<string[]> => {
        const val = value.toLowerCase();
        const docs = DocListCast(this.document[this.props.fieldKey]);

        if (Doc.UserDoc().noviceMode) {
            if (docs instanceof Doc) {
                const keys = Object.keys(docs).filter(key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('author_date') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0].toUpperCase() === key[0] && key[0] !== '_'));
                return keys.filter(key => key.toLowerCase().indexOf(val) > -1);
            } else {
                const keys = new Set<string>();
                docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
                const noviceKeys = Array.from(keys).filter(
                    key => key.indexOf('title') >= 0 || key.indexOf('author') >= 0 || key.indexOf('author_date') >= 0 || key.indexOf('modificationDate') >= 0 || (key[0]?.toUpperCase() === key[0] && key[0] !== '_')
                );
                return noviceKeys.filter(key => key.toLowerCase().indexOf(val) > -1);
            }
        }

        if (docs instanceof Doc) {
            return Object.keys(docs).filter(key => key.toLowerCase().indexOf(val) > -1);
        } else {
            const keys = new Set<string>();
            docs.forEach(doc => Doc.allKeys(doc).forEach(key => keys.add(key)));
            return Array.from(keys).filter(key => key.toLowerCase().indexOf(val) > -1);
        }
    };

    @action
    onKeyChange = (e: React.ChangeEvent, { newValue }: { newValue: string }) => {
        this._currentKey = newValue;
    };

    getSuggestionValue = (suggestion: string) => suggestion;

    renderSuggestion = (suggestion: string) => {
        return <p>{suggestion}</p>;
    };

    onSuggestionFetch = async ({ value }: { value: string }) => {
        const sugg = await this.getKeySuggestions(value);
        runInAction(() => {
            this.suggestions = sugg;
        });
    };

    @action
    onSuggestionClear = () => {
        this.suggestions = [];
    };

    @action
    setValue = (value: string) => {
        this.document._pivotField = value;
        return true;
    };

    @action toggleSort = () => {
        this.document._columnsSort = this.document._columnsSort === 'descending' ? 'ascending' : this.document._columnsSort === 'ascending' ? undefined : 'descending';
    };
    @action resetValue = () => {
        this._currentKey = this.pivotField;
    };

    render() {
        const doctype = this.props.docView.Document.type;
        const isPres: boolean = doctype === DocumentType.PRES;
        return isPres ? null : (
            <div className="collectionStackingViewChrome-cont">
                <div className="collectionStackingViewChrome-pivotField-cont">
                    <div className="collectionStackingViewChrome-pivotField-label">GROUP BY:</div>
                    <div className="collectionStackingViewChrome-sortIcon" onClick={this.toggleSort} style={{ transform: `rotate(${this.descending ? '180' : '0'}deg)` }}>
                        <FontAwesomeIcon icon="caret-up" size="2x" color="white" />
                    </div>
                    <div className="collectionStackingViewChrome-pivotField">
                        <EditableView
                            GetValue={() => this.pivotField}
                            autosuggestProps={{
                                resetValue: this.resetValue,
                                value: this._currentKey,
                                onChange: this.onKeyChange,
                                autosuggestProps: {
                                    inputProps: {
                                        value: this._currentKey,
                                        // @ts-ignore
                                        onChange: this.onKeyChange,
                                    },
                                    getSuggestionValue: this.getSuggestionValue,
                                    suggestions: this.suggestions,
                                    alwaysRenderSuggestions: true,
                                    renderSuggestion: this.renderSuggestion,
                                    onSuggestionsFetchRequested: this.onSuggestionFetch,
                                    onSuggestionsClearRequested: this.onSuggestionClear,
                                },
                            }}
                            oneLine
                            SetValue={this.setValue}
                            contents={this.pivotField ? this.pivotField : 'N/A'}
                        />
                    </div>
                </div>
            </div>
        );
    }
}

/**
 * Chrome for grid view.
 */
@observer
export class CollectionGridViewChrome extends React.Component<CollectionViewMenuProps> {
    private clicked: boolean = false;
    private entered: boolean = false;
    private decrementLimitReached: boolean = false;
    @observable private resize = false;
    private resizeListenerDisposer: Opt<Lambda>;
    get document() {
        return this.props.docView.props.Document;
    }

    @computed get panelWidth() {
        return this.props.docView.props.PanelWidth();
    }

    componentDidMount() {
        runInAction(() => (this.resize = this.props.docView.props.PanelWidth() < 700));

        // listener to reduce text on chrome resize (panel resize)
        this.resizeListenerDisposer = reaction(
            () => this.panelWidth,
            newValue => (this.resize = newValue < 700)
        );
    }

    componentWillUnmount() {
        this.resizeListenerDisposer?.();
    }

    get numCols() {
        return NumCast(this.document.gridNumCols, 10);
    }

    /**
     * Sets the value of `numCols` on the grid's Document to the value entered.
     */
    onNumColsChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        if (e.currentTarget.valueAsNumber > 0) undoBatch(() => (this.document.gridNumCols = e.currentTarget.valueAsNumber))();
    };

    /**
     * Sets the value of `rowHeight` on the grid's Document to the value entered.
     */
    // @undoBatch
    // onRowHeightEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
    //     if (e.key === "Enter" || e.key === "Tab") {
    //         if (e.currentTarget.valueAsNumber > 0 && this.document.rowHeight as number !== e.currentTarget.valueAsNumber) {
    //             this.document.rowHeight = e.currentTarget.valueAsNumber;
    //         }
    //     }
    // }

    /**
     * Sets whether the grid is flexible or not on the grid's Document.
     */
    @undoBatch
    toggleFlex = () => {
        this.document.gridFlex = !BoolCast(this.document.gridFlex, true);
    };

    /**
     * Increments the value of numCols on button click
     */
    onIncrementButtonClick = () => {
        this.clicked = true;
        this.entered && (this.document.gridNumCols as number)--;
        undoBatch(() => (this.document.gridNumCols = this.numCols + 1))();
        this.entered = false;
    };

    /**
     * Decrements the value of numCols on button click
     */
    onDecrementButtonClick = () => {
        this.clicked = true;
        if (this.numCols > 1 && !this.decrementLimitReached) {
            this.entered && (this.document.gridNumCols as number)++;
            undoBatch(() => (this.document.gridNumCols = this.numCols - 1))();
            if (this.numCols === 1) this.decrementLimitReached = true;
        }
        this.entered = false;
    };

    /**
     * Increments the value of numCols on button hover
     */
    incrementValue = () => {
        this.entered = true;
        if (!this.clicked && !this.decrementLimitReached) {
            this.document.gridNumCols = this.numCols + 1;
        }
        this.decrementLimitReached = false;
        this.clicked = false;
    };

    /**
     * Decrements the value of numCols on button hover
     */
    decrementValue = () => {
        this.entered = true;
        if (!this.clicked) {
            if (this.numCols > 1) {
                this.document.gridNumCols = this.numCols - 1;
            } else {
                this.decrementLimitReached = true;
            }
        }

        this.clicked = false;
    };

    /**
     * Toggles the value of preventCollision
     */
    toggleCollisions = () => {
        this.document.gridPreventCollision = !this.document.gridPreventCollision;
    };

    /**
     * Changes the value of the compactType
     */
    changeCompactType = (e: React.ChangeEvent<HTMLSelectElement>) => {
        // need to change startCompaction so that this operation will be undoable.
        this.document.gridStartCompaction = e.target.selectedOptions[0].value;
    };

    render() {
        return (
            <div className="collectionGridViewChrome-cont">
                <span className="grid-control" style={{ width: this.resize ? '25%' : '30%' }}>
                    <span className="grid-icon">
                        <FontAwesomeIcon icon="columns" size="1x" />
                    </span>
                    <input
                        className="collectionGridViewChrome-entryBox"
                        type="number"
                        value={this.numCols}
                        onChange={this.onNumColsChange}
                        onClick={(e: React.MouseEvent<HTMLInputElement, MouseEvent>) => {
                            e.stopPropagation();
                            e.preventDefault();
                            e.currentTarget.focus();
                        }}
                    />
                    <input className="collectionGridViewChrome-columnButton" onClick={this.onIncrementButtonClick} onMouseEnter={this.incrementValue} onMouseLeave={this.decrementValue} type="button" value="↑" />
                    <input className="collectionGridViewChrome-columnButton" style={{ marginRight: 5 }} onClick={this.onDecrementButtonClick} onMouseEnter={this.decrementValue} onMouseLeave={this.incrementValue} type="button" value="↓" />
                </span>
                <span className="grid-control" style={{ width: this.resize ? '12%' : '20%' }}>
                    <input type="checkbox" style={{ marginRight: 5 }} onChange={this.toggleCollisions} checked={!this.document.gridPreventCollision} />
                    <label className="flexLabel">{this.resize ? 'Coll' : 'Collisions'}</label>
                </span>

                <select
                    className="collectionGridViewChrome-viewPicker"
                    style={{ marginRight: 5 }}
                    onPointerDown={stopPropagation}
                    onChange={this.changeCompactType}
                    value={StrCast(this.document.gridStartCompaction, StrCast(this.document.gridCompaction))}>
                    {['vertical', 'horizontal', 'none'].map(type => (
                        <option className="collectionGridViewChrome-viewOption" onPointerDown={stopPropagation} value={type}>
                            {this.resize ? type[0].toUpperCase() + type.substring(1) : 'Compact: ' + type}
                        </option>
                    ))}
                </select>

                <span className="grid-control" style={{ width: this.resize ? '12%' : '20%' }}>
                    <input style={{ marginRight: 5 }} type="checkbox" onChange={this.toggleFlex} checked={BoolCast(this.document.gridFlex, true)} />
                    <label className="flexLabel">{this.resize ? 'Flex' : 'Flexible'}</label>
                </span>

                <button onClick={() => (this.document.gridResetLayout = true)}>{!this.resize ? 'Reset' : <FontAwesomeIcon icon="redo-alt" size="1x" />}</button>
            </div>
        );
    }
}
