// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_VIEWS_TABS_TAB_CONTAINER_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_CONTAINER_H_

#include <memory>
#include <vector>

#include "chrome/browser/ui/views/frame/browser_root_view.h"
#include "chrome/browser/ui/views/tabs/tab.h"
#include "chrome/browser/ui/views/tabs/tab_group_underline.h"
#include "chrome/browser/ui/views/tabs/tab_group_views.h"
#include "chrome/browser/ui/views/tabs/tab_slot_controller.h"
#include "chrome/browser/ui/views/tabs/tab_slot_view.h"
#include "chrome/browser/ui/views/tabs/z_orderable_tab_container_element.h"
#include "components/tab_groups/tab_group_id.h"
#include "components/tab_groups/tab_group_visual_data.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/views/animation/bounds_animator.h"
#include "ui/views/view.h"
#include "ui/views/view_model.h"

class TabStrip;

// A View that contains a sequence of Tabs for the TabStrip.

// As a BrowserRootView::DropTarget, this can handle drag & drop sessions on
// behalf of BrowserRootView.

// This interface exists only for use by TabContainerImpl and
// CompoundTabContainer as described in go/2-tabcontainers-1-pager. Reuse is
// strongly discouraged outside of that context, as the interface will likely go
// away after that project is completed.
class TabContainer : public views::View, public BrowserRootView::DropTarget {
  METADATA_HEADER(TabContainer, views::View)

 public:
  struct TabInsertionParams {
    std::unique_ptr<Tab> tab;
    int model_index;
    TabPinned pinned;

    TabInsertionParams(std::unique_ptr<Tab> tab, int index, TabPinned pinned);
    ~TabInsertionParams();
    TabInsertionParams(TabInsertionParams&& other) noexcept;
    TabInsertionParams& operator=(TabInsertionParams&& other) noexcept;

    TabInsertionParams(const TabInsertionParams&) = delete;
    TabInsertionParams& operator=(const TabInsertionParams&) = delete;
  };

  // This callback is used when calculating animation targets that may increase
  // the width of the tabstrip.
  virtual void SetAvailableWidthCallback(
      base::RepeatingCallback<int()> available_width_callback) = 0;

  // Handle model changes.
  virtual std::vector<Tab*> AddTabs(
      std::vector<TabInsertionParams> tabs_params) = 0;
  virtual void MoveTab(int from_model_index, int to_model_index) = 0;
  virtual void RemoveTab(int index, bool was_active) = 0;
  virtual void SetTabPinned(int model_index, TabPinned pinned) = 0;
  // Changes the active tab from `prev_active_index` to `new_active_index`.
  virtual void SetActiveTab(std::optional<size_t> prev_active_index,
                            std::optional<size_t> new_active_index) = 0;

  // Removes the tab at `model_index` from the TabContainer's data structures so
  // it can be reparented elsewhere. Unlike RemoveTab, it does not animate the
  // tab closed and it does not destroy the tab, so it should be used only to
  // transfer the tab to another parent and not to close the tab.
  [[nodiscard]] virtual Tab* RemoveTabFromViewModel(int model_index) = 0;

  // Adds the tab to the TabContainer's data structures, but does not transfer
  // ownership of the actual view `tab`.
  virtual Tab* AddTabToViewModel(Tab* tab,
                                 int model_index,
                                 TabPinned pinned) = 0;

  // Returns `view` to this TabContainer in the view hierarchy. N.B. this
  // may be called during `view`'s destruction.
  virtual void ReturnTabSlotView(TabSlotView* view) = 0;

  // Handle tab group model changes.
  virtual void OnGroupCreated(const tab_groups::TabGroupId& group) = 0;
  // Opens the editor bubble for the tab `group` as a result of an explicit user
  // action to create the `group`.
  virtual void OnGroupEditorOpened(const tab_groups::TabGroupId& group) = 0;
  virtual void OnGroupMoved(const tab_groups::TabGroupId& group) = 0;
  virtual void OnGroupContentsChanged(const tab_groups::TabGroupId& group) = 0;
  virtual void OnGroupVisualsChanged(
      const tab_groups::TabGroupId& group,
      const tab_groups::TabGroupVisualData* old_visuals,
      const tab_groups::TabGroupVisualData* new_visuals) = 0;
  virtual void ToggleTabGroup(const tab_groups::TabGroupId& group,
                              bool is_collapsing,
                              ToggleTabGroupCollapsedStateOrigin origin) = 0;
  virtual void OnGroupClosed(const tab_groups::TabGroupId& group) = 0;
  virtual void UpdateTabGroupVisuals(tab_groups::TabGroupId group_id) = 0;
  virtual void NotifyTabstripBubbleOpened() = 0;
  virtual void NotifyTabstripBubbleClosed() = 0;

  virtual void OnSplitCreated(const std::vector<int>& indices) = 0;
  virtual void OnSplitRemoved(const std::vector<int>& indices) = 0;
  virtual void OnSplitContentsChanged(const std::vector<int>& indices) = 0;

  virtual std::optional<int> GetModelIndexOf(
      const TabSlotView* slot_view) const = 0;
  virtual Tab* GetTabAtModelIndex(int index) const = 0;
  virtual int GetTabCount() const = 0;

  // Returns the model index of the first tab after (or including) `tab` which
  // is not closing.
  virtual std::optional<int> GetModelIndexOfFirstNonClosingTab(
      Tab* tab) const = 0;

  virtual void UpdateHoverCard(
      HoverCardAnchorTarget* anchor_target,
      TabSlotController::HoverCardUpdateType update_type) = 0;

  virtual void HandleLongTap(ui::GestureEvent* event) = 0;

  virtual bool IsRectInContentArea(const gfx::Rect& rect) = 0;

  virtual std::optional<ZOrderableTabContainerElement>
  GetLeadingElementForZOrdering() const = 0;
  virtual std::optional<ZOrderableTabContainerElement>
  GetTrailingElementForZOrdering() const = 0;

  // Animation stuff. Will be public until fully moved down into TabContainer.

  // Called whenever a tab or group header animation has progressed.
  virtual void OnTabSlotAnimationProgressed(TabSlotView* view) = 0;

  // Called whenever a tab close animation has completed. This kills the `tab`.
  virtual void OnTabCloseAnimationCompleted(Tab* tab) = 0;

  // Force recalculation of ideal bounds at the next layout. Used to cause tabs
  // to animate to their ideal bounds after somebody other than TabContainer
  // (cough TabDragController cough) moves tabs directly.
  virtual void InvalidateIdealBounds() = 0;

  // Animates tabs and group views from where they are to where they should be.
  // Callers that want to do fancier things can manipulate starting bounds
  // before calling this and/or replace the animation for some tabs or group
  // views after calling this.
  virtual void AnimateToIdealBounds() = 0;

  // Returns true if any tabs are being animated by this TabContainer.
  virtual bool IsAnimating() const = 0;

  // Stops any ongoing animations, leaving tabs where they are.
  virtual void CancelAnimation() = 0;

  // Stops any ongoing animations and forces a layout.
  virtual void CompleteAnimationAndLayout() = 0;

  // Returns the total width available for the TabContainer's use.
  virtual int GetAvailableWidthForTabContainer() const = 0;

  // See `in_tab_close_` for details on tab closing mode. `source` is the input
  // method used to enter tab closing mode, which determines how it is exited
  // due to user inactivity.
  virtual void EnterTabClosingMode(std::optional<int> override_width,
                                   CloseTabSource source) = 0;
  virtual void ExitTabClosingMode() = 0;

  // Sets the visibility state of all tabs and group headers (if any) based on
  // ShouldTabBeVisible().
  virtual void SetTabSlotVisibility() = 0;

  virtual bool InTabClose() = 0;

  // Returns the TabGroupViews associated with the group `group_id`.
  virtual TabGroupViews* GetGroupViews(
      tab_groups::TabGroupId group_id) const = 0;
  virtual const std::map<tab_groups::TabGroupId,
                         std::unique_ptr<TabGroupViews>>&
  get_group_views_for_testing() const = 0;
  virtual std::map<tab_groups::TabGroupId, TabGroupHeader*> GetGroupHeaders()
      const = 0;

  // Returns ideal bounds for the tab at `model_index` in this TabContainer's
  // coordinate space.
  virtual gfx::Rect GetIdealBounds(int model_index) const = 0;

  // Returns ideal bounds for the group header associated with `group` in this
  // TabContainer's coordinate space.
  virtual gfx::Rect GetIdealBounds(tab_groups::TabGroupId group) const = 0;
};

#endif  // CHROME_BROWSER_UI_VIEWS_TABS_TAB_CONTAINER_H_
