/**
 * Copyright (c) 2022
 *    Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 *    Abrar (https://gitlab.com/s96abrar)
 *
 * This file was originally a part of SmartVerticalFlowLayout project
 * <https://github.com/VaysseB/SmartVerticalFlowLayout>
 * Several modifications have been made to suit the needs of DFL.
 * Any and all bug reports are to be filed with DFL and not SVFL.
 *
 * DFL::DynamicLayout is a dynamic layout that switches from horizontal
 * to vertical layout mode if the available width goes below a
 * particular value (default: 300 px).
 **/

#pragma once

#include <QStyle>
#include <QLayout>
#include <QWidget>
#include <QLayoutItem>

namespace DFL {
    class DynamicLayout;
}

class DFL::DynamicLayout : public QLayout {
    Q_OBJECT

    Q_PROPERTY( int horizontalSpacing READ horizontalSpacing WRITE setHorizontalSpacing )
    Q_PROPERTY( int verticalSpacing READ verticalSpacing WRITE setVerticalSpacing )
    Q_PROPERTY( Qt::Alignment alignment READ alignment WRITE setAlignment )
    Q_PROPERTY( int maxRowCount READ maxRowCount WRITE setMaxRowCount )

    public:
        explicit DynamicLayout( QWidget *parent = 0 );
        ~DynamicLayout();

        int count() const;
        void addItem( QLayoutItem *item );
        QLayoutItem *itemAt( int index ) const;
        QLayoutItem *takeAt( int index );

        void clear();

        int horizontalSpacing() const;
        int verticalSpacing() const;

        bool hasHeightForWidth() const;
        int heightForWidth( int width ) const;

        int maxRowCount() const;

        /**
         * @brief Return with no expanding direction if aligment isn't justify nor 0.
         * @return Qt::Horizontal or 0
         */
        Qt::Orientations expandingDirections() const;

        QSize sizeHint() const;
        QSize minimumSizeHint() const;

        QSize minimumSize() const;
        void setGeometry( const QRect& rect );

    public slots:
        void setSpacing( int space );
        void setHorizontalSpacing( int space );
        void setVerticalSpacing( int space );

        void setMaxRowCount( int count );

        /**
         * @brief Change alignment of all items.
         * You must call DesQLayout::updateLayout() if called as
         * QLayout* or QLayoutItem* because the function isn't virtual
         *
         * @param align Items alignment ( 0, Justify, Left, Center, Right )
         */
        void setAlignment( Qt::Alignment align );

        /**
         * @brief Force layout to reprocess all items positions.
         */
        void updateLayout();

    private:
        void doLayout( const QRect& rect, bool dummy ) const;
        int smartSpacing( QStyle::PixelMetric pm ) const;

    private:
        QList<QLayoutItem *> m_items;
        int m_hSpace = -1;
        int m_vSpace = -1;

        int m_maxRowCount = -1;

        mutable QList<QList<QLayoutItem *> > m_structure;
        mutable QRect m_structureGeometry;
        mutable bool m_isLayoutModified = false;
};
