/**
 * Copyright Marcus Britanicus <marcusbritanicus@gmail.com>
 *
 * This file is a part of LibDesQ Widgets (https://gitlab.com/DesQ/libdesqui)
 * This library contains the UI classes and Plugin interfaces that are used
 * through out the DesQ Project.
 *
 * This file was originally a part of the KDE project: KF5 ItemViews Module
 * 2007 Rafael Fernández López <ereslibre@kde.org>
 * 2007 John Tapsell <tapsell@kde.org>
 * Original License: LGPL 2.0
 *
 * 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 3 of the License, or
 * at your option, any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 **/

#pragma once

#include <QSortFilterProxyModel>
#include <memory>
class QItemSelection;

namespace DesQUI {
    class SortFilterProxyModel;
    class SortFilterProxyModelPrivate;
}

/**
 * This class lets you categorize a view. It is meant to be used along with
 * CategorizedView class.
 *
 * In general terms all you need to do is to reimplement subSortLessThan() and
 * compareCategories() methods. In order to make categorization work, you need
 * to also call setCategorizedModel() class to enable it, since the categorization
 * is disabled by default.
 */
class DesQUI::SortFilterProxyModel : public QSortFilterProxyModel {
    Q_OBJECT;

    public:
        enum AdditionalRoles {
            /** String value that's painted as category title */
            CategoryDisplayRole = 0x17CE990A,

            /** A value that's used to sort categories (String/numeric) */
            CategorySortRole    = 0x27857E60,
        };

        SortFilterProxyModel( QObject *parent = nullptr );
        ~SortFilterProxyModel() override;

        /**
         * Overridden from QSortFilterProxyModel. Sorts the source model using
         * @p column for the given @p order.
         */
        void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override;

        /**
         * @return whether the model is categorized or not. Disabled by default.
         */
        bool isCategorizedModel() const;

        /**
         * Enables or disables the categorization feature.
         *
         * @param categorizedModel whether to enable or disable the categorization feature.
         */
        void setCategorizedModel( bool categorizedModel );

        /**
         * @return the column being used for sorting.
         */
        int sortColumn() const;

        /**
         * @return the sort order being used for sorting.
         */
        Qt::SortOrder sortOrder() const;

        /**
         * Set if the sorting using CategorySortRole will use a natural comparison
         * in the case that strings were returned. If enabled, QCollator
         * will be used for sorting.
         *
         * @param sortCategoriesByNaturalComparison whether to sort using a natural comparison or not.
         */
        void setSortCategoriesByNaturalComparison( bool sortCategoriesByNaturalComparison );

        /**
         * @return whether it is being used a natural comparison for sorting. Enabled by default.
         */
        bool sortCategoriesByNaturalComparison() const;

    protected:

        /**
         * This function calls compareCategories() to sort by category.
         * If the both items are in the same category, then subSortLessThan is called.
         */
        bool lessThan( const QModelIndex& left, const QModelIndex& right ) const override;

        /**
         * A function to compare the items within a category.
         */
        virtual bool subSortLessThan( const QModelIndex& left, const QModelIndex& right ) const;

        /**
         * A function to compare the two categories: Negative value puts the @left category
         * before the @right category.
         */
        virtual int compareCategories( const QModelIndex& left, const QModelIndex& right ) const;

    private:
        Q_DECLARE_PRIVATE( DesQUI::SortFilterProxyModel );
};
