/***************************************************************************
                          contact.cpp  -  description
                             -------------------
    begin                : Sun Jan 5 2003
    copyright            : (C) 2003 by Mike K. Bennett
    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.                                   *
 *                                                                         *
 ***************************************************************************/

#include "contact.h"

#include <qdir.h>
#include <qpixmap.h>
#include <qstringlist.h>

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

#include "contactextension.h"
#include "../currentaccount.h"
#include "../kmessdebug.h"
#include "../msnobject.h"
#include "../specialgroups.h"

#ifdef KMESSDEBUG_CONTACT
  #define KMESSDEBUG_CONTACT_GENERAL
#endif



// The constructor
Contact::Contact(QString handle, QString friendlyName, int lists, QString groupIds)
 : ContactBase(handle, friendlyName),
   allowed_(false),
   blocked_(false),
   capabilities_(0),
   friend_(false),
   initialized_(false),
   msnObject_(0),
   msnObjectChat_(0),
   reverse_(false),
   status_("FLN")
{
  if(lists & MSN_LIST_FRIEND)  friend_  = true;
  if(lists & MSN_LIST_ALLOWED) allowed_ = true;
  if(lists & MSN_LIST_BLOCKED) blocked_ = true;
  if(lists & MSN_LIST_REVERSE) reverse_ = true;

  // Never include the implicit group "0" to the list.
  if(groupIds != "0")
  {
    groupIds_  = QStringList::split(",", groupIds);
  }

  extension_ = new ContactExtension( handle );

  connect ( extension_, SIGNAL(     changedFriendlyName() ),
            this,         SLOT( emitChangedFriendlyName() ) );
  connect ( extension_, SIGNAL(          changedPicture() ),
            this,         SLOT(   forwardChangedPicture() ) );
}



// The destructor
Contact::~Contact()
{
#ifdef KMESSDEBUG_CONTACT_GENERAL
  kdDebug() << "DESTROYED Contact " << friendlyName_ << " (" << handle_ << ") " << endl;
#endif

  delete extension_;
  if(msnObject_) delete msnObject_;
}



// Add the groupID to the list of current groups
void Contact::addGroupId(const QString &groupId)
{
  if(! groupIds_.contains(groupId) && groupId != "0")
  {
    groupIds_.append(groupId);

#ifdef KMESSDEBUG_CONTACT_GENERAL
    kdDebug() << "Contact groups of " << handle_ << " are '" << groupIds_.join(",") << "'" << endl;
#endif

    emit changedGroup(this);
  }
  else
  {
    kdDebug() << "KMess: contact " << handle_ << " is already a member of group " << groupId << "." << endl;
  }
}


// Check if this is a new contact
bool Contact::checkIfContactAddedUser()
{
#ifdef KMESSDEBUG_CONTACT_GENERAL
  kdDebug() << "Contact " << friendlyName_ << " (" << handle_ << ") - Check if new." << endl;
#endif

  // Check if the contact is a new contact
  if ( !isFriend() && !isBlocked() && !isAllowed() && isReverse() )
  {
    return true;
  }
  return false;
}



// Slot to pass on the changedFriendlyName()
void Contact::emitChangedFriendlyName()
{
  emit changedFriendlyName();
}



// Forward the "changed picture" signal
void Contact::forwardChangedPicture()
{
  emit changedPicture();
}


// The capabilities of the client
uint Contact::getCapabilities() const
{
  return capabilities_;
}


// Return the path to the contact's picture
QString Contact::getContactPicturePath() const
{
  QString picturePath = extension_->getContactPicturePath();

  if( picturePath.isEmpty() )
  {
    return getContactDefaultPicturePath();
  }
  else
  {
    return picturePath;
  }
}


// Return a pointer to the extension class
ContactExtension *Contact::getExtension() const
{
  return extension_;
}


// Return the contact's friendly name
QString Contact::getFriendlyName() const
{
  if ( extension_->getUseAlternativeName() )
  {
    return extension_->getAlternativeName();
  }
  else
  {
    return friendlyName_;
  }
}



// Return the group ID's the contact is added to
QStringList Contact::getGroupIds() const
{
  return groupIds_;
}



// Return the contact's status
QString Contact::getStatus() const
{
  return status_;
}



// Return the contact's true friendly name, regardless of extension
QString Contact::getTrueFriendlyName() const
{
  return friendlyName_;
}



// Whether or not the contact is allowed
bool Contact::isAllowed() const
{
  return allowed_;
}



// Whether or not the contact is blocked
bool Contact::isBlocked() const
{
  return blocked_;
}



// Whether or not the contact is on the friends list
bool Contact::isFriend() const
{
  return friend_;
}



// Whether or not the contact is on the reverse list
bool Contact::isReverse() const
{
  return reverse_;
}


// Return the MSNObject
const MsnObject* Contact::getMsnObject() const
{
  return msnObject_;
}



// the chat session used to retreive the new msn object
const ChatInformation* Contact::getMsnObjectChat() const
{
  return msnObjectChat_;
}



// Setup and load an MSN Object
void Contact::loadMsnObject( QString msnObject )
{
  if (! msnObject || msnObject.isEmpty())
  {
    if(msnObject_ != 0)
    {
#ifdef KMESSDEBUG_CONTACT_GENERAL
      kdDebug() << getFriendlyName() << ": MSN Object Removed!" << endl;
#endif

      // Contact removed his picture.
      delete msnObject_;
      msnObject_ = 0;
      emit changedMsnObject(this);
    }
  }
  else
  {
    // Contact set his picture, or changed it.
    if (msnObject_)
    {
      // Actually not changed...
      if(! msnObject_->hasChanged(msnObject)) return;

      // Delete previous object.
      delete msnObject_;
      msnObject_= 0;
    }

#ifdef KMESSDEBUG_CONTACT_GENERAL
    kdDebug() << getFriendlyName() << ": MSN Object Changed!" << endl;
#endif

    msnObject_= new MsnObject(msnObject);
    emit changedMsnObject(this);
  }
}



// Remove the group from the list of group IDs
void Contact::removeGroupId(const QString &groupId)
{
  int removeCount = groupIds_.remove(groupId);
  if(removeCount > 0)
  {
#ifdef KMESSDEBUG_CONTACT_GENERAL
    kdDebug() << "Contact groups of " << handle_ << " are '" << groupIds_.join(",") << "'" << endl;
#endif

    emit changedGroup(this);
  }
  else
  {
    kdDebug() << "KMess: contact " << handle_ << " was not registered to group " << groupId << "." << endl;
  }
}



// Set whether or not the contact is allowed
void Contact::setAllowed(bool allowed)
{
  bool prevAllowed = allowed_;
  allowed_ = allowed;

  if(prevAllowed != allowed_)
  {
    emit changedList(this);
  }
}



// Set whether or not the contact is blocked
void Contact::setBlocked(bool blocked)
{
  bool prevBlocked = blocked_;
  blocked_ = blocked;

  if(prevBlocked != blocked_)
  {
    emit changedList(this);
  }
}



// Set the client capabilities
void Contact::setCapabilities(uint capabilities)
{
  capabilities_ = capabilities;
}



// Set whether or not the contact is on the friends list
void Contact::setFriend(bool isFriend)
{
  bool prevFriend = friend_;
  friend_ = isFriend;

  // If the contact is no longer at the FL, remove from all groups
  if(! isFriend)
  {
    groupIds_.clear();
    setStatus("FLN", false);
  }

  if(prevFriend != friend_)
  {
    emit changedList(this);
  }
}



// Change the contact's friendly name
void Contact::setFriendlyName(QString newName)
{
  if ( newName != "" )
  {
    friendlyName_ = newName;
//    updateItemIdentifierAndPixmap();
    emit changedFriendlyName();
  }
}



// Set whether or not the user is on a given list
void Contact::setList(const QString list, bool isMember)
{
#ifdef KMESSTEST
  ASSERT( ( list == "FL" ) || ( list == "AL" ) || ( list == "BL" ) || ( list == "RL" ) );
#endif
#ifdef KMESSDEBUG_CONTACT_GENERAL
  kdDebug() << "Contact::setList: old =" << (allowed_ ? " AL" : "")
                                         << (blocked_ ? " BL" : "")
                                         << (friend_  ? " FL" : "")
                                         << (reverse_ ? " RL" : "") << endl;
#endif

  if ( list == "FL" )
  {
    setFriend( isMember );
  }
  else if ( list == "AL" )
  {
    setAllowed( isMember );
  }
  else if ( list == "BL" )
  {
    setBlocked( isMember );
  }
  else if ( list == "RL" )
  {
    setReverse( isMember );
  }

#ifdef KMESSDEBUG_CONTACT_GENERAL
  kdDebug() << "Contact::setList: new =" << (allowed_ ? " AL" : "")
                                         << (blocked_ ? " BL" : "")
                                         << (friend_  ? " FL" : "")
                                         << (reverse_ ? " RL" : "") << endl;
#endif
}



// Set whether or not the contact is on the reverse list
void Contact::setReverse(bool reverse)
{
  bool prevReverse = reverse_;
  reverse_ = reverse;

  if(prevReverse != reverse_)
  {
    emit changedList(this);
  }
}



// the chat session used to retreive the new msn object
void Contact::setMsnObjectChat(const ChatInformation *msnObjectChat)
{
  // We only store the pointer, never include chatinformation.h!! (so we have no dependency)
  this->msnObjectChat_ = msnObjectChat;
}



// Set the contact's status
void Contact::setStatus(const QString status, bool showBaloon)
{
  bool isValidStatus = ( status == "AWY" ) ||
                       ( status == "BRB" ) ||
                       ( status == "BSY" ) ||
                       ( status == "FLN" ) ||
                       ( status == "IDL" ) ||
                       ( status == "LUN" ) ||
                       ( status == "NLN" ) ||
                       ( status == "PHN" );

#ifdef KMESSTEST
  ASSERT( isValidStatus );
#endif

  if(isValidStatus)
  {
    QString oldStatus = status_;
    status_ = status;

#ifdef KMESSDEBUG_CONTACT_GENERAL
    kdDebug() << "Contact " << friendlyName_ << " went from " << oldStatus << " to " << status_ << "." << endl;
#endif

    // Signal the UI
    emit changedStatus();

    // Check if the contact went offline
    if( status_ == "FLN" && oldStatus != "FLN" )
    {
#ifdef KMESSDEBUG_CONTACT_GENERAL
      kdDebug() << "Contact went offline." << endl;
#endif
      emit contactOffline( this, showBaloon );
    }
    // Check if the contact went online
    else if( status_ != "FLN" && oldStatus == "FLN" )
    {
      // showNotification is here to avoid showing notification when we connect
#ifdef KMESSDEBUG_CONTACT_GENERAL
      kdDebug() << "Contact went online." << endl;
#endif
      emit contactOnline( this, showBaloon );
    }
  }
}

#include "contact.moc"
