#ifndef __GROUP_LIST_H__
#define __GROUP_LIST_H__

/*
 * KFontInst - KDE Font Installer
 *
 * Copyright 2003-2007 Craig Drummond <craig@kde.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.
 *
 * 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; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <QUrl>
#include <KFileItem>
#include <KIO/Job>
#include <KDirLister>
#include <QList>
#include <QTreeView>
#include <QAbstractItemModel>
#include <QModelIndex>
#include <QVariant>
#include "FontList.h"

class QDragEnterEvent;
class QDragLeaveEvent;
class QDropEvent;
class QTextStream;
class QDomElement;

namespace KFI
{

class CGroupList;
class CFontItem;

class CGroupListItem
{
    public:

    enum EType
    {
        ALL,
        PERSONAL,
        SYSTEM,
        UNCLASSIFIED,
        CUSTOM
    };

    union Data
    {
        bool       validated;      //CUSTOM
        CGroupList *parent;        //UNCLASSIFIED
    };

    CGroupListItem(const QString &name);
    CGroupListItem(EType type, CGroupList *p);

    const QString &      name() const                        { return itsName; }
    void                 setName(const QString &n)           { itsName=n; }
    QSet<QString> &      families()                          { return itsFamilies; }
    EType                type() const                        { return itsType; }
    bool                 isCustom() const                    { return CUSTOM==itsType; }
    bool                 isAll() const                       { return ALL==itsType; }
    bool                 isUnclassified() const              { return UNCLASSIFIED==itsType; }
    bool                 isPersonal() const                  { return PERSONAL==itsType; }
    bool                 isSystem() const                    { return SYSTEM==itsType; }
    bool                 validated() const                   { return isCustom() ? itsData.validated : true; }
    void                 setValidated()                      { if(isCustom()) itsData.validated=true; }
    bool                 highlighted() const                 { return itsHighlighted; }
    void                 setHighlighted(bool b)              { itsHighlighted=b; }
    bool                 hasFont(const CFontItem *fnt) const;
    CFamilyItem::EStatus status() const                      { return itsStatus; }
    void                 updateStatus(QSet<QString> &enabled, QSet<QString> &disabled,
                                      QSet<QString> &partial);
    bool                 load(QDomElement &elem);
    bool                 addFamilies(QDomElement &elem);
    void                 save(QTextStream &str);
    void                 addFamily(const QString &family)    { itsFamilies.insert(family); }
    void                 removeFamily(const QString &family) { itsFamilies.remove(family); }
    bool                 hasFamily(const QString &family)    { return itsFamilies.contains(family); }

    private:

    QSet<QString>        itsFamilies;
    QString              itsName;
    EType                itsType;
    Data                 itsData;
    bool                 itsHighlighted;
    CFamilyItem::EStatus itsStatus;
};

class CGroupList : public QAbstractItemModel
{
    Q_OBJECT

    public:

    CGroupList(QWidget *parent = 0);
    ~CGroupList();

    QVariant        data(const QModelIndex &index, int role) const;
    bool            setData(const QModelIndex &index, const QVariant &value, int role);
    Qt::ItemFlags   flags(const QModelIndex &index) const;
    QVariant        headerData(int section, Qt::Orientation orientation,
                               int role = Qt::DisplayRole) const;
    QModelIndex     index(int row, int column,
                          const QModelIndex &parent = QModelIndex()) const;
    QModelIndex     parent(const QModelIndex &index) const;
    int             rowCount(const QModelIndex &parent = QModelIndex()) const;
    int             columnCount(const QModelIndex &parent = QModelIndex()) const;
    void            update(const QModelIndex &unHighlight, const QModelIndex &highlight);
    void            updateStatus(QSet<QString> &enabled, QSet<QString> &disabled,
                                 QSet<QString> &partial);
    void            setSysMode(bool sys);
    void            rescan();
    void            load();
    bool            load(const QString &file);
    bool            save();
    bool            save(const QString &fileName, CGroupListItem *grp);
    void            merge(const QString &file);
    void            clear();
    QModelIndex     index(CGroupListItem::EType t);
    void            createGroup(const QString &name);
    bool            removeGroup(const QModelIndex &idx);
    void            removeFamily(const QString &family);
    bool            removeFromGroup(CGroupListItem *grp, const QString &family);
    QString         whatsThis() const;

    CGroupListItem * group(CGroupListItem::EType t)
                        { return itsSpecialGroups[t]; }
    bool            exists(const QString &name, bool showDialog=true);

    public Q_SLOTS:

    void            addToGroup(const QModelIndex &group, const QSet<QString> &families);
    void            removeFromGroup(const QModelIndex &group, const QSet<QString> &families);

    Q_SIGNALS:

    void            refresh();

    private:

    void            readGroupsFile();
    void            sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
    Qt::DropActions supportedDropActions() const;
    QStringList     mimeTypes() const;
    CGroupListItem * find(const QString &name);
    QModelIndex     createIdx(int r, int c, void *p) { return createIndex(r, c, p); }

    private:

    QString                                       itsFileName;
    time_t                                        itsTimeStamp;
    bool                                          itsModified;
    QWidget                                       *itsParent;
    QList<CGroupListItem *>                       itsGroups;
    QMap<CGroupListItem::EType, CGroupListItem *> itsSpecialGroups;
    Qt::SortOrder                                 itsSortOrder;

    friend class CGroupListItem;
    friend class CGroupListView;
};

class CGroupListView : public QTreeView
{
    Q_OBJECT

    public:

    CGroupListView(QWidget *parent, CGroupList *model);
    virtual ~CGroupListView()              { }

    QSize                 sizeHint() const { return QSize(32, 32); }

    bool                  isCustom()       { return CGroupListItem::CUSTOM==getType(); }
    bool                  isUnclassified() { return CGroupListItem::UNCLASSIFIED==getType(); }
    bool                  isSystem()       { return CGroupListItem::SYSTEM==getType(); }
    bool                  isPersonal()     { return CGroupListItem::PERSONAL==getType(); }
    CGroupListItem::EType getType();
    void                  controlMenu(bool del, bool en, bool dis, bool p, bool exp);

    Q_SIGNALS:

    void                  del();
    void                  print();
    void                  enable();
    void                  disable();
    void                  zip();
    void                  moveFonts();
    void                  info(const QString &str);
    void                  addFamilies(const QModelIndex &group, const QSet<QString> &);
    void                  removeFamilies(const QModelIndex &group, const QSet<QString> &);
    void                  itemSelected(const QModelIndex &);
    void                  unclassifiedChanged();

    private Q_SLOTS:

    void                  selectionChanged(const QItemSelection &selected,
                                           const QItemSelection &deselected);
    void                  rename();
    void                  emitMoveFonts();

    private:

    void                  contextMenuEvent(QContextMenuEvent *ev);
    void                  dragEnterEvent(QDragEnterEvent *event);
    void                  dragMoveEvent(QDragMoveEvent *event);
    void                  dragLeaveEvent(QDragLeaveEvent *event);
    void                  dropEvent(QDropEvent *event);
    void                  drawHighlighter(const QModelIndex &idx);
    virtual bool          viewportEvent(QEvent *event);

    private:

    QMenu       *itsMenu;
    QAction     *itsDeleteAct,
                *itsEnableAct,
                *itsDisableAct,
                *itsPrintAct,
                *itsRenameAct,
                *itsExportAct;
    QModelIndex itsCurrentDropItem;
};
}

#endif
