/***************************************************************************
                          currentaccount.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 "currentaccount.h"

#include "contact/contactbase.h"
#include "contact/contact.h"
#include "contact/invitedcontact.h"
#include "model/contactlist.h"
#include "utils/kmessconfig.h"
#include "utils/kmessshared.h"
#include "emoticonmanager.h"
#include "kmess.h"
#include "kmessapplication.h"
#include "kmessdebug.h"

#include <QProcess>
#include <QRegExp>



// Initialize the instance to zero
CurrentAccount* CurrentAccount::instance_(0);

// The constructor
CurrentAccount::CurrentAccount()
 : autoreply_(false),
   contactList_(0),
   externalPort_(0),
   noEmails_(0),
   status_(STATUS_OFFLINE)
{
}



// The destructor
CurrentAccount::~CurrentAccount()
{
#ifdef KMESSDEBUG_CURRENTACCOUNT
  kmDebug() << "DESTROYED.";
#endif

  // Delete all remaining invited contacts
  qDeleteAll( invitedContacts_ );
  invitedContacts_.clear();

  // Unset the instance
  instance_ = 0;
}



// Add an unknown contact to the invited contact list
InvitedContact * CurrentAccount::addInvitedContact( const QString &handle, const QString &friendlyName, const uint capabilities )
{
#ifdef KMESSDEBUG_CURRENTACCOUNT
  kmDebug() << handle;
#endif
#ifdef KMESSTEST
  KMESS_ASSERT( ! handle.isEmpty() );
#endif

  if(getContactByHandle(handle) != 0)
  {
    kmWarning() << "attempted to add contact " << handle << " twice.";
    return 0;
  }

  if(handle.isEmpty())
  {
    return 0;
  }

  // Create the contact
  InvitedContact *contact = new InvitedContact( handle, friendlyName, capabilities );
  invitedContacts_.append( contact );

  // Connect signals.
  // Remove the contact when it left all chats.
  connect( contact, SIGNAL(                    leftAllChats(ContactBase*) ),
           this,    SLOT  (  slotInvitedContactLeftAllChats(ContactBase*) ));

  return contact;
}



// Receive notice that some emails were added or deleted
void CurrentAccount::changeNoEmails( int change )
{
#ifdef KMESSTEST
  int oldNoEmails = noEmails_;
#endif
  setNoEmails( noEmails_ + change );
#ifdef KMESSTEST
  KMESS_ASSERT( ( noEmails_ == (  oldNoEmails + change ) ) || ( noEmails_ == 0 ) );
#endif
}



// Copy an account
void CurrentAccount::copyAccount( const Account *account )
{
  // Do the ancestor's copying
  Account::copyAccount( account );
}



// Delete the instance of the contact list
void CurrentAccount::destroy()
{
  delete instance_;
  instance_ = 0;
}



// Return whether or not to autoreply to messages
bool CurrentAccount::getAutoreply() const
{
  return autoreply_;
}



// Return a contact by handle
ContactBase * CurrentAccount::getContactByHandle(const QString &handle) const
{
  // Return value can't be const, some objects (like ContactFrame)
  // want to connect to the object signals.

  // First see if the contact is listed in our MSN contact list.
  ContactBase *contact = 0;
  if(! KMESS_NULL(contactList_))
  {
    contact = contactList_->getContactByHandle(handle);
  }

  // Next, see if the contact was invited to a chat.
  if(contact == 0)
  {
    contact = getInvitedContactByHandle(handle);
  }

  return contact;
}



// Return a contact's name by handle
QString CurrentAccount::getContactFriendlyNameByHandle( const QString &handle, FormattingMode mode ) const
{
  ContactBase *contact = getContactByHandle( handle );

  if( contact == 0 )
  {
    return QString();
  }

  return contact->getFriendlyName( mode );
}



// Return the contact last dragged
const ContactBase* CurrentAccount::getContactLastDragged() const
{
  // currently a stub
  return 0;
}


// Return the contact list as read-only
const ContactList * CurrentAccount::getContactList() const
{
  return contactList_;
}



// Return the email URL
const QString& CurrentAccount::getEmailUrl() const
{
  return emailUrl_;
}



// Return the external IP
const QString& CurrentAccount::getExternalIp() const
{
  return externalIp_;
}



// Return the external port
uint CurrentAccount::getExternalPort() const
{
  return externalPort_;
}



// Return the language code setted for current account
const QString& CurrentAccount::getLanguageCode() const
{
  return languageCode_;
}



// Find an invited contact by handle
InvitedContact * CurrentAccount::getInvitedContactByHandle(const QString &handle) const
{
  foreach( InvitedContact *contact, invitedContacts_ )
  {
    if( contact->getHandle() == handle )
    {
      return contact;
    }
  }

  return 0;
}



// Return the key for offline im messages
const QString& CurrentAccount::getOfflineImKey() const
{
  return offlineImKey_;
}



// Return the local IP.
const QString& CurrentAccount::getLocalIp() const
{
  return localIp_;
}


// Return the number of email in the inbox
int CurrentAccount::getNoEmails() const
{
  return noEmails_;
}



// Return the user's staus
Status CurrentAccount::getStatus() const
{
  return status_;
}



// Return the requested token
const QString CurrentAccount::getToken( const QString &domain ) const
{
  // Return the requested value or, if not exists, return empty string
  return tokens_.value( domain, "" );
}



// Return the qhash that contain url informations
QHash<QString,QString>& CurrentAccount::getUrlInformation()
{
  return urls_;
}



// Return whether the given contact exists in the contact list.
bool CurrentAccount::hasContactInList(const QString &handle) const
{
  return ( contactList_->getContactByHandle(handle) != 0 );
}



// Return a singleton instance of the current account
CurrentAccount* CurrentAccount::instance()
{
  // If the instance is null, create a new current account and return that.
  if ( instance_ == 0 )
  {
    instance_ = new CurrentAccount();
  }
  return instance_;
}



// Open mail with the given command, url, and folder
void CurrentAccount::openMail( const QString &folder )
{
  KMessShared::openEmailClient( "", folder, getEmailSupported() );
}



// Open email at the compose page with the given contact handle
void CurrentAccount::openMailAtCompose( QString contactHandle )
{
  const QString composeFolder( urls_.value( "COMPOSE" ) );
  KMessShared::openEmailClient( contactHandle, composeFolder, getEmailSupported() );
}



// Open email at the user's inbox
void CurrentAccount::openMailAtInbox()
{
  const QString inboxFolder( urls_.value( "INBOX" ) );
  KMessShared::openEmailClient( "", inboxFolder, getEmailSupported() );
}



// Set some account information
void CurrentAccount::setAccountInformation( QString authorization, QString preferredEmail,
                                            QString sid, QString languageCode, bool emailSupported,
                                            QString externalIp, uint externalPort,
                                            QString localIp)
{
  Q_UNUSED( authorization );

#ifdef KMESSTEST
  bool goodSid;
  sid.toInt(&goodSid);
  KMESS_ASSERT( goodSid );
#endif

  preferredEmail_ = preferredEmail;
  sid_            = sid;
  languageCode_   = languageCode;
  externalIp_     = externalIp;
  externalPort_   = externalPort;
  localIp_        = localIp;

  // protected method call
  setEmailSupported(emailSupported);
}



// Set whether or not to autoreply to a contact's chat message.
void CurrentAccount::setAutoreply(bool autoreply)
{
  autoreply_ = autoreply;
}



// Store the contact list, maintained by the MsnNotificationConnection class.
// Allows other classes to access the contact list from this central class.
void CurrentAccount::setContactList(const ContactList *contactList)
{
  contactList_ = contactList;
}



// Set initial email information
void CurrentAccount::setInitialEmailInformation( int noEmailsInInbox, int noEmailsInOtherFolders )
{
#ifdef KMESSTEST
  KMESS_ASSERT( noEmails_ == 0 );
  KMESS_ASSERT( noEmailsInInbox >= 0 );
  KMESS_ASSERT( noEmailsInOtherFolders >= 0 );
#else
  Q_UNUSED( noEmailsInOtherFolders ); // Avoid compiler warning
#endif

  setNoEmails( noEmailsInInbox );
}



// Set the key for offline im messages
void CurrentAccount::setOfflineImKey( const QString &key )
{
  offlineImKey_ = key;
}



// Set the email post url
void CurrentAccount::setEmailUrl( QString postUrl )
{
  emailUrl_ = postUrl;
}



// Set the number of emails
void CurrentAccount::setNoEmails( int noEmails )
{
#ifdef KMESSTEST
  KMESS_ASSERT( noEmails >= 0 );
#endif
  noEmails_ = noEmails;
  if ( noEmails_ < 0 )
  {
    noEmails_ = 0;
  }
  emit changedNoEmails();
}



// Set the user's status
void CurrentAccount::setStatus( Status status )
{
  // Apply the status change
  Status oldStatus = status_;
  status_ = status;

  // If there are no real changes in the user's status, end now
  if( status_ == oldStatus )
  {
    return;
  }

#ifdef KMESSDEBUG_CURRENTACCOUNT
  kmDebug() << "Status set to " << MsnStatus::getCode( status_ ) << ".";
#endif

  emit changedStatus();

  // Check if the contact went offline
  if( status_ == STATUS_OFFLINE )
  {
#ifdef KMESSDEBUG_CURRENTACCOUNT
    kmDebug() << "Account went offline.";
#endif
    emit accountOffline();
  }
  // Check if the account went invisible
  if( status == STATUS_INVISIBLE )
  {
#ifdef KMESSDEBUG_CURRENTACCOUNT
    kmDebug() << "Account went invisible.";
#endif
    emit accountInvisible();
  }
  // Check if the contact went online
  else if( oldStatus == STATUS_OFFLINE || oldStatus == STATUS_INVISIBLE )
  {
#ifdef KMESSDEBUG_CURRENTACCOUNT
    kmDebug() << "Account went online.";
#endif
    emit accountOnline();
  }
}



// Set the tokens
void CurrentAccount::setTokens( const QHash<QString,QString> tokens )
{
  tokens_ = tokens;
}



// An invited contact left all chats.
void CurrentAccount::slotInvitedContactLeftAllChats( ContactBase *contact )
{
  if(KMESS_NULL(contact)) return;
#ifdef KMESSDEBUG_CURRENTACCOUNT
  kmDebug() << "invited contact " << contact->getHandle() << " left all chats, delete contact.";
#endif

  // Remove from list
  bool removed = invitedContacts_.removeAll( static_cast<InvitedContact*>( contact ) ) > 0;
  if( ! removed )
  {
    kmWarning() << "could not remove invited contact '" << contact->getHandle() << "' from the list!";
  }

  // Delete after all slots are processed.
  contact->deleteLater();
}



#include "currentaccount.moc"
