// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * 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.
 */
var TabSwitcherView = (function() {
  'use strict';

  // We inherit from View.
  var superClass = View;

  /**
   * @constructor
   *
   * @param {DOMSelectNode} dropdownMenu The menu for switching between tabs.
   *                        The TabSwitcherView will attach an onchange event to
   *                        the dropdown menu, and control the selected index.
   * @param {?Function} opt_onTabSwitched Optional callback to run when the
   *                    active tab changes. Called as
   *                    opt_onTabSwitched(oldTabId, newTabId).
   */
  function TabSwitcherView(dropdownMenu, opt_onTabSwitched) {
    assertFirstConstructorCall(TabSwitcherView);

    this.tabIdToView_ = {};
    this.activeTabId_ = null;

    this.dropdownMenu_ = dropdownMenu;
    this.dropdownMenu_.onchange = this.onMenuSelectionChanged_.bind(this);

    this.onTabSwitched_ = opt_onTabSwitched;

    superClass.call(this);
  }

  TabSwitcherView.prototype = {
    // Inherit the superclass's methods.
    __proto__: superClass.prototype,

    // ---------------------------------------------
    // Override methods in View
    // ---------------------------------------------

    setGeometry: function(left, top, width, height) {
      superClass.prototype.setGeometry.call(this, left, top, width, height);

      // Position each of the tabs content areas.
      for (var tabId in this.tabIdToView_) {
        var view = this.tabIdToView_[tabId];
        view.setGeometry(left, top, width, height);
      }
    },

    show: function(isVisible) {
      superClass.prototype.show.call(this, isVisible);
      var activeView = this.getActiveTabView();
      if (activeView)
        activeView.show(isVisible);
    },

    // ---------------------------------------------

    /**
     * Adds a new tab (initially hidden).
     *
     * @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: function(tabId, view, name) {
      if (!tabId) {
        throw Error('Must specify a non-false tabId');
      }

      this.tabIdToView_[tabId] = view;

      // Tab content views start off hidden.
      view.show(false);

      // Add it to the dropdown menu.
      var menuItem = addNode(this.dropdownMenu_, 'option');
      menuItem.value = tabId;
      menuItem.textContent = name;
    },

    showMenuItem: function(tabId, isVisible) {
      var wasActive = this.activeTabId_ == tabId;

      // Hide the menuitem from the list. Note it needs to be 'disabled' to
      // prevent it being selectable from keyboard.
      var menuitem = this.getMenuItemNode_(tabId);
      setNodeDisplay(menuitem, isVisible);
      menuitem.disabled = !isVisible;

      if (wasActive && !isVisible) {
        // If the active tab is being hidden in the dropdown menu, then
        // switch to the first tab which is still visible.
        for (var i = 0; i < this.dropdownMenu_.options.length; ++i) {
          var option = this.dropdownMenu_.options[i];
          if (option.style.display != 'none') {
            this.switchToTab(option.value);
            break;
          }
        }
      }
    },

    getAllTabViews: function() {
      return this.tabIdToView_;
    },

    getTabView: function(tabId) {
      return this.tabIdToView_[tabId];
    },

    getActiveTabView: function() {
      return this.tabIdToView_[this.activeTabId_];
    },

    getActiveTabId: function() {
      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: function(tabId) {
      var newView = this.getTabView(tabId);

      if (!newView) {
        throw Error('Invalid tabId');
      }

      var oldTabId = this.activeTabId_;
      this.activeTabId_ = tabId;

      this.dropdownMenu_.value = tabId;

      // Hide the previously visible tab contents.
      if (oldTabId)
        this.getTabView(oldTabId).show(false);

      newView.show(this.isVisible());

      if (this.onTabSwitched_)
        this.onTabSwitched_(oldTabId, tabId);
    },

    getMenuItemNode_: function(tabId) {
      for (var i = 0; i < this.dropdownMenu_.options.length; ++i) {
        var option = this.dropdownMenu_.options[i];
        if (option.value == tabId) {
          return option;
        }
      }
      return null;
    },

    onMenuSelectionChanged_: function(event) {
      var tabId = this.dropdownMenu_.value;
      this.switchToTab(tabId);
    },
  };

  return TabSwitcherView;
})();