// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { $ } from 'chrome://resources/js/util.js';
import { addNode, addNodeWithText, setNodeDisplay, setNodePosition } from './util.js';
import { View } from './view.js';
const TAB_LIST_ID = 'tab-list';
/** @type {?TabSwitcherView} */
let instance = null;
/**
 * Controller and View for switching between tabs.
 *
 * The View part of TabSwitcherView displays the contents of the currently
 * selected tab (only one tab can be active at a time).
 *
 * The controller part of TabSwitcherView hooks up a dropdown menu (i.e. HTML
 * SELECT) to control switching between tabs.
 */
export class TabSwitcherView extends View {
    constructor() {
        super();
        this.tabIdToView_ = {};
        this.tabIdToLink_ = {};
        // Map from tab id to the views link visiblity.
        this.tabIdsLinkVisibility_ = new Map();
        this.activeTabId_ = null;
        this.onTabSwitched_ = null;
        // The ideal width of the tab list.  If width is reduced below this, the
        // tab list will be shrunk, but it will be returned to this width once it
        // can be.
        this.tabListWidth_ = $(TAB_LIST_ID).offsetWidth;
    }
    /**
     * @param {!Function} onTabSwitched Callback to run when the
     *                    active tab changes. Called as
     *                    onTabSwitched(oldTabId, newTabId).
     */
    setOnTabSwitched(onTabSwitched) {
        this.onTabSwitched_ = onTabSwitched;
    }
    // ---------------------------------------------
    // Override methods in View
    // ---------------------------------------------
    setGeometry(left, top, width, height) {
        super.setGeometry(this, left, top, width, height);
        const tabListNode = $(TAB_LIST_ID);
        // Set position of the tab list.  Can't use DivView because DivView sets
        // a fixed width at creation time, and need to set the width of the tab
        // list only after its been populated.
        let tabListWidth = this.tabListWidth_;
        if (tabListWidth > width) {
            tabListWidth = width;
        }
        tabListNode.style.position = 'absolute';
        setNodePosition(tabListNode, left, top, tabListWidth, height);
        // Position each of the tab's content areas.
        for (const tabId in this.tabIdToView_) {
            const view = this.tabIdToView_[tabId];
            view.setGeometry(left + tabListWidth, top, width - tabListWidth, height);
        }
    }
    show(isVisible) {
        super.show(isVisible);
        const activeView = this.getActiveTabView();
        if (activeView) {
            activeView.show(isVisible);
        }
    }
    // ---------------------------------------------
    /**
     * Adds a new tab (initially hidden).  To ensure correct tab list sizing,
     * may only be called before first layout.
     *
     * @param {string} tabId The ID to refer to the tab by.
     * @param {!View} view The tab's actual contents.
     * @param {string} name The name for the menu item that selects the tab.
     */
    addTab(tabId, view, name, hash) {
        if (!tabId) {
            throw Error('Must specify a non-false tabId');
        }
        this.tabIdToView_[tabId] = view;
        this.tabIdsLinkVisibility_.set(tabId, true);
        const node = addNodeWithText($(TAB_LIST_ID), 'a', name);
        node.href = hash;
        this.tabIdToLink_[tabId] = node;
        addNode($(TAB_LIST_ID), 'br');
        // Tab content views start off hidden.
        view.show(false);
        this.tabListWidth_ = $(TAB_LIST_ID).offsetWidth;
    }
    getAllTabViews() {
        return this.tabIdToView_;
    }
    getTabView(tabId) {
        return this.tabIdToView_[tabId];
    }
    getActiveTabView() {
        return this.tabIdToView_[this.activeTabId_];
    }
    getActiveTabId() {
        return this.activeTabId_;
    }
    /**
     * Changes the currently active tab to |tabId|. This has several effects:
     *   (1) Replace the tab contents view with that of the new tab.
     *   (2) Update the dropdown menu's current selection.
     *   (3) Invoke the optional onTabSwitched callback.
     */
    switchToTab(tabId) {
        const newView = this.getTabView(tabId);
        if (!newView) {
            throw Error('Invalid tabId');
        }
        const oldTabId = this.activeTabId_;
        this.activeTabId_ = tabId;
        if (oldTabId) {
            this.tabIdToLink_[oldTabId].classList.remove('selected');
            // Hide the previously visible tab contents.
            this.getTabView(oldTabId).show(false);
        }
        this.tabIdToLink_[tabId].classList.add('selected');
        newView.show(this.isVisible());
        if (this.onTabSwitched_) {
            this.onTabSwitched_(oldTabId, tabId);
        }
    }
    static getInstance() {
        return instance || (instance = new TabSwitcherView());
    }
}
