/**
 * @author Martin Karkowski
 * @email m.karkowski@zema.de
 * @create date 2019-02-20 09:19:06
 * @modify date 2020-10-29 09:55:30
 * @desc [description]
 * 
 * A Basic Layout.
 * I uses a Toolbar, Sidebar
 * 
 * Toast are implemented by https://fkhadra.github.io/react-toastify/introduction
 */

import { type } from 'os';
import React from 'react';
import { Nav } from 'react-bootstrap';
import { FaTimesCircle } from 'react-icons/fa';
import { ITab } from './interfaces/ITab';
import { ITabEntry } from './interfaces/ITabEntry';


export interface ITabProps {
    onMount?: (item: ITabEntry) => void,
    onNewTab?: () => Promise<ITab | false>;
    onTabSelect?: (oldTabId: ITab, newTabId: ITab) => Promise<boolean>;
    onTabEdit?: (tab: ITab) => Promise<ITab>;
    onTabDelete?: (tabId: ITab, forced?: boolean) => Promise<boolean>;
    onNoTabSelected?: () => Promise<void>;
    tabs: {
        allowNewTabs?: boolean;
        active: string,
        items: ITab[]
    }
}

class TabEntry extends React.Component<ITabProps, ITabProps> implements ITabEntry {


    protected _handleResize: () => void;

    public hotkeysEnabled = true;
    public pressedKey: string = null;
    public currentMousePosition: MouseEvent;

    constructor(props) {
        super(props);
        this.state = Object.assign({}, this.props);
    }

    /**
     * Function will be called if the Item has been rendered sucessfully.
     */
    componentDidMount() {

        const _this = this;

        if (typeof _this.state.onMount === 'function') {
            _this.state.onMount(_this);
        }
    }


    public get selectedTab() {
        for (const tab of this.state.tabs.items) {
            if (tab.id === this.state.tabs.active) {
                return tab;
            }
        }

        return null;
    }

    public async requestTab() {
        if (typeof this.state.onNewTab === 'function') {
            const tab = await this.state.onNewTab();

            if (tab && typeof tab === 'object') {
                this.state.tabs.items.push(tab);

                this.selectTab(tab);
            }
        }
    }

    public async createTab(tab: ITab) {
        const tabs = this.tabs;
        tabs.push(tab);
        this.tabs = tabs;
    }

    public get tabs(): ITab[] {
        return this.state.tabs?.items || [];
    }

    public set tabs(value: ITab[]) {
        this.setState({
            tabs: {
                active: this.activeTab,
                items: value,
                allowNewTabs: this.state.tabs.allowNewTabs
            }
        })
    }

    public get activeTab(): string {
        return this.state.tabs.active;
    }

    public set activeTab(value: string) {
        this.setState({
            tabs: {
                active: value,
                items: this.props.tabs.items,
                allowNewTabs: this.props.tabs.allowNewTabs
            }
        })
    }

    /**
     * Function to Select a Tab
     * @param tab 
     */
    public async selectTab(tab: ITab | string) {
        let newTabToDisplay: ITab;

        if (typeof tab === "string") {
            for (const _t of this.tabs) {
                if (_t.id === tab) {
                    newTabToDisplay = _t;
                    break;
                }
            }
        } else {
            newTabToDisplay = tab;
        }

        if (typeof this.state.onTabSelect === 'function') {

            const currentlySelected = this.selectedTab;

            // Call the Async Function to select a Tab.
            if (await this.state.onTabSelect(currentlySelected, newTabToDisplay)) {

                this.activeTab = newTabToDisplay.id;

                return true;
            }

            return false;
        } else {
            // Assign the Tab ID
            this.activeTab = newTabToDisplay.id;

            return true;
        }
    }

    public async editTab(tab: ITab | string) {
        let tabToEdit: ITab;
        let idx = -1;

        const tabs = this.tabs;

        for (const [_idx, _tab] of this.tabs.entries()) {
            if (_tab.id === (typeof tab === 'string' ? tab : tab.id)) {
                tabToEdit = _tab;
                idx = _idx;
                break;
            }
        }

        if (tabToEdit && typeof this.state.onTabEdit === 'function') {

            const editedTab = await this.state.onTabEdit(tabToEdit);
            tabs[idx] = editedTab;

            this.tabs = tabs;
        } 
    }

    public async delteTab(tab: ITab | string, forced = false) {

        let idx: number = -1;
        let _tab: ITab = null;

        const tabs = this.state.tabs.items;

        for (const [_idx, _t] of tabs.entries()) {
            if (_t.id === (typeof tab === 'string' ? tab : tab.id)) {
                idx = _idx;
                _tab = _t;
                break;
            }
        }

        if (_tab != null) {
            let removed = false;
            if (typeof this.state.onTabDelete === 'function') {
                // Call the Async Function to select a Tab.
                if (await this.state.onTabDelete(_tab, forced)) {
                    removed = true;
                }
            } else {
                removed = true;
            }

            if (removed) {
                // Remove the Items.
                tabs.splice(idx, 1);

                // Check if the active element has been removed:
                if (_tab.id == this.state.tabs.active) {

                    // Assign the ID of the Element.
                    const _idx = tabs.length > idx ? idx : tabs.length - 1;

                    if (_idx !== -1) {
                        // Assign the First ID.
                        const _newTab = tabs.length > _idx ? tabs[_idx] : null;

                        if (_newTab !== null) {
                            if (!await this.selectTab(_newTab) && typeof this.state.onNoTabSelected === 'function') {
                                // Send a Warning, that no Tabs has been selected
                                await this.state.onNoTabSelected();
                            }
                        } else if (typeof this.state.onNoTabSelected === 'function') {
                            // Send a Warning, that no Tabs has been selected
                            await this.state.onNoTabSelected();
                        }
                    } else if (typeof this.state.onNoTabSelected === 'function') {
                        // Send a Warning, that no Tabs has been selected
                        await this.state.onNoTabSelected();
                    }
                }
                this.tabs = tabs;
            }
        }
    }

    public render() {
        return (<>
            <Nav variant="tabs" activeKey={this.state.tabs.active} justify>
                {this.state.tabs.items.map((tab, idx) => {
                    if (tab.delteable && this.state.tabs.allowNewTabs) {
                        return (
                            <Nav.Item key={tab.id} onDoubleClick={_=> this.editTab(tab)}>
                                <Nav.Link onSelect={_ => {
                                    this.selectTab(tab);
                                }} eventKey={tab.id}>{tab.label + ' '}
                                    <FaTimesCircle onClick={
                                        (e) => {
                                            e.preventDefault();
                                            e.stopPropagation();

                                            this.delteTab(tab);
                                        }
                                    } ></FaTimesCircle>
                                </Nav.Link>
                            </Nav.Item>
                        );
                    } else {
                        return (
                            <Nav.Item key={tab.id}>
                                <Nav.Link onSelect={_ => {
                                    this.selectTab(tab);
                                }} eventKey={tab.id}>{tab.label}</Nav.Link>
                            </Nav.Item>
                        );
                    }
                })}

                {this.state.tabs.allowNewTabs ?
                    <Nav.Item>
                        <Nav.Link eventKey='_NEW_ITEM' onSelect={_ => this.requestTab()}>
                            +
                                </Nav.Link>
                    </Nav.Item> : ''
                }
            </Nav>
        </>);
    }
}

export default TabEntry;