import { action, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as ReactDOM from 'react-dom';
import * as GoldenLayout from '../../../client/goldenLayout';
import { Doc, DocListCast, Opt } from '../../../fields/Doc';
import { Id } from '../../../fields/FieldSymbols';
import { InkTool } from '../../../fields/InkField';
import { List } from '../../../fields/List';
import { Cast, ImageCast, NumCast, StrCast } from '../../../fields/Types';
import { ImageField } from '../../../fields/URLField';
import { inheritParentAcls } from '../../../fields/util';
import { emptyFunction, incrementTitleCopy } from '../../../Utils';
import { DocServer } from '../../DocServer';
import { Docs } from '../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../documents/DocumentTypes';
import { DragManager } from '../../util/DragManager';
import { InteractionUtils } from '../../util/InteractionUtils';
import { ScriptingGlobals } from '../../util/ScriptingGlobals';
import { SelectionManager } from '../../util/SelectionManager';
import { undoBatch, UndoManager } from '../../util/UndoManager';
import { DashboardView } from '../DashboardView';
import { LightboxView } from '../LightboxView';
import './CollectionDockingView.scss';
import { CollectionFreeFormView } from './collectionFreeForm';
import { CollectionSubView, SubCollectionViewProps } from './CollectionSubView';
import { TabDocView } from './TabDocView';
import React = require('react');
const _global = (window /* browser */ || global) /* node */ as any;

@observer
export class CollectionDockingView extends CollectionSubView() {
    @observable public static Instance: CollectionDockingView | undefined;
    public static makeDocumentConfig(document: Doc, panelName?: string, width?: number) {
        return {
            type: 'react-component',
            component: 'DocumentFrameRenderer',
            title: document.title,
            width: width,
            props: {
                documentId: document[Id],
                panelName, // name of tab that can be used to close or replace its contents
            },
        };
    }

    private _reactionDisposer?: IReactionDisposer;
    private _lightboxReactionDisposer?: IReactionDisposer;
    private _containerRef = React.createRef<HTMLDivElement>();
    public _flush: UndoManager.Batch | undefined;
    private _ignoreStateChange = '';
    public tabMap: Set<any> = new Set();
    public get HasFullScreen() {
        return this._goldenLayout._maximisedItem !== null;
    }
    private _goldenLayout: any = null;

    constructor(props: SubCollectionViewProps) {
        super(props);
        if (this.props.renderDepth < 0) runInAction(() => (CollectionDockingView.Instance = this));
        //Why is this here?
        (window as any).React = React;
        (window as any).ReactDOM = ReactDOM;
        DragManager.StartWindowDrag = this.StartOtherDrag;
        this.rootDoc.myTrails; // this is equivalent to having a prefetchProxy for myTrails which is needed for the My Trails button in the UI which assumes that Doc.ActiveDashboard.myTrails is legit...
    }

    /**
     * Switches from dragging a document around a freeform canvas to dragging it as a tab to be docked.
     *
     * @param e fake mouse down event position data containing pageX and pageY coordinates
     * @param dragDocs the documents to be dragged
     * @param batch optionally an undo batch that has been started to use instead of starting a new batch
     */
    public StartOtherDrag = (e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => {
        this._flush = this._flush ?? UndoManager.StartBatch('golden layout drag');
        const config = dragDocs.length === 1 ? CollectionDockingView.makeDocumentConfig(dragDocs[0]) : { type: 'row', content: dragDocs.map(doc => CollectionDockingView.makeDocumentConfig(doc)) };
        const dragSource = CollectionDockingView.Instance?._goldenLayout.createDragSource(document.createElement('div'), config);
        this.tabDragStart(dragSource, finishDrag);
        dragSource._dragListener.onMouseDown({ pageX: e.pageX, pageY: e.pageY, preventDefault: emptyFunction, button: 0 });
    };

    tabItemDropped = () => DragManager.CompleteWindowDrag?.(false);
    tabDragStart = (proxy: any, finishDrag?: (aborted: boolean) => void) => {
        const dashDoc = proxy?._contentItem?.tab?.DashDoc as Doc;
        dashDoc && (DragManager.DocDragData = new DragManager.DocumentDragData([proxy._contentItem.tab.DashDoc]));
        DragManager.CompleteWindowDrag = (aborted: boolean) => {
            if (aborted) {
                proxy._dragListener.AbortDrag();
                if (this._flush) {
                    this._flush.cancel(); // cancel the undo change being logged
                    this._flush = undefined;
                    this.setupGoldenLayout(); // restore golden layout to where it was before the drag (this is a no-op when using StartOtherDrag because the proxy dragged item was never in the golden layout)
                }
                DragManager.CompleteWindowDrag = undefined;
            }
            finishDrag?.(aborted);
        };
    };
    @undoBatch
    public CloseFullScreen = () => {
        this._goldenLayout._maximisedItem?.toggleMaximise();
        this.stateChanged();
    };

    @undoBatch
    public static CloseSplit(document: Opt<Doc>, panelName?: string): boolean {
        if (CollectionDockingView.Instance) {
            const tab = Array.from(CollectionDockingView.Instance.tabMap.keys()).find(tab => (panelName ? tab.contentItem.config.props.panelName === panelName : tab.DashDoc === document));
            if (tab) {
                const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
                if (j !== -1) {
                    tab.header.parent.contentItems[j].remove();
                    return CollectionDockingView.Instance.layoutChanged();
                }
            }
        }

        return false;
    }

    @undoBatch
    public static OpenFullScreen(doc: Doc) {
        SelectionManager.DeselectAll();
        const instance = CollectionDockingView.Instance;
        if (instance) {
            if (doc._viewType === CollectionViewType.Docking && doc.layoutKey === 'layout') {
                return DashboardView.openDashboard(doc);
            }
            const newItemStackConfig = {
                type: 'stack',
                content: [CollectionDockingView.makeDocumentConfig(Doc.MakeAlias(doc))],
            };
            const docconfig = instance._goldenLayout.root.layoutManager.createContentItem(newItemStackConfig, instance._goldenLayout);
            instance._goldenLayout.root.contentItems[0].addChild(docconfig);
            docconfig.callDownwards('_$init');
            instance._goldenLayout._$maximiseItem(docconfig);
            instance._goldenLayout.emit('stateChanged');
            instance.stateChanged();
        }
        return true;
    }

    @undoBatch
    @action
    public static ReplaceTab(document: Doc, panelName: string, stack: any, addToSplit?: boolean): boolean {
        const instance = CollectionDockingView.Instance;
        if (!instance) return false;
        const newConfig = CollectionDockingView.makeDocumentConfig(document, panelName);
        if (!panelName && stack) {
            const activeContentItemIndex = stack.contentItems.findIndex((item: any) => item.config === stack._activeContentItem.config);
            const newContentItem = stack.layoutManager.createContentItem(newConfig, instance._goldenLayout);
            stack.addChild(newContentItem.contentItems[0], undefined);
            stack.contentItems[activeContentItemIndex].remove();
            return instance.layoutChanged();
        }
        const tab = Array.from(instance.tabMap.keys()).find(tab => tab.contentItem.config.props.panelName === panelName);
        if (tab) {
            tab.header.parent.addChild(newConfig, undefined);
            const j = tab.header.parent.contentItems.indexOf(tab.contentItem);
            !addToSplit && j !== -1 && tab.header.parent.contentItems[j].remove();
            return instance.layoutChanged();
        }
        return CollectionDockingView.AddSplit(document, panelName, stack, panelName);
    }

    @undoBatch
    public static ToggleSplit(doc: Doc, location: string, stack?: any, panelName?: string) {
        return CollectionDockingView.Instance && Array.from(CollectionDockingView.Instance.tabMap.keys()).findIndex(tab => tab.DashDoc === doc) !== -1
            ? CollectionDockingView.CloseSplit(doc)
            : CollectionDockingView.AddSplit(doc, location, stack, panelName);
    }

    //
    //  Creates a split on any side of the docking view based on the passed input pullSide and then adds the Document to the requested side
    //
    @undoBatch
    @action
    public static AddSplit(document: Doc, pullSide: string, stack?: any, panelName?: string) {
        if (document?._viewType === CollectionViewType.Docking) return DashboardView.openDashboard(document);
        if (!CollectionDockingView.Instance) return false;
        const tab = Array.from(CollectionDockingView.Instance.tabMap).find(tab => tab.DashDoc === document);
        if (tab) {
            tab.header.parent.setActiveContentItem(tab.contentItem);
            return true;
        }
        const instance = CollectionDockingView.Instance;
        const glayRoot = instance._goldenLayout.root;
        if (!instance) return false;
        const docContentConfig = CollectionDockingView.makeDocumentConfig(document, panelName);

        if (!pullSide && stack) {
            stack.addChild(docContentConfig, undefined);
            stack.setActiveContentItem(stack.contentItems[stack.contentItems.length - 1]);
        } else {
            const newContentItem = () => {
                const newItem = glayRoot.layoutManager.createContentItem({ type: 'stack', content: [docContentConfig] }, instance._goldenLayout);
                newItem.callDownwards('_$init');
                return newItem;
            };
            if (glayRoot.contentItems.length === 0) {
                // if no rows / columns
                glayRoot.addChild(newContentItem());
            } else if (glayRoot.contentItems[0].isStack) {
                glayRoot.contentItems[0].addChild(docContentConfig);
            } else if (glayRoot.contentItems.length === 1 && glayRoot.contentItems[0].contentItems.length === 1 && glayRoot.contentItems[0].contentItems[0].contentItems.length === 0) {
                glayRoot.contentItems[0].contentItems[0].addChild(docContentConfig);
            } else if (instance._goldenLayout.root.contentItems[0].isRow) {
                // if row
                switch (pullSide) {
                    default:
                    case 'right':
                        glayRoot.contentItems[0].addChild(newContentItem());
                        break;
                    case 'left':
                        glayRoot.contentItems[0].addChild(newContentItem(), 0);
                        break;
                    case 'top':
                    case 'bottom':
                        // if not going in a row layout, must add already existing content into column
                        const rowlayout = glayRoot.contentItems[0];
                        const newColumn = rowlayout.layoutManager.createContentItem({ type: 'column' }, instance._goldenLayout);

                        const newItem = newContentItem();
                        instance._goldenLayout.saveScrollTops(rowlayout.element);
                        rowlayout.parent.replaceChild(rowlayout, newColumn);
                        if (pullSide === 'top') {
                            newColumn.addChild(rowlayout, undefined, true);
                            newColumn.addChild(newItem, 0, true);
                        } else if (pullSide === 'bottom') {
                            newColumn.addChild(newItem, undefined, true);
                            newColumn.addChild(rowlayout, 0, true);
                        }
                        instance._goldenLayout.restoreScrollTops(rowlayout.element);

                        rowlayout.config.height = 50;
                        newItem.config.height = 50;
                }
            } else {
                // if (instance._goldenLayout.root.contentItems[0].isColumn) { // if column
                switch (pullSide) {
                    case 'top':
                        glayRoot.contentItems[0].addChild(newContentItem(), 0);
                        break;
                    case 'bottom':
                        glayRoot.contentItems[0].addChild(newContentItem());
                        break;
                    case 'left':
                    case 'right':
                    default:
                        // if not going in a row layout, must add already existing content into column
                        const collayout = glayRoot.contentItems[0];
                        const newRow = collayout.layoutManager.createContentItem({ type: 'row' }, instance._goldenLayout);

                        const newItem = newContentItem();
                        instance._goldenLayout.saveScrollTops(collayout.element);
                        collayout.parent.replaceChild(collayout, newRow);
                        if (pullSide === 'left') {
                            newRow.addChild(collayout, undefined, true);
                            newRow.addChild(newItem, 0, true);
                        } else {
                            newRow.addChild(newItem, undefined, true);
                            newRow.addChild(collayout, 0, true);
                        }
                        instance._goldenLayout.restoreScrollTops(collayout.element);

                        collayout.config.width = 50;
                        newItem.config.width = 50;
                }
            }
            instance._ignoreStateChange = JSON.stringify(instance._goldenLayout.toConfig());
        }

        return instance.layoutChanged();
    }

    @undoBatch
    @action
    layoutChanged() {
        this._goldenLayout.root.callDownwards('setSize', [this._goldenLayout.width, this._goldenLayout.height]);
        this._goldenLayout.emit('stateChanged');
        this.stateChanged();
        return true;
    }

    setupGoldenLayout = async () => {
        const config = StrCast(this.props.Document.dockingConfig);
        if (config) {
            const matches = config.match(/\"documentId\":\"[a-z0-9-]+\"/g);
            const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) ?? [];
            await Promise.all(docids.map(id => DocServer.GetRefField(id)));

            if (this._goldenLayout) {
                if (config === JSON.stringify(this._goldenLayout.toConfig())) {
                    return;
                } else {
                    try {
                        this._goldenLayout.unbind('tabCreated', this.tabCreated);
                        this._goldenLayout.unbind('tabDestroyed', this.tabDestroyed);
                        this._goldenLayout.unbind('stackCreated', this.stackCreated);
                    } catch (e) {}
                }
                this.tabMap.clear();
                this._goldenLayout.destroy();
            }
            const glay = (this._goldenLayout = new GoldenLayout(JSON.parse(config)));
            glay.on('tabCreated', this.tabCreated);
            glay.on('tabDestroyed', this.tabDestroyed);
            glay.on('stackCreated', this.stackCreated);
            glay.registerComponent('DocumentFrameRenderer', TabDocView);
            glay.container = this._containerRef.current;
            glay.init();
            glay.root.layoutManager.on('itemDropped', this.tabItemDropped);
            glay.root.layoutManager.on('dragStart', this.tabDragStart);
            glay.root.layoutManager.on('activeContentItemChanged', this.stateChanged);
        }
    };

    componentDidMount: () => void = () => {
        if (this._containerRef.current) {
            this._lightboxReactionDisposer = reaction(
                () => LightboxView.LightboxDoc,
                doc => setTimeout(() => !doc && this.onResize(undefined))
            );
            new _global.ResizeObserver(this.onResize).observe(this._containerRef.current);
            this._reactionDisposer = reaction(
                () => StrCast(this.props.Document.dockingConfig),
                config => {
                    if (!this._goldenLayout || this._ignoreStateChange !== config) {
                        //  bcz: TODO! really need to diff config with ignoreStateChange and modify the current goldenLayout instead of building a new one.
                        this.setupGoldenLayout();
                    }
                    this._ignoreStateChange = '';
                }
            );
            setTimeout(this.setupGoldenLayout);
            //window.addEventListener('resize', this.onResize); // bcz: would rather add this event to the parent node, but resize events only come from Window
        }
    };

    componentWillUnmount: () => void = () => {
        try {
            this._goldenLayout.unbind('stackCreated', this.stackCreated);
            this._goldenLayout.unbind('tabDestroyed', this.tabDestroyed);
        } catch (e) {}
        this._goldenLayout?.destroy();
        window.removeEventListener('resize', this.onResize);

        this._reactionDisposer?.();
        this._lightboxReactionDisposer?.();
    };

    @action
    onResize = (event: any) => {
        const cur = this._containerRef.current;
        // bcz: since GoldenLayout isn't a React component itself, we need to notify it to resize when its document container's size has changed
        !LightboxView.LightboxDoc && cur && this._goldenLayout?.updateSize(cur.getBoundingClientRect().width, cur.getBoundingClientRect().height);
    };

    @action
    onPointerUp = (e: MouseEvent): void => {
        window.removeEventListener('pointerup', this.onPointerUp);
        const flush = this._flush;
        this._flush = undefined;
        if (flush) {
            DragManager.CompleteWindowDrag = undefined;
            if (!this.stateChanged()) flush.cancel();
            else flush.end();
        }
    };

    @action
    onPointerDown = (e: React.PointerEvent): void => {
        let hitFlyout = false;
        for (let par = e.target as any; !hitFlyout && par; par = par.parentElement) {
            hitFlyout = par.className === 'dockingViewButtonSelector';
        }
        if (!hitFlyout) {
            const htmlTarget = e.target as HTMLElement;
            window.addEventListener('mouseup', this.onPointerUp);
            if (!htmlTarget.closest('*.lm_content') && (htmlTarget.closest('*.lm_tab') || htmlTarget.closest('*.lm_stack'))) {
                const className = typeof htmlTarget.className === 'string' ? htmlTarget.className : '';
                if (!className.includes('lm_close') && !className.includes('lm_maximise')) {
                    this._flush = UndoManager.StartBatch('golden layout edit');
                }
            }
        }
        if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE) && !InteractionUtils.IsType(e, InteractionUtils.PENTYPE) && ![InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) {
            e.stopPropagation();
        }
    };

    public CaptureThumbnail() {
        const content = this.props.DocumentView?.()?.ContentDiv;
        if (content) {
            const _width = Number(getComputedStyle(content).width.replace('px', ''));
            const _height = Number(getComputedStyle(content).height.replace('px', ''));
            return CollectionFreeFormView.UpdateIcon(this.layoutDoc[Id] + '-icon' + new Date().getTime(), content, _width, _height, _width, _height, 0, 1, true, this.layoutDoc[Id] + '-icon', (iconFile, _nativeWidth, _nativeHeight) => {
                const img = Docs.Create.ImageDocument(new ImageField(iconFile), { title: this.rootDoc.title + '-icon', _width, _height, _nativeWidth, _nativeHeight });
                const proto = this.dataDoc; // Cast(img.proto, Doc, null)!;
                proto['thumb-nativeWidth'] = _width;
                proto['thumb-nativeHeight'] = _height;
                this.dataDoc.thumb = new ImageField(iconFile);
            });
        }
    }
    public static async TakeSnapshot(doc: Doc | undefined, clone = false) {
        if (!doc) return undefined;
        let json = StrCast(doc.dockingConfig);
        if (clone) {
            const cloned = await Doc.MakeClone(doc);
            Array.from(cloned.map.entries()).map(entry => (json = json.replace(entry[0], entry[1][Id])));
            Doc.GetProto(cloned.clone).dockingConfig = json;
            return DashboardView.openDashboard(cloned.clone);
        }
        const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
        const origtabids = matches?.map(m => m.replace('"documentId":"', '').replace('"', '')) || [];
        const origtabs = origtabids
            .map(id => DocServer.GetCachedRefField(id))
            .filter(f => f)
            .map(f => f as Doc);
        const newtabs = origtabs.map(origtab => {
            const origtabdocs = DocListCast(origtab.data);
            const newtab = origtabdocs.length ? Doc.MakeCopy(origtab, true, undefined, true) : Doc.MakeAlias(origtab);
            const newtabdocs = origtabdocs.map(origtabdoc => Doc.MakeAlias(origtabdoc));
            if (newtabdocs.length) {
                Doc.GetProto(newtab).data = new List<Doc>(newtabdocs);
                newtabdocs.forEach(ntab => (ntab.context = newtab));
            }
            json = json.replace(origtab[Id], newtab[Id]);
            return newtab;
        });
        const copy = Docs.Create.DockDocument(newtabs, json, { title: incrementTitleCopy(StrCast(doc.title)) });
        DashboardView.SetupDashboardTrails(copy);
        return DashboardView.openDashboard(copy);
    }

    @action
    stateChanged = () => {
        this._ignoreStateChange = JSON.stringify(this._goldenLayout.toConfig());
        const json = JSON.stringify(this._goldenLayout.toConfig());
        const matches = json.match(/\"documentId\":\"[a-z0-9-]+\"/g);
        const docids = matches?.map(m => m.replace('"documentId":"', '').replace('"', ''));
        const docs = !docids
            ? []
            : docids
                  .map(id => DocServer.GetCachedRefField(id))
                  .filter(f => f)
                  .map(f => f as Doc);
        const changesMade = this.props.Document.dockcingConfig !== json;
        if (changesMade && !this._flush) {
            UndoManager.RunInBatch(() => {
                this.props.Document.dockingConfig = json;
                this.props.Document.data = new List<Doc>(docs);
            }, 'state changed');
        }
        return changesMade;
    };

    tabDestroyed = (tab: any) => {
        if (![DocumentType.KVP, DocumentType.PRES].includes(tab.DashDoc?.type)) {
            Doc.AddDocToList(Doc.MyHeaderBar, 'data', tab.DashDoc);
            Doc.AddDocToList(Doc.MyRecentlyClosed, 'data', tab.DashDoc, undefined, true, true);
        }
        if (CollectionDockingView.Instance) {
            const dview = CollectionDockingView.Instance.props.Document;
            const fieldKey = CollectionDockingView.Instance.props.fieldKey;
            Doc.RemoveDocFromList(dview, fieldKey, tab.DashDoc);
            this.tabMap.delete(tab);
            tab._disposers && Object.values(tab._disposers).forEach((disposer: any) => disposer?.());
            tab.reactComponents?.forEach((ele: any) => ReactDOM.unmountComponentAtNode(ele));
            setTimeout(this.stateChanged);
        }
    };
    tabCreated = (tab: any) => {
        this.tabMap.add(tab);
        tab.contentItem.element[0]?.firstChild?.firstChild?.InitTab?.(tab); // have to explicitly initialize tabs that reuse contents from previous tabs (ie, when dragging a tab around a new tab is created for the old content)
    };

    stackCreated = (stack: any) => {
        stack.header?.element.on('mousedown', (e: any) => {
            const dashboard = Doc.ActiveDashboard;
            if (dashboard && e.target === stack.header?.element[0] && e.button === 2) {
                dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1;
                const docToAdd = Docs.Create.FreeformDocument([], {
                    _width: this.props.PanelWidth(),
                    _height: this.props.PanelHeight(),
                    _backgroundGridShow: true,
                    _fitWidth: true,
                    title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
                });
                this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
                CollectionDockingView.AddSplit(docToAdd, '', stack);
            }
        });

        stack.header?.controlsContainer
            .find('.lm_close') //get the close icon
            .off('click') //unbind the current click handler
            .click(
                action(() => {
                    //if (confirm('really close this?')) {
                    if (!stack.parent.parent.isRoot || stack.parent.contentItems.length > 1) {
                        stack.remove();
                    } else {
                        alert('cant delete the last stack');
                    }
                })
            );

        stack.header?.controlsContainer
            .find('.lm_maximise') //get the close icon
            .click(() => setTimeout(this.stateChanged));
        stack.header?.controlsContainer
            .find('.lm_popout') //get the popout icon
            .off('click') //unbind the current click handler
            .click(
                action(() => {
                    // stack.config.fixed = !stack.config.fixed;  // force the stack to have a fixed size
                    const dashboard = Doc.ActiveDashboard;
                    if (dashboard) {
                        dashboard['pane-count'] = NumCast(dashboard['pane-count']) + 1;
                        const docToAdd = Docs.Create.FreeformDocument([], {
                            _width: this.props.PanelWidth(),
                            _height: this.props.PanelHeight(),
                            _fitWidth: true,
                            _backgroundGridShow: true,
                            title: `Untitled Tab ${NumCast(dashboard['pane-count'])}`,
                        });
                        this.props.Document.isShared && inheritParentAcls(this.props.Document, docToAdd);
                        CollectionDockingView.AddSplit(docToAdd, '', stack);
                    }
                })
            );
    };

    render() {
        const href = ImageCast(this.rootDoc.thumb)?.url.href;
        return this.props.renderDepth > -1 ? (
            <div>
                {href ? (
                    <img
                        style={{ background: 'white', top: 0, position: 'absolute' }}
                        src={href} // + '?d=' + (new Date()).getTime()}
                        width={this.props.PanelWidth()}
                        height={this.props.PanelHeight()}
                    />
                ) : (
                    <p>nested dashboards has no thumbnail</p>
                )}
            </div>
        ) : (
            <div className="collectiondockingview-container" onPointerDown={this.onPointerDown} ref={this._containerRef} />
        );
    }
}

ScriptingGlobals.add(
    function openInLightbox(doc: any) {
        LightboxView.AddDocTab(doc, 'lightbox');
    },
    'opens up document in a lightbox',
    '(doc: any)'
);
ScriptingGlobals.add(
    function openOnRight(doc: any) {
        return CollectionDockingView.AddSplit(doc, 'right');
    },
    'opens up document in tab on right side of the screen',
    '(doc: any)'
);
ScriptingGlobals.add(
    function openInOverlay(doc: any) {
        return Doc.AddDocToList(Doc.MyOverlayDocs, undefined, doc);
    },
    'opens up document in screen overlay layer',
    '(doc: any)'
);
ScriptingGlobals.add(function useRightSplit(doc: any, shiftKey?: boolean) {
    CollectionDockingView.ReplaceTab(doc, 'right', undefined, shiftKey);
});
