/***************************************************************************
                          grouplistviewitem.cpp  -  description
                             -------------------
    begin                : Fri Mar 28 2003
    copyright            : (C) 2003 by Mike K. Bennett
                           (C) 2005 by Diederik van der Boor
    email                : mkb137b@hotmail.com
                           vdboor --at-- codingdomain.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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "grouplistviewitem.h"

#include <qobject.h>
#include <qregexp.h>
#include <qstylesheet.h>

#include <kdebug.h>
#include <klocale.h>
#include <kaction.h>
#include <kiconloader.h>


#include "contactlistviewitem.h"
#include "kmessdebug.h"
#include "specialgroups.h"
#include "contact/contact.h"
#include "contact/group.h"

#ifdef KMESSDEBUG_GROUPLISTVIEWITEM
#define KMESSDEBUG_GROUPLISTVIEWITEM_GENERAL
#endif


// The constructor
GroupListViewItem::GroupListViewItem(QListView *parent, Group *group)
 : QObject(0, "listItem"),
   KMessListViewItem( parent ),
   group_(group),
   moveAction_(0),
   noContactsOnline_(0)
{
  // Do general construction
  construct();
}



// The constructor
GroupListViewItem::GroupListViewItem(QListViewItem *parent, Group *group)
 : QObject(0, "listItem"),
   KMessListViewItem( parent ),
   group_(group),
   moveAction_(0),
   noContactsOnline_(0)
{
  // Do general construction
  construct();
}



// The destructor
GroupListViewItem::~GroupListViewItem()
{
  if(moveAction_ != 0)
  {
    moveAction_->unplugAll();
    delete moveAction_;
  }
}



// Add a new contact item
ContactListViewItem * GroupListViewItem::addContactItem(Contact *contact)
{
  ContactListViewItem *item = new ContactListViewItem(this, contact);

  if(! group_->isSpecialGroup())
  {
    // Update counters
    if(item->getContact()->isOnline())
    {
      noContactsOnline_++;
    }

    // Attach to signals to update the counters
    connect(contact, SIGNAL(contactOffline(Contact*,bool)), this, SLOT(slotContactOffline()));
    connect(contact, SIGNAL(contactOnline(Contact*,bool)),  this, SLOT(slotContactOnline()));
  }

  // Update the counter text
  slotUpdateAppearance();

  // Return for further processing
  return item;
}



// // Compare
// int GroupListViewItem::compare( QListViewItem *item, int col, bool asc) const
// {
// #ifdef KMESSTEST
//   ASSERT( dynamic_cast<KMessListViewItem *>(item) != 0 );
// #endif
//
//   GroupListViewItem *that;
// 
//   int thatType = static_cast<KMessListViewItem*>(item) -> getType();
//   int result;
// 
// 
//   // Determine the sorting based on the object type.
//   if(thatType == LISTTYPE_GROUP)
//   {
//     return 0; // FIXME
//     that   = static_cast<GroupListViewItem *>(item);
// 
// #ifdef KMESSTEST
//     ASSERT( dynamic_cast<GroupListViewItem *>(item) != 0 );
//     ASSERT( this->group_ != 0 );
//     ASSERT( that->group_ != 0 );
// #endif
// 
//     if(this->group_ == 0 && that->group_ == 0) return 0;
//     if(this->group_ == 0) return -1;
//     if(that->group_ == 0) return  1;
// 
//     result = that->group_->getSortPosition() - this->group_->getSortPosition();
//   }
//   else
//   {
//     // Groups
//     result = KMessListViewItem::compare(item, col, asc);
//   }
// 
// 
//   // Return the correct value for the sorting algorithm.
//   if(result < 0) return -1;  // "this" is smaller then "that"
//   if(result > 0) return 1;   // "this" is greater then "that"
//   return 0;                  // "this" and "that" are equal.
// }



// Do general construction
void GroupListViewItem::construct()
{
  // Set default settings
  setExpandable(true);

  // Create the popupmenu action
  if(! group_->isSpecialGroup())
  {
    moveAction_ = new KAction();
    connect(moveAction_, SIGNAL(activated()), this, SLOT(slotForwardActivated()));
  }

  // Attach group signals
  connect( group_, SIGNAL(nameChanged()          ),    // The name changed
           this,     SLOT(slotUpdateAppearance() ) );
  connect( group_, SIGNAL(sortPositionChanged()  ),    // The sort position changed
           this,     SLOT(slotUpdateAppearance() ) );
  connect( group_, SIGNAL(expandedStateChanged() ),    // The expanded state changed
           this,     SLOT(slotUpdateAppearance() ) );

  // Call the event manually this time, to update the appearance.
  slotUpdateAppearance();
}



// Called to signal that the contactitem will be removed from this group.
void GroupListViewItem::detachContactItem(ContactListViewItem *item)
{
  Contact *contact;

  if(! group_->isSpecialGroup())
  {
#ifdef KMESSDEBUG_GROUPLISTVIEWITEM_GENERAL
    kdDebug() << "GroupListViewItem::detachContactItem: is online: " << item->getContact()->isOnline() << endl;
#endif

    contact = item->getContact();
    if(contact->isOnline())
    {
      noContactsOnline_--;
    }

    // Detach to signals that update the counters
    disconnect(contact, SIGNAL(contactOffline(Contact*,bool)), this, SLOT(slotContactOffline()));
    disconnect(contact, SIGNAL(contactOnline(Contact*,bool)),  this, SLOT(slotContactOnline()));
  }

  // Update the item count text
  slotUpdateAppearance();
}



// Return the group
Group * GroupListViewItem::getGroup() const
{
  return group_;
}



// Return the KAction object to be used in the move-contact menu (and null if it's not possible)
KAction * GroupListViewItem::getMoveAction() const
{
  return moveAction_;
}



// Return the type ID
int GroupListViewItem::getType() const
{
  return LISTTYPE_GROUP;
}



// Update the contacts online/offline count
void GroupListViewItem::recountContacts()
{
#ifdef KMESSDEBUG_GROUPLISTVIEWITEM_GENERAL
  kdDebug() << "GroupListViewItem: Recounting contacts of group " << group_->getId() << endl;
#endif

  /*
   * The slotContactOffline/slotContactOnline slots are
   * not activated when a contact is removed from the friends-list.
   * Before they receive their signals, they are already
   * detached using detachContactItem().
   * That's why this code is required.
   */

  if(! group_->isSpecialGroup())
  {
    QListViewItem       *item = firstChild();
    ContactListViewItem *contactItem;
    int                  type;

    noContactsOnline_  = 0;

    while(item != 0)
    {
      // Check for the given type
      type = static_cast<KMessListViewItem*>( item )->getType();
      if(type == KMessListViewItem::LISTTYPE_CONTACT)
      {
        // Check whether the object references the contact.
        contactItem = static_cast<ContactListViewItem*>( item );

        if(contactItem->getContact()->isOnline())
        {
          noContactsOnline_++;
        }
      }
      item = item->nextSibling();
    }
  }

  slotUpdateAppearance();
}



// Update the online/offline counters
void GroupListViewItem::slotContactOffline()
{
#ifdef KMESSDEBUG_GROUPLISTVIEWITEM_GENERAL
  kdDebug() << "GroupListViewItem: contact went offline in group " << group_->getId() << endl;
#endif

  noContactsOnline_--;
  slotUpdateAppearance();
}



// Update the online/offline counters
void GroupListViewItem::slotContactOnline()
{
#ifdef KMESSDEBUG_GROUPLISTVIEWITEM_GENERAL
  kdDebug() << "GroupListViewItem: contact went online in group " << group_->getId() << endl;
#endif

  noContactsOnline_++;
  slotUpdateAppearance();
}



// Forward when moveAction_ is activated
void GroupListViewItem::slotForwardActivated()
{
  emit moveToGroup(group_);
}



// Update the appearance of the item
void GroupListViewItem::slotUpdateAppearance()
{
  KIconLoader *loader = KGlobal::iconLoader();
  QString sortPrefix;
  QString iconName;
  QString imageFile;
  int     imageSize;
  QString name       = group_->getName();
  QString htmlName   = QStyleSheet::escape(name);
  QString fullText;
  bool    isExpanded = group_->isExpanded();

  // Set the KAction text
  if(moveAction_ != 0)
  {
    moveAction_->setText(group_->getName());
  }

  // Determine the icon and sorting index
  if(group_->getId() == SpecialGroups::ONLINE)
  {
    sortPrefix  = "bb ";
    iconName    = "folder_green";
  }
  else if(group_->getId() == SpecialGroups::OFFLINE)
  {
    sortPrefix  = "cc ";
    iconName    = "folder_green";
  }
  else if(group_->getId() == SpecialGroups::ALLOWED)
  {
    sortPrefix  = "dd ";
    iconName    = "folder_orange";
  }
  else if(group_->getId() == SpecialGroups::REMOVED)
  {
    sortPrefix  = "ee ";
    iconName    = "folder_orange";
  }
  else
  {
    // Normal group
    sortPrefix.sprintf("aa%02d ", group_->getSortPosition());
    iconName    = "folder_green";
  }


  // Open for expanded items
  if(isExpanded && childCount() > 0)
  {
    iconName += "_open";
  }


    // Include the image to the text
  imageFile = loader->iconPath(iconName, KIcon::Small, false);
  imageSize = loader->currentSize(KIcon::Small);

  if(! imageFile.isEmpty())
  {
    fullText = QString("<img src=\"%1\" width=\"%2\" height=\"%2\"> ")
                      .arg(imageFile).arg(imageSize).append(htmlName);
  }
  else
  {
    fullText = htmlName;
  }

  // Append the contact online/offline count status.
  if(group_->isSpecialGroup())
  {
    fullText += " (" + QString::number(childCount()) + ")";
  }
  else
  {
    fullText += " (" + QString::number(noContactsOnline_) + "/" + QString::number(childCount()) + ")";
  }

  setHTMLText(fullText);


  // Set the sort text
  // FIXME: remove this if the "QListViewItem::compare" method works.
  setText(0, sortPrefix + name);
  resortParent();
  setOpen(isExpanded);
}


#include "grouplistviewitem.moc"
