#ifndef DockAreaWidgetH
#define DockAreaWidgetH
/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   DockAreaWidget.h
/// \author Uwe Kindler
/// \date   24.02.2017
/// \brief  Declaration of CDockAreaWidget class
//============================================================================


//============================================================================
//                                   INCLUDES
//============================================================================
#include <QFrame>

#include "ads_globals.h"
#include "AutoHideTab.h"
#include "DockWidget.h"

QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter)
QT_FORWARD_DECLARE_CLASS(QAbstractButton)

namespace ads
{
struct DockAreaWidgetPrivate;
class CDockManager;
class CDockContainerWidget;
class DockContainerWidgetPrivate;
class CDockAreaTitleBar;
class CDockingStateReader;
class CDockSplitter;


/**
 * DockAreaWidget manages multiple instances of DockWidgets.
 * It displays a title tab, which is clickable and will switch to
 * the contents associated to the title when clicked.
 */
class ADS_EXPORT CDockAreaWidget : public QFrame
{
	Q_OBJECT
private:
	DockAreaWidgetPrivate* d; ///< private data (pimpl)
	friend struct DockAreaWidgetPrivate;
	friend class CDockContainerWidget;
	friend class DockContainerWidgetPrivate;
	friend class CDockWidgetTab;
	friend struct DockWidgetPrivate;
	friend class CDockWidget;
	friend struct DockManagerPrivate;
	friend class CDockManager;
	friend class CAutoHideDockContainer;
	void onDockWidgetFeaturesChanged();

private Q_SLOTS:
	void onTabCloseRequested(int Index);

	/**
	 * Reorder the index position of DockWidget at fromIndx to toIndex
	 * if a tab in the tabbar is dragged from one index to another one
	 */
	void reorderDockWidget(int fromIndex, int toIndex);

	/*
	 * Update the auto hide button checked state based on if it's contained in an auto hide container or not
	 */
	void updateAutoHideButtonCheckState();

	/*
	 * Update the title bar button tooltips
	 */
	void updateTitleBarButtonsToolTips();

	/**
	 * Calculate the auto hide side bar location depending on the dock area
	 * widget position in the container
	 */
	SideBarLocation calculateSideTabBarArea() const;

protected:

#ifdef Q_OS_WIN
	/**
	 * Reimplements QWidget::event to handle QEvent::PlatformSurface
	 * This is here to fix issue #294 Tab refresh problem with a QGLWidget
	 * that exists since Qt version 5.12.7. So this function is here to
	 * work around a Qt issue.
	 */
	virtual bool event(QEvent *event) override;
#endif

	/**
	 * Inserts a dock widget into dock area.
	 * All dockwidgets in the dock area tabified in a stacked layout with tabs.
	 * The index indicates the index of the new dockwidget in the tabbar and
	 * in the stacked layout. If the Activate parameter is true, the new
	 * DockWidget will be the active one in the stacked layout
	 */
	void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true);

	/**
	 * Add a new dock widget to dock area.
	 * All dockwidgets in the dock area tabified in a stacked layout with tabs
	 */
	void addDockWidget(CDockWidget* DockWidget);

	/**
	 * Removes the given dock widget from the dock area
	 */
	void removeDockWidget(CDockWidget* DockWidget);

	/**
	 * Called from dock widget if it is opened or closed
	 */
	void toggleDockWidgetView(CDockWidget* DockWidget, bool Open);

	/**
	 * This is a helper function to get the next open dock widget to activate
	 * if the given DockWidget will be closed or removed.
	 * The function returns the next widget that should be activated or
	 * nullptr in case there are no more open widgets in this area.
	 */
	CDockWidget* nextOpenDockWidget(CDockWidget* DockWidget) const;

	/**
	 * Returns the index of the given DockWidget in the internal layout
	 */
	int index(CDockWidget* DockWidget);

	/**
	 * Call this function, if you already know, that the dock does not
	 * contain any visible content (any open dock widgets).
	 */
	void hideAreaWithNoVisibleContent();

	/**
	 * Updates the dock area layout and components visibility
	 */
	void updateTitleBarVisibility();

	/**
	 * This is the internal private function for setting the current widget.
	 * This function is called by the public setCurrentDockWidget() function
	 * and by the dock manager when restoring the state
	 */
	void internalSetCurrentDockWidget(CDockWidget* DockWidget);

	/**
	 * Marks tabs menu to update
	 */
	void markTitleBarMenuOutdated();

	/*
	 * Update the title bar button visibility based on if it's top level or not
	 */
	void updateTitleBarButtonVisibility(bool IsTopLevel) const;

protected Q_SLOTS:
	void toggleView(bool Open);

public:
	using Super = QFrame;

	/**
	 * Dock area related flags
	 */
	enum eDockAreaFlag
	{
		HideSingleWidgetTitleBar = 0x0001,
		DefaultFlags = 0x0000
	};
	Q_DECLARE_FLAGS(DockAreaFlags, eDockAreaFlag)

    /**
	 * Default Constructor
	 */
	CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent);

	/**
	 * Virtual Destructor
	 */
	virtual ~CDockAreaWidget();

	/**
	 * Returns the dock manager object this dock area belongs to
	 */
	CDockManager* dockManager() const;

	/**
	 * Returns the dock container widget this dock area widget belongs to or 0
	 * if there is no
	 */
	CDockContainerWidget* dockContainer() const;

	/**
	 * Returns the auto hide dock container widget this dock area widget belongs to or 0
	 * if there is no
	 */
	CAutoHideDockContainer* autoHideDockContainer() const; 

	/**
	 * Returns the parent splitter that contains this dock area
	 */
	CDockSplitter* parentSplitter() const;

	/**
	 * Returns true if the dock area is in an auto hide container
	 */
	bool isAutoHide() const;

	/**
	 * Sets the current auto hide dock container
	 */
	void setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer);

    /**
     * Returns the largest minimumSizeHint() of the dock widgets in this
     * area.
     * The minimum size hint is updated if a dock widget is removed or added.
     */
    virtual QSize minimumSizeHint() const override;

	/**
	 * Returns the rectangle of the title area
	 */
	QRect titleBarGeometry() const;

	/**
	 * Returns the rectangle of the content
	 */
	QRect contentAreaGeometry() const;

	/**
	 * Returns the number of dock widgets in this area
	 */
	int dockWidgetsCount() const;

	/**
	 * Returns a list of all dock widgets in this dock area.
	 * This list contains open and closed dock widgets.
	 */
	QList<CDockWidget*> dockWidgets() const;

	/**
	 * Returns the number of open dock widgets in this area
	 */
	int openDockWidgetsCount() const;

	/**
	 * Returns a list of dock widgets that are not closed.
	 */
	QList<CDockWidget*> openedDockWidgets() const;

	/**
	 * Returns a dock widget by its index
	 */
	CDockWidget* dockWidget(int Index) const;

	/**
	 * Returns the index of the current active dock widget or -1 if there
	 * are is no active dock widget (ie.e if all dock widgets are closed)
	 */
	int currentIndex() const;

	/**
	 * Returns the index of the first open dock widgets in the list of
	 * dock widgets.
	 * This function is here for performance reasons. Normally it would
	 * be possible to take the first dock widget from the list returned by
	 * openedDockWidgets() function. But that function enumerates all
	 * dock widgets while this functions stops after the first open dock widget.
	 * If there are no open dock widgets, the function returns -1.
	 */
	int indexOfFirstOpenDockWidget() const;

	/**
	 * Returns the current active dock widget or a nullptr if there is no
	 * active dock widget (i.e. if all dock widgets are closed)
	 */
	CDockWidget* currentDockWidget() const;

	/**
	 * Shows the tab with the given dock widget
	 */
	void setCurrentDockWidget(CDockWidget* DockWidget);

	/**
	 * Saves the state into the given stream
	 */
	void saveState(QXmlStreamWriter& Stream) const;

    /**
	 * Restores a dock area.
	 * \see restoreChildNodes() for details
	 */
    static bool restoreState(CDockingStateReader& Stream, CDockAreaWidget*& CreatedWidget,
		bool Testing, CDockContainerWidget* ParentContainer);

	/**
	 * This functions returns the dock widget features of all dock widget in
	 * this area.
	 * A bitwise and is used to combine the flags of all dock widgets. That
	 * means, if only one single dock widget does not support a certain flag,
	 * the whole dock are does not support the flag. I.e. if one single
	 * dock widget in this area is not closable, the whole dock are is not
	 * closable.
	 */
	CDockWidget::DockWidgetFeatures features(eBitwiseOperator Mode = BitwiseAnd) const;

	/**
	 * Returns the title bar button corresponding to the given title bar
	 * button identifier
	 */
	QAbstractButton* titleBarButton(TitleBarButton which) const;

	/**
	 * Update the close button if visibility changed
	 */
	virtual void setVisible(bool Visible) override;

	/**
	 * Configures the areas of this particular dock area that are allowed for docking
	 */
	void setAllowedAreas(DockWidgetAreas areas);

	/**
	 * Returns flags with all allowed drop areas of this particular dock area
	 */
	DockWidgetAreas allowedAreas() const;

	/**
	 * Returns the title bar of this dock area
	 */
	CDockAreaTitleBar* titleBar() const;

	/**
	 * Returns the dock area flags - a combination of flags that configure the
	 * appearance and features of the dock area.
	 * \see setDockAreaFlasg()
	 */
	DockAreaFlags dockAreaFlags() const;

	/**
	 * Sets the dock area flags - a combination of flags that configure the
	 * appearance and features of the dock area
	 */
	void setDockAreaFlags(DockAreaFlags Flags);

	/**
	 * Sets the dock area flag Flag on this widget if on is true; otherwise
	 * clears the flag.
	 */
	void setDockAreaFlag(eDockAreaFlag Flag, bool On);

    /**
     * Returns true if the area has a single dock widget and contains the central widget of it's manager.
     */
    bool isCentralWidgetArea() const;

    /**
     * Returns true if the area contains the central widget of it's manager.
     */
    bool containsCentralWidget() const;

    /**
     * If this dock area is the one and only visible area in a container, then
     * this function returns true
     */
    bool isTopLevelArea() const;


public Q_SLOTS:
	/**
	 * This activates the tab for the given tab index.
	 * If the dock widget for the given tab is not visible, the this function
	 * call will make it visible.
	 */
	void setCurrentIndex(int index);

	/**
	 * Closes the dock area and all dock widgets in this area
	 */
	void closeArea();

	/**
	 * Sets the dock area into auto hide mode or into normal mode.
	 * If the dock area is switched to auto hide mode, then all dock widgets
	 * that are pinable will be added to the sidebar
	 */
	void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone, int TabIndex = -1);

	/**
	 * Switches the dock area to auto hide mode or vice versa depending on its
	 * current state.
	 */
	void toggleAutoHide(SideBarLocation Location = SideBarNone);

    /**
	 * This function closes all other areas except of this area
	 */
	void closeOtherAreas();

	/**
	 * Moves the dock area into its own floating widget if the area
	 * DockWidgetFloatable flag is true
	 */
	void setFloating();

Q_SIGNALS:
	/**
	 * This signal is emitted when user clicks on a tab at an index.
	 */
	void tabBarClicked(int index);

    /**
     * This signal is emitted when the tab bar's current tab is about to be changed. The new
     * current has the given index, or -1 if there isn't a new one.
     * @param index
     */
    void currentChanging(int index);

	/**
	 * This signal is emitted when the tab bar's current tab changes. The new
	 * current has the given index, or -1 if there isn't a new one
	 * @param index
	 */
	void currentChanged(int index);

	/**
	 * This signal is emitted if the visibility of this dock area is toggled
	 * via toggle view function
	 */
	void viewToggled(bool Open);
}; // class DockAreaWidget
} // namespace ads

Q_DECLARE_OPERATORS_FOR_FLAGS(ads::CDockAreaWidget::DockAreaFlags)
//-----------------------------------------------------------------------------
#endif // DockAreaWidgetH
