/***************************************************************************
                          accountpage.cpp  -  description
                             -------------------
    copyright            : (C) 2004 by Madelman
                           (C) 2006 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 "accountpage.h"

#include "../dialogs/userpicturesdialog.h"
#include "../utils/kmessconfig.h"
#include "../utils/kmessshared.h"
#include "../kmessdebug.h"
#include "../currentaccount.h"

#include <config-kmess.h>

#include <QFileInfo>

#include <KAction>

#include <KFileDialog>
#include <KIO/NetAccess>
#include <KLocale>
#include <KMenu>
#include <KMessageBox>
#include <KPixmapRegionSelectorDialog>
#include <KStandardDirs>




/**
 * Constructor
 */
AccountPage::AccountPage( QWidget* parent )
: QWidget(parent)
, Ui::AccountPage()
, hasTempPicture_(false)
, userPicturesDialog_(0)
{
  // First setup the user interface
  setupUi( this );

#ifndef HAVE_XSCREENSAVER
  useIdleTimerCheckBox_ ->setEnabled( false );
  idleTimeSpinBox_      ->setEnabled( false );
  idleLabel1_           ->setEnabled( false );
  idleLabel2_           ->setEnabled( false );
#else
  needXScreensaverLabel_->setVisible( false );
#endif

  // Connect the UI signals
  connect( friendlyNameEdit_,  SIGNAL(   textChanged(const QString&)), this,  SLOT(forwardSettingsUpdate()     ) );
  connect( handleEdit_,        SIGNAL(   textChanged(const QString&)), this,  SLOT(forwardSettingsUpdate()     ) );
  connect( noPictureCheckbox_, SIGNAL(       toggled(bool)          ), this,  SLOT(   showPictureToggled(bool) ) );
  connect( registerButton_,    SIGNAL(leftClickedUrl()              ), this,  SLOT( showRegisterPassport()     ) );
  connect( verifyButton_,      SIGNAL(leftClickedUrl()              ), this,  SLOT(   showVerifyPassport()     ) );
  connect( rememberCheckbox_,  SIGNAL(       toggled(bool)          ), this,  SLOT(    rememberMeToggled(bool) ) );

  // Find the default picture
  KStandardDirs *dirs    = KGlobal::dirs();
  QString defaultPicture ( dirs->findResource( "data", "kmess/pics/kmesspic.png" ) );

  // Load the picture in the X-Server:
  defaultPixmap_ = QPixmap(defaultPicture);
  customPixmap_  = defaultPixmap_;

  // Create the "Change..." button actions
  KMenu   *browsePopup   = new KMenu( this );
  KAction *browseSimple  = new KAction( KIcon("folder-open"), i18n("Browse..."),                  this );
  KAction *browseResize  = new KAction( KIcon("edit-cut"),    i18n("Browse and Crop Picture..."), this );
  KAction *setPrevious   = new KAction( KIcon("edit-redo"),   i18n("Set Previous Image..."),     this );
  connect( browseSimple, SIGNAL(activated()), this,  SLOT(pictureBrowseSimple() ) );
  connect( browseResize, SIGNAL(activated()), this,  SLOT(pictureBrowseResize() ) );
  connect( setPrevious,  SIGNAL(activated()), this,  SLOT( pictureSetPrevious() ) );

  // Plug the items into the browse menu button
  browsePopup->addAction( browseSimple );
  browsePopup->addAction( browseResize );
  browsePopup->addAction( setPrevious  );

  // Assign the new popup to the button and detach old connection
  browseButton_->setMenu( browsePopup );
  disconnect( browseButton_, SIGNAL( clicked() ) );

  // Add the items to the initial status combo box
  QStringList states;
  states << i18n("Online")
         << i18n("Away")
         << i18n("Be Right Back")
         << i18n("Busy")
         << i18n("Out to Lunch")
         << i18n("On the Phone")
         << i18n("Invisible");
  initialStatus_->addItems( states );

  // Default the path to the display picture original
  originalPicturePath_ = QString();
}



/**
 * Destructor
 */
AccountPage::~AccountPage()
{
  delete userPicturesDialog_;

  // Clean up the temp file.
  if( hasTempPicture_ )
  {
    QFile::remove( tempPictureFile_ );
  }

  // no need to delete child widgets, Qt does it all for us
}



// Send a signal to the Chat Style page with the new account settings
void AccountPage::forwardSettingsUpdate()
{
  emit settingsUpdated( handleEdit_->text(), friendlyNameEdit_->text(), tempPictureFile_ );
}



// Return the currently entered handle.
const QString AccountPage::getEnteredHandle() const
{
  return handleEdit_->text();
}



// return the entered friendly name.
const QString AccountPage::getEnteredFriendlyName() const
{
  return friendlyNameEdit_->text();
}



/**
 * Load the dialog settings.
 */
void AccountPage::loadSettings( const Account *account, bool isCurrentAccount)
{
  bool showPicture;

  // Read settings
  myHandle_        = account->getHandle();
  pictureFile_     = account->getPicturePath();
  pictureDir_      = KMessConfig::instance()->getAccountDirectory( myHandle_ ) + "/displaypics/";
  tempPictureFile_ = pictureDir_ + "temporary-picture.png";
  showPicture      = account->getShowPicture();
  originalPicturePath_ = account->getOriginalPicturePath();

  // Load default properties
  friendlyNameEdit_ ->setText( account->getFriendlyName( STRING_ORIGINAL ) );
  handleEdit_       ->setText( myHandle_ );
  rememberPasswordCheckBox_->setChecked( account->getSavePassword() );
  passwordEdit_     ->setText( account->getPassword() );

  autologinCheckBox_      ->setChecked( account->getUseAutologin()   );

  useIdleTimerCheckBox_   ->setChecked( account->getUseIdleTimer() );
  idleTimeSpinBox_        ->setValue( account->getIdleTime() );
  hideNotificationsWhenBusyCheckBox_->setChecked( account->getHideNotificationsWhenBusy() );

  // Make sure the drop down list matches the user's initial status
  int item;
  switch( account->getInitialStatus() )
  {
    case STATUS_AWAY:          item = 1; break;
    case STATUS_BE_RIGHT_BACK: item = 2; break;
    case STATUS_BUSY:          item = 3; break;
    case STATUS_INVISIBLE:     item = 6; break;
    case STATUS_ON_THE_PHONE:  item = 5; break;
    case STATUS_OUT_TO_LUNCH:  item = 4; break;
    case STATUS_ONLINE:
    default:                   item = 0; break;
  }
  initialStatus_->setCurrentIndex( item );

  // Show or hide the help links
  if( isCurrentAccount )
  {
    registerLabel_   ->hide();
    registerButton_  ->hide();
    friendlyNameEdit_->setEnabled(   account->isVerified() );
    handleEdit_      ->setEnabled( false );

    // We can only know whether the account is verified when we're logged in
    verifyLabel_     ->setVisible( ! account->isVerified() );
    verifyButton_    ->setVisible( ! account->isVerified() );
  }
  else
  {
    verifyLabel_     ->hide();
    verifyButton_    ->hide();
    friendlyNameEdit_->setEnabled( false );
    handleEdit_      ->setEnabled( true );

    // Only show the Register link when creating new accounts
    bool hasInvalidHandle = ( account->getHandle() == i18n("you@hotmail.com") );
    registerLabel_   ->setVisible( hasInvalidHandle );
    registerButton_  ->setVisible( hasInvalidHandle );
  }

  // When the account is a guest account, offer a method to upgrade to a real account.
  if( account->isGuestAccount() )
  {
    // Disable settings that require a real account which is saved in the config file.
    rememberMeToggled(false);
  }
  else
  {
    // Hide the upgrade function
    rememberCheckbox_->hide();
  }

  // Load the custom pixmap if we have one.
  customPixmap_ = QPixmap( pictureFile_ );

  if( customPixmap_.isNull() )
  {
    // Failed to load
    customPixmap_ = defaultPixmap_;
    pictureFile_  = QString();
  }

  // Load the pixmap
  pictureLabel_->setPixmap(customPixmap_);

  // Set the "Show Picture" checkbox
  // Run the event manually this time to update the GUI.
  noPictureCheckbox_->setChecked( ! showPicture );
  showPictureToggled( ! showPicture );

  // Force update of the preview in the Chat Style settings page
  forwardSettingsUpdate();
}



// Show the normal browse dialog to change display picture
void AccountPage::pictureBrowseSimple()
{
  selectPicture( false );
}



// Show the browse dialog to change display picture and then allow the user to crop it
void AccountPage::pictureBrowseResize()
{
  selectPicture( true );
}



// Show the browse dialog to view the used user images
void AccountPage::pictureSetPrevious()
{
  if( userPicturesDialog_ == 0 )
  {
    userPicturesDialog_ = new UserPicturesDialog();
    connect( userPicturesDialog_,   SIGNAL( pictureUpdate( bool, QString ) ),
             this,                    SLOT( selectPicture( bool, QString ) ) );
  }

  userPicturesDialog_->updateWidgets( myHandle_ );
  userPicturesDialog_->show();
}



/**
 * Save the settings in the account object.
 */
void AccountPage::saveSettings( Account *account )
{
  QString password;
  QString pictureName;
  Status  initialStatus;
  QString newFriendlyName;
  QDir    pictureFolder;
  bool    showPicture;

  // Read settings
  showPicture = ! noPictureCheckbox_->isChecked();

  // Update the picture if we have one. This is done before changing the handle, so the new picture is saved at the old account dir
  // and can be moved to the new one easily
  if( hasTempPicture_ )
  {
    if( ! showPicture )
    {
      // The temporary file is no longer needed.
      QFile::remove( tempPictureFile_ );
      hasTempPicture_ = false;

      // Leaving variable 'pictureName' empty, which means no image is selected
    }
    else
    {
      // Retrieve the picture's hash
      QString msnObjectHash( KMessShared::generateFileHash( tempPictureFile_ ).toBase64() );
      const QString safeMsnObjectHash( msnObjectHash.replace( QRegExp("[^a-zA-Z0-9+=]"), "_" ) );

      // Save the new display picture with its hash as name, to ensure correct caching
      pictureName = msnObjectHash + ".png";
      pictureFolder = QDir( pictureDir_ );

      // Do not overwrite identical pictures
      if( ! pictureFolder.exists( pictureName ) )
      {
        if( pictureFolder.rename( tempPictureFile_, pictureName ) )
        {
          // The temp picture has now its final name, nothing is left to be removed
          hasTempPicture_ = false;
        }
        else
        {
          kmWarning() << "The display picture file could not be renamed from" << tempPictureFile_ << "to" << pictureName << ".";
        }
      }
    }

    // Set the new picture
    account->setPicturePath( pictureDir_ + pictureName );
  }

  // Save path to the display picture original
  account->setOriginalPicturePath( originalPicturePath_ );

  // When the account is a guest account, see if the user wanted to "upgrade" it.

  if( account->isGuestAccount() )
  {
    if( rememberCheckbox_->isChecked() )
    {
      account->setGuestAccount(false);
    }
  }

  // If the account is not verified, don't change the nickname.
  if( ! account->isVerified() )
  {
    newFriendlyName = account->getFriendlyName( STRING_ORIGINAL );
  }
  else
  {
    newFriendlyName = friendlyNameEdit_->text();
  }

  // Update the settings
  account->setLoginInformation( handleEdit_->text(), newFriendlyName, passwordEdit_->text() );
  // Switch option "remember password" to true only if also the password is not empty
  account->setSavePassword( rememberPasswordCheckBox_->isChecked() && ! account->getPassword().isEmpty() );
  // Switch option "autologin" to true only if the option "save password" is true
  account->setUseAutologin( autologinCheckBox_->isChecked() && account->getSavePassword() );
  account->setShowPicture( showPicture );

  // Update the initial status
  switch( initialStatus_->currentIndex() )
  {
    case 1:  initialStatus = STATUS_AWAY;          break;
    case 2:  initialStatus = STATUS_BE_RIGHT_BACK; break;
    case 3:  initialStatus = STATUS_BUSY;          break;
    case 6:  initialStatus = STATUS_INVISIBLE;     break;
    case 5:  initialStatus = STATUS_ON_THE_PHONE;  break;
    case 4:  initialStatus = STATUS_OUT_TO_LUNCH;  break;
    case 0:
    default: initialStatus = STATUS_ONLINE;        break;
  }
  account->setInitialStatus( initialStatus );

  account->setStatusOptions( useIdleTimerCheckBox_->isChecked(), idleTimeSpinBox_->value(),
                             hideNotificationsWhenBusyCheckBox_->isChecked() );

  if ( account->getHandle() == CurrentAccount::instance()->getHandle() )
  {
    CurrentAccount::instance()->copyAccount( account );
  }
}



/**
 * The user toggled the remember me option
 */
void AccountPage::rememberMeToggled(bool noGuest)
{
  autologinCheckBox_->setEnabled( noGuest );
  initialStatus_->setEnabled( noGuest );
}



/*
 * Allow the user to select a picture, and convert it to 96x96, then place it in a temp file.
 */
void AccountPage::selectPicture( bool resize, QString picturePath )
{
  // This code is partially borrowed from Kopete.

  KStandardDirs *dirs   = KGlobal::dirs();
  bool    isRemoteFile  = false;
  KUrl    filePath;
  QString localFilePath;
  QImage  pictureData;

  // Show the open file dialog
  if( picturePath.isEmpty() )
  {
    QString startDir;

    if( ! originalPicturePath_.isEmpty() )
    {
      // Directory where the current display picture is.
      startDir = originalPicturePath_;
    }
    else
    {
      // Search a resourcedir to use as default.

      // all pictures:  dirs->findAllResources("data", "kdm/pics/users/*.png")
      // default dir: dirs->findResource("data", "kdm/pics/users/");

      // Get the resourcedir which contains the largest collection of pictures.
      // This fixes a problem with SuSE, where /etc/opt/kde/share is returned instead of /opt/kde3/share

      const QStringList kdmDirs( dirs->findDirs( "data", "kdm/pics/users/" ) );
      QDir kdmDir;
      int fileCount = 0;

      foreach( const QString& kdmPath, kdmDirs )
      {
        kdmDir.setPath( kdmPath );
        const QStringList pngFiles( kdmDir.entryList( QStringList( "*.png" ) ) );

        if( pngFiles.size() > fileCount )
        {
          fileCount = pngFiles.size();
          startDir = kdmPath;
        }
      }
    }

    filePath = KFileDialog::getImageOpenUrl( startDir, this, i18n( "Display Picture" ) );
  }
  else
  {
    filePath = picturePath;
  }

  if( filePath.isEmpty() )
  {
    return;
  }

  // Save location if the user selected the image.
  if( picturePath.isEmpty() )
  {
    originalPicturePath_ = filePath.pathOrUrl();
  }

  // Read the path.
  if( filePath.isLocalFile() )
  {
    localFilePath = filePath.path();
  }
  else
  {
    // File is remote, download it to a local folder
    // first because QPixmap doesn't have KIO magic.
    // KIO::NetAccess::download fills the localFilePath field.
    if( ! KIO::NetAccess::download(filePath, localFilePath, this ) )
    {
      KMessageBox::sorry( this, i18n( "Downloading of display picture failed" ), i18n("KMess") );
      return;
    }

    isRemoteFile = true;
  }


  // Convert the picture to the correct format.
  // We use a temporary filename first and replace the original if you press OK.
  pictureData = QImage( localFilePath );  // Load picture data

  // Remove any temporary files
  if( isRemoteFile )
  {
    KIO::NetAccess::removeTempFile( localFilePath );
  }

  // Allow the user to select a region of the picture
  if( resize )
  {
    pictureData = KPixmapRegionSelectorDialog::getSelectedImage( QPixmap::fromImage( pictureData ), 96, 96, this );
  }

  // Close the dialog if cancel was clicked
  if( pictureData.isNull() )
  {
    return;
  }

  pictureData = pictureData.scaled( 96, 96, Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation ); // Makes smallest edge 96 pixels, preserving aspect ratio

  if( pictureData.width() != 96 || pictureData.height() != 96 )
  {
    // Copy the middle part of the picture.
    pictureData = pictureData.copy( (pictureData.width() - 96) / 2,  // X
                                    (pictureData.height() - 96) / 2, // Y
                                    96, 96 );
  }

  // Create any missing directories.
  QDir dir;
  const QFileInfo file( tempPictureFile_ );

  if( ! dir.mkpath( file.absolutePath() ) )
  {
    kmWarning() << "Making the account folder failed! Path was" << file.absolutePath();
  }

  if( pictureData.save( tempPictureFile_, "PNG" ) )
  {
    // Sucess! Update the preview picture
    customPixmap_ = QPixmap( tempPictureFile_ );
    pictureLabel_->setPixmap( customPixmap_ );
    hasTempPicture_ = true;
  }
  else
  {
    KMessageBox::sorry( this,
                        i18n( "An error occurred while trying to change the display picture.\n"
                              "Make sure that you have selected an existing image file." ),
                        i18n( "KMess" ) );
  }

  // Signal the update to the settings
  forwardSettingsUpdate();
}



// Slot running when the "Show picture" checkbox was toggled.
void AccountPage::showPictureToggled( bool noPicture )
{
  browseButton_->setEnabled( ! noPicture );
  pictureLabel_->setEnabled( ! noPicture );
}



// The user pressed the "Create new account" button
void AccountPage::showRegisterPassport()
{
  // Launch the browser for the given URL
  KMessShared::openBrowser( KUrl( "https://accountservices.passport.net/reg.srf" ) );
}



// The user pressed the "Send verification email" button
void AccountPage::showVerifyPassport()
{
  // Launch the browser for the given URL
  KMessShared::openBrowser( KUrl( "https://login.live.com/emailval.srf" ) );
}



// Force the page onto a specific tab
void AccountPage::switchToTab( int tabIndex )
{
  if( ( tabIndex < 0 ) || tabIndex > tabWidget_->count() )
  {
    kmWarning() << "Invalid tab index" << tabIndex << "selected!";
    return;
  }

  tabWidget_->setCurrentIndex( tabIndex );
}


#include "accountpage.moc"
