/***************************************************************************
                          accountsettingsdialog.cpp  -  description
                             -------------------
    begin                : Sat Jan 11 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 "accountsettingsdialog.h"

#include "../network/chatmessage.h"
#include "../utils/kmessconfig.h"
#include "../accountsmanager.h"
#include "../account.h"
#include "../currentaccount.h"
#include "../emoticonmanager.h"
#include "../kmess.h"
#include "../kmessapplication.h"
#include "../kmessdebug.h"
#include "accountpage.h"
#include "contactlistpage.h"
#include "chatloggingpage.h"
#include "chatstylepage.h"
#include "emoticonspage.h"

#include <QCloseEvent>
#include <QShowEvent>

#include <KMessageBox>



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



// The constructor
AccountSettingsDialog::AccountSettingsDialog( QWidget *parent )
: KPageDialog( parent )
, account_(0)
, initialPage_( PageAccount )
{
  // Open the config group we'll use throughout the class
  config_ = KMessConfig::instance()->getGlobalConfig( "AccountSettingsDialog" );

  // Set up the dialog box
  setObjectName( "AccountSettings" );
  setButtons( Help | Ok | Apply | Cancel | User1 );
  setHelp( "settings-account" );
  setButtonText( User1, i18n( "&Delete" ) );
  setDefaultButton( Ok );
  setCaption( i18n("Settings") );
  restoreDialogSize( config_ );

  // Create the widgets that belong in the pages
  accountPage_     = new AccountPage();
  contactListPage_ = new ContactListPage();
  chattingPage_    = new ChatStylePage();
  chatLoggingPage_ = new ChatLoggingPage();
  emoticonPage_    = new EmoticonsPage();

  // Connect the account page signal to update the chatting page preview
  connect( accountPage_, SIGNAL(      settingsUpdated(const QString&,const QString&,const QString&) ),
           chattingPage_,   SLOT( updatePreviewDetails(const QString&,const QString&,const QString&) ) );

  // Add the pages to the dialog and set them up
  KPageWidgetItem *page;

  page = addPage( accountPage_, i18n("Account") );
  page->setHeader( i18n( "My Account" ) );
  page->setIcon( KIcon( "user-identity" ) );
  pageWidgets_.insert( PageAccount, page );
  pageWidgets_.insert( PageAccountStatus, page );

  page = addPage( contactListPage_, i18n("Contact List") );
  page->setHeader( i18n( "Contact List" ) );
  page->setIcon( KIcon( "view-list-details" ) );
  pageWidgets_.insert( PageContactList, page );

  page = addPage( emoticonPage_, i18n("Emoticons") );
  page->setHeader( i18n( "Emoticons" ) );
  page->setIcon( KIcon( "emoticons" ) );
  pageWidgets_.insert( PageEmoticons, page );
  pageWidgets_.insert( PageEmoticonsTabCustom, page );

  page = addPage( chattingPage_, i18n("Chatting") );
  page->setHeader( i18n( "Chatting" ) );
  page->setIcon( KIcon( "format-stroke-color" ) );  // preferences-desktop-color, insert-text?
  pageWidgets_.insert( PageChatStyle, page );
  pageWidgets_.insert( PageChatStyleTabText, page );

  page = addPage( chatLoggingPage_, i18n("Chat Logging") );
  page->setHeader( i18n( "Chat Logging" ) );
  page->setIcon( KIcon( "document-save-as" ) );
  pageWidgets_.insert( PageChatLogging, page );
}



// The destructor
AccountSettingsDialog::~AccountSettingsDialog()
{
  // Save the window size before deleting it
  saveDialogSize( config_ );

  pageWidgets_.clear();

  instance_ = 0;

#ifdef KMESSDEBUG_ACCOUNTSETTINGSDIALOG
  kmDebug() << "DESTROYED.";
#endif
}



// Load the settings for the given account
void AccountSettingsDialog::loadSettings( Account *account, bool isCurrentAccount, Page initialPage )
{
  account_ = account;

  if( account == 0 )
  {
    kmWarning() << "Invalid account given!";
    return;
  }

  // Load account information into the widgets
  accountPage_    ->loadSettings( account, isCurrentAccount );
  contactListPage_->loadSettings( account );
  chattingPage_   ->loadSettings( account );
  chatLoggingPage_->loadSettings( account );
  emoticonPage_   ->loadSettings( account );

  // Disable the "remove account" button for guest accounts and for
  // the current account
  KMessApplication *kmessApp = static_cast<KMessApplication*>( kapp );
  if( account->isGuestAccount()
  ||  (  CurrentAccount::instance()->getHandle() == account->getHandle()
      && kmessApp->getContactListWindow()->isConnected() ) )
  {
    enableButton( KDialog::User1, false );
    setButtonToolTip( KDialog::User1,
                      i18nc( "Button tooltip text",
                             "Click here to delete this account from the "
                             "list of registered accounts.\nYou cannot delete "
                             "the currently connected account nor a guest account, "
                             "which will be deleted when you disconnect." ) );
  }

  // Save the initial page for later, when the dialog is actually shown
  initialPage_ = initialPage;
}



// Save options before closing.
void AccountSettingsDialog::closeEvent( QCloseEvent *event )
{
  saveDialogSize( config_ );
  event->accept();
}



// Return a singleton instance of the settings dialog window
AccountSettingsDialog* AccountSettingsDialog::instance( QWidget *parent )
{
  // If the instance is null, create a new dialog and return that.
  if ( instance_ == 0 )
  {
    instance_ = new AccountSettingsDialog( parent );
  }

  return instance_;
}



// Save all widget settings
bool AccountSettingsDialog::saveAccountSettings()
{
  if( account_ == 0 )
  {
    return false;
  }

  // Save the old handle and name to check if they were changed later
  QString oldHandle       ( account_->getHandle() );
  QString newHandle       ( accountPage_->getEnteredHandle() );
  QString oldFriendlyName ( account_->getFriendlyName( STRING_ORIGINAL ) );

  // Make sure the account handle was changed off the default
  if( newHandle.isEmpty() || ! Account::isValidEmail( newHandle )
  ||  newHandle == i18n( "you@hotmail.com" ) )
  {
    KMessageBox::error( 0, i18n( "The email address you have entered is not valid, and cannot be used as an account: '%1'", newHandle ) );
    return false;
  }

  // Also verify that the account name is not already listed
  if( oldHandle != newHandle
  && AccountsManager::instance()->getAccountByHandle( newHandle ) != 0 )
  {
    KMessageBox::error( 0, i18n( "The email address you have entered is already in use: '%1'", newHandle ) );
    return false;
  }

  if ( accountPage_->getEnteredFriendlyName().trimmed().isEmpty() )
  {
    KMessageBox::error( 0, i18n( "Please enter a friendly name for this account." ) );
    setCurrentPage( pageWidgets_.at( PageAccount ) );
    return false;
  }

  // Save information from the widgets
  accountPage_    ->saveSettings( account_ );
  contactListPage_->saveSettings( account_ );
  chattingPage_   ->saveSettings( account_ );
  chatLoggingPage_->saveSettings( account_ );
  emoticonPage_   ->saveSettings( account_ );

  // if we're changing the currently connected account then our stored Account instance will
  // actually be a CurrentAccount instance (see accountsmanager.cpp:703).
  // in this case we must copy the changes back to the real Account object in the accountsmanager,
  // otherwise there will be stale data.
  // TODO: This feels really bad. Hopefully we can fix this ugliness in 2.1
  if ( account_ == CurrentAccount::instance() )
  {
    Account *realAccount = AccountsManager::instance()->getAccountByHandle( account_->getHandle() );
    realAccount->copyAccount( account_ );
  }

  // Let the Accounts Manager know the settings have changed. It will also make sure
  // that the updated settings get synced to disk.
  emit changedSettings( account_, oldHandle, oldFriendlyName );

  return true;
}



// Select the Account page when showing the settings dialog
void AccountSettingsDialog::showEvent( QShowEvent */*event*/ )
{
  // After the first switch (happening when the window is first shown)
  // we'll keep whichever page the user has currently selected
  if( initialPage_ == PageNone )
  {
    return;
  }

  // Switch the dialog to the specified page
  setCurrentPage( pageWidgets_.at( initialPage_ ) );

  // Switch to the tabs other than the first if needed
  if( initialPage_ == PageEmoticonsTabCustom )
  {
    emoticonPage_->switchToTab( 1 );
  }
  else if( initialPage_ == PageChatStyleTabText )
  {
    chattingPage_->switchToTab( 1 );
  }
  else if ( initialPage_ == PageAccountStatus )
  {
    accountPage_->switchToTab( 1 );
  }

  initialPage_ = PageNone;
}



// A button has been pressed, act accordingly
void AccountSettingsDialog::slotButtonClicked( int button )
{
  switch( button )
  {
    case KDialog::Ok:
      if( ! saveAccountSettings() )
      {
        return;
      }

      accept();
      break;

    case KDialog::Apply:
      saveAccountSettings();

      // Do not delete the dialog, we still need it
      return;
      break;

    case KDialog::Cancel:
    case KDialog::Close:
      reject();
      break;

    case KDialog::User1:
      // Delete the account, but first ask the user for confirmation
      if( KMessageBox::warningYesNo( this, i18n("Are you sure you want to delete this account?") ) == KMessageBox::Yes )
      {
        emit deleteAccount( account_ );
        reject();
      }
      else
      {
        // Do not delete the dialog, we still need it
        return;
      }
      break;

    default:
      KDialog::slotButtonClicked( button );
      break;
  }

  // Schedule the dialog for deletion, to save memory
  // if we've been hidden then "Ok" or "Close" has been chosen 
  // in which case we can delete ourselves.
  if ( ! isVisible() )
  {
    deleteLater();
  }
}



#include "accountsettingsdialog.moc"
