/***************************************************************************
 *   Copyright (C) 2005-2006 David Saxton <david@bluehaze.org>             *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#ifndef VIEWCONTAINER_H
#define VIEWCONTAINER_H

// #include <q3dragobject.h>
#include <QList>
#include <QMap>
#include <QPointer>
#include <QSplitter>

class KConfigGroup;
class KTechlab;
class View;
class ViewArea;
class ViewContainer;

class KConfig;
class QHBoxLayout;
class QLayout;
class QSplitter;

typedef QMap<uint, ViewArea *> ViewAreaMap;
typedef QList<int> IntList;

/**
Before a ViewAre has been given a view, this is shown.
\author David Saxton
*/
class EmptyViewArea : public QWidget
{
    Q_OBJECT
public:
    EmptyViewArea(ViewArea *parent);
    ~EmptyViewArea() override;

protected slots:
    void openDocument();

protected:
    ViewArea *m_pViewArea;
};

/**
Contains either exactly one View, or two ViewAreas, separated by a QSplitter.
If it contains one view, then the value returned in id() is that of the view.
If it contains two ViewAreas, then the value returned by id() is -1.
@author David Saxton
*/
class ViewArea : public QSplitter
{
    Q_OBJECT
public:
    enum Position { Right, Bottom };

    ViewArea(QWidget *parent, ViewContainer *viewContainer, int id, bool showOpenButton);
    ~ViewArea() override;

    ViewContainer *viewContainer() const
    {
        return p_viewContainer;
    }
    int id() const
    {
        return m_id;
    }
    /**
     * Splits this ViewArea into two, and returns a pointer to the new ViewArea
     * @param showOpenButton Whether to present the user with the EmptyViewArea
     * widget (i.e. the new ViewArea is not destined to be immediately filled
     * with a view).
     */
    ViewArea *createViewArea(Position position, uint id, bool showOpenButton);
    /**
     * Adds the given View to the main part of the layout
     */
    void setView(View *view);
    /**
     * Saves the state of this ViewArea and any contained ViewAreas
     */
    void saveState(KConfigGroup *config);
    /**
     * Restores the state of this ViewArea and any contained ViewAreas
     * @param groupName e.g. "ViewContainer 1"
     */
    void restoreState(KConfigGroup *config, int id, const QString &groupName);
    /**
     * Returns true if this ViewArea can save useful information as to its state
     * (i.e. it's children can save useful information about their state, or has
     * a view with a url in it)
     */
    bool canSaveUsefulStateInfo() const;

    static QString fileKey(int id);
    static QString containsKey(int id);
    static QString orientationKey(int id);

    View *view() const
    {
        return p_view;
    }

protected slots:
    void viewAreaDestroyed(QObject *obj);
    void viewDestroyed();

protected:
    int m_id;
    EmptyViewArea *m_pEmptyViewArea;
    QPointer<View> p_view;
    ViewArea *p_viewArea1;
    ViewArea *p_viewArea2;
    ViewContainer *p_viewContainer;
};

/**
@author David Saxton
*/
class ViewContainer : public QWidget
{
    Q_OBJECT
public:
    /**
     * Constructs a new ViewContainer, along with a default ViewArea ready for
     * parenting a View, with an id of 0. parent is only used if ktechlab is
     * null; otherwise the parent widget is ktechlab's tabWidget()
     */
    ViewContainer(const QString &caption, QWidget *parent = nullptr);
    ~ViewContainer() override;

    /**
     * Returns the view in the ViewArea with the given id
     */
    View *view(uint id) const;
    /**
     * Returns the ViewArea with the given id
     */
    ViewArea *viewArea(uint id) const;
    /**
     * The active view area is the one that is focused.
     */
    void setActiveViewArea(uint id);
    /**
     * Returns the id of the active ViewArea
     */
    uint activeViewArea() const
    {
        return m_activeViewArea;
    }
    /**
     * Returns a pointer to the view of the active view area
     */
    View *activeView() const
    {
        return view(activeViewArea());
    }
    /**
     * Attempts to close the given viewarea, returning true if successful (i.e
     * if the user did not object to the close request )
     */
    bool closeViewArea(uint id);
    /**
     * Creates a view area (parent QWidget, splitter et al) ready for inclusion
     * of a view.
     * @param relativeViewArea the viewarea to position the new viewarea next to, if -1 then is taken to be the active view area
     * @param position Top, Right, Bottom or Left of given relativeViewArea
     * @returns id of the view area, or -1 if unsucessful
     * @param showOpenButton Whether to present the user with the EmptyViewArea
     * widget (i.e. the new ViewArea is not destined to be immediately filled
     * with a view).
     */
    int createViewArea(int relativeViewArea, ViewArea::Position position, bool showOpenButton);
    /**
     * Attempts to close each view area, returning false if any fail to be
     * closed
     */
    bool closeViewContainer();
    /**
     * @returns number of views in this view container
     */
    uint viewCount() const
    {
        return m_viewAreaMap.size();
    }
    /**
     * Sets the pointer to the view area with the given id
     */
    void setViewAreaId(ViewArea *viewArea, uint id);
    /**
     * Removes a ViewArea from internal lists
     */
    void setViewAreaRemoved(uint id);
    /**
     * Sets the id to be "used"
     */
    void setIdUsed(int id);
    /**
     * Writes the state of the View Container (layout of views and view URLs)
     * to the given KConfig. Doesn't change the group - so preset it if
     * needed!
     */
    void saveState(KConfigGroup *config);
    /**
     * Reads in the saved config state (as written by saveState), and restores
     * the ViewContainer with all appropriate views open
     * @param groupName e.g. "ViewContainer 1"
     */
    void restoreState(KConfigGroup *config, const QString &groupName);
    /**
     * Returns a unique id (negative) for a ViewArea that is now a Parent of other ViewAreas
     */
    int uniqueParentId();
    /**
     * Returns a unique id (positive) for a new ViewArea
     */
    int uniqueNewId();
    /**
     * Returns true if this ViewArea can save useful information as to its state
     * (i.e. it's children can save useful information about their state, or has
     * a view with a url in it)
     */
    bool canSaveUsefulStateInfo() const;

public slots:
    /**
     * Sets the tab caption et al from the contents of this ViewContainer
     */
    void updateCaption();

protected slots:
    void baseViewAreaDestroyed(QObject *obj);

protected:
    void restoreViewArea(KConfigGroup *config, int id, ViewArea *viewArea);
    void findActiveViewArea();
    int m_activeViewArea;
    ViewArea *m_baseViewArea;
    ViewAreaMap m_viewAreaMap;
    IntList m_usedIDs;
    bool b_deleted;
};

#endif
