/***************************************************************************
                          contactlist.h  -  description
                             -------------------
    begin                : Sun Jan 5 2003
    copyright            : (C) 2003 by Mike K. Bennett
                           (C) 2005 by Diederik van der Boor
    email                : mkb137b@hotmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 CONTACTLIST_H
#define CONTACTLIST_H

#include "contact/msnstatus.h"
#include "contactlistmodelitem.h"

#include <QAbstractItemModel>
#include <QHash>


// Forward declarations
class Contact;
class CurrentAccount;
class Group;
class KMessTest;



/**
 * @brief Data class for the contact list.
 *
 * This class stores the state of the current contact list, it does not update the server.
 * The MsnNotificationConnection class sends update requests to the server.
 * When the server acknowledges the change, it will be updated here.
 * The user interface classes repond to the signals of this class to update their view.
 *
 * The instance of this class is shared between the MsnNotificationConnection class,
 * and re-used when the user connects with a different account.
 * After the MsnNotificationConnection class is initialized, a pointer
 * to the ContactList is set in the CurrentAccount class too.
 * The CurrentAccount class is only used to provide access to the current contact list,
 * the administration of the contacts is still done through the MsnNotificationConnection class,
 *
 * @author Mike K. Bennett
 * @author Valerio Pilo
 * @ingroup Contact
 */
class ContactList : public QAbstractItemModel
{
  Q_OBJECT

  friend class KMessTest;

  public: // Public methods
    // The constructor
                         ContactList();
    // The destructor
    virtual             ~ContactList();
    // Add a contact to the contact list
    Contact *            addContact( const QString& handle, const QString& friendlyName, int lists, 
                                      QStringList groupIds, const QString& guid, bool isMessenger = true );
    // Change a contact's status (and update the friendly name)
    void                 changeContactStatus( const QString& handle, Status status,
                                              const QString& friendlyName = QString(),
                                              uint capabilities = 0, const QString& msnObjectString = QString(), bool showBaloon = true );
    // Return the contact with the given guid
    Contact*             getContactByGuid( QString guid ) const;
    // Return the contact with the given handle
    Contact*             getContactByHandle( QString handle ) const;
    // Return the list of contacts
    const QHash<QString,Contact*>& getContactList() const;
    // Return the group with the given id
    Group*               getGroupById( QString groupId ) const;
    // Return the group with the given name
    Group*               getGroupByName( QString name ) const;
    // Return the group with the given sort position
    Group*               getGroupBySortPosition( int sortPosition, bool next ) const;
    // Return the list of groups
    const QList<Group*>& getGroupList() const;
    // Find out if a group contains contacts
    bool                 isGroupEmpty( const QString &groupId ) const;
    // Read groups and contacts properties
    void                 readProperties();
    // Change a contact's name
    void                 renameContact( QString handle, QString newName );
    // Restore the orginal state of the contact list (empty it)
    void                 reset( bool restore = true );
    // Save groups and contacts properties
    void                 saveProperties();
    // Save the properties of a contact
    void                 saveProperties( const Contact *contact ) const;
    // Save the properties of a group
    void                 saveProperties( const Group *group ) const;

  public slots:
    // Add a group to the contact list
    Group*               addGroup( const QString& groupId, const QString& groupName );
    // Remove a contact from the list completely
    void                 removeContact( QString contactId );
    // Remove a group
    void                 removeGroup( const QString& groupId );
    // Change a group's name
    void                 renameGroup( const QString& groupId, const QString& newName );

  public:  // Public model methods
    // Get the number of columns present in an index
    int                  columnCount( const QModelIndex &parent = QModelIndex() ) const;
    // Return the data contained by an index in the model
    QVariant             data( const QModelIndex &index, int role ) const;
    // Insert dropped data in the model (move/copy around stuff, in fact)
    bool                 dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent );
    // Dumps the contact list contents to the debug output
    void                 dump( ContactListModelItem *start = 0, int depth = 1 ) const;
    // Return the flags which characterize the index
    Qt::ItemFlags        flags( const QModelIndex &index ) const;
    // Find out if a model index contains other indices
    bool                 hasChildren( const QModelIndex &parent ) const;
    // Find out if the model contains a valid index at the specified position
    bool                 hasIndex( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
    // Return the text for a list or tree column header.
    QVariant             headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
    // Obtain a model index for a specificly located item
    QModelIndex          index( int row, int column, const QModelIndex &parent = QModelIndex() ) const;
    // Provide a MIME representation of some of the model's indexes
    QMimeData           *mimeData( const QModelIndexList &indexes ) const;
    // Return the supported drag&drop mimetypes
    QStringList          mimeTypes() const;
    // Obtain a model index's parent index
    QModelIndex          parent( const QModelIndex &index ) const;
    // Get the number of rows present in an index
    int                  rowCount( const QModelIndex &parent = QModelIndex() ) const;
    // Specify which drag and drop operations are supported
    Qt::DropActions      supportedDropActions() const;

  private: // Private methods
    // Return whether or not the contact with the given handle exists
    bool                 contactExists( QString handle );
    // Remove gaps and duplicates in the groups list
    void                 ensureGroupListValid();
    // Emits the Data Changed signal on one item
    void                 forwardDataChanged( ContactListModelItem *item );
    // Emits the Data Changed signal on some items
    void                 forwardDataChanged( ModelItemList itemList );
    // Return whether or not a group with the given id exists
    bool                 groupExists( QString groupId );
    // return a QModelIndex pointing to the given group Id.
    QModelIndex          getIndexForGroup( QString groupId );
    // remove a contact from a group
    void                 removeContactFromGroup( const QString& handle, ContactListModelItem *groupItem );

  private slots: // Private slots
    // Forward from a contact that it moved
    void                 slotContactMoved( Contact *contact );
    // Forward from a group that it moved
    void                 slotGroupMoved( Group *group, int oldPosition, int newPosition );
    // Forward from a contact that it is offline
    void                 slotForwardContactOffline( Contact *contact, bool showBaloon );
    // Forward from a contact that it is contact is online
    void                 slotForwardContactOnline( Contact *contact, bool showBaloon );


  private: // Private attributes
    // The list of contacts
    QHash<QString,Contact*> contacts_;
    // The list of groups
    QList<Group*>         groups_;
    // The root node which makes up the contact list tree
    ContactListModelItem *rootNode_;

  signals: // Signals
    // Signal that a contact changed it's msnobject.
    void                 contactChangedMsnObject(Contact *contact);
    // Signal that a contact changed it's status.
    void                 contactChangedStatus( Contact *contact, bool showBaloon );
    // Signal that a contact is offline
    void                 contactOffline( Contact *contact, bool showBaloon );
    // Signal that a contact is online
    void                 contactOnline( Contact *contact, bool showBaloon );
    // Signal that a contact has been added
    void                 contactAdded( Contact *contact );
    // Signal that a contact has been removed
    void                 contactRemoved( Contact *contact );
    // Signal that a group has been added
    void                 groupAdded( const Group *group );
    // Signal that a group has been modified
    void                 groupChanged(const Group *group);
    // Signal that a group has been removed
    void                 groupRemoved(const Group *group);
    // Drag'n'drop operation to move a contact -- TODO post 2.0: replace with proper impl
    void                 dndMoveContactToGroup( QString handle, QString oldGroupId, QString newGroupId );
};

#endif
