/***************************************************************************
                          transferentry.cpp  -  description
                             -------------------
    begin                : Wed Nov 3 2004
    copyright            : (C) 2004 by Diederik van der Boor
    email                : 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 "transferentry.h"

#include "../kmessdebug.h"

#include <QPixmap>

#include <KLocale>
#include <KRun>
#include <KIconLoader>
#include <KMimeType>
#include <KUrl>



// Constructor
TransferEntry::TransferEntry( QWidget *parent, const QString filename, const ulong filesize,
                              bool incoming, const QImage preview)
: QWidget( parent ),
 Ui::TransferEntry(),
 isDone_(false),
 incoming_(incoming),
 filename_(filename),
 filesize_(filesize),
 previousPercentage_(-1),
 previousTransferred_(0),
 transferID_(-1)
{
  // Set up the user interface
  setupUi( this );

  // Get the preview from the caller
  preview_ = QPixmap::fromImage( preview );

#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "Initializing, file='" << filename_
            << "', preview=" << ( preview_.isNull() ? "null" : "set" ) << "." << endl;
#endif

  KIconLoader *loader = KIconLoader::global();

  // Set pixmap and filename
  if( preview_.isNull() )
  {
    // Get a default icon pixmap
    QString      iconTitle( KMimeType::iconNameForUrl( KUrl( filename_) ) );
    preview_               = loader->loadIcon( iconTitle, KIconLoader::NoGroup, iconLabel_->width() );

    if( ! preview_.isNull() )
    {
      iconLabel_->setPixmap( preview_ );
    }
  }
  else
  {
    // Scale down if needed. Don't scale large images up
    if( preview_.width()  > iconLabel_->width()
    ||  preview_.height() > iconLabel_->height() )
    {
      preview_ = preview_.scaled( iconLabel_->width(), iconLabel_->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation );
    }

    iconLabel_->setPixmap( preview_ );
  }

  filenameLabel_->setText("<b>" + filename_ + "</b>");

  QPixmap pixmapTransfer;
  // Enable urls?
  if(incoming_)
  {
    // Can't open it yet.
    openLabel_->hide();
    openLabel_->setEnabled(false);
    pixmapTransfer = loader->loadIcon( "go-down", KIconLoader::Small );
  }
  else
  {
    pixmapTransfer = loader->loadIcon( "go-up", KIconLoader::Small );
  }

  cancelLabel_->setEnabled(true);
  iconTransferLabel_->setPixmap( pixmapTransfer );

  // Set the timer to update the transfer rate and eta
  timer_ = new QTimer();
  connect( timer_ , SIGNAL( timeout() ), this, SLOT( updateTransferRate() ) );
}



// Destructor
TransferEntry::~TransferEntry()
{
#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "DESTROYED. [file=" << filename_ << "]";
#endif
  delete timer_;
}



// Called when cancel is clicked.
void TransferEntry::cancelClicked()
{
#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "Notifying listeners.";
#endif

  emit cancelTransfer( transferID_ );

  if(! isDone_)
  {
    // If a slot didn't call failTransfer(),
    // we do this with the correct (!) status message.
    failTransfer( i18n("Cancelled") );
  }
}



// Indicate the transfer is complete or cancelled.
bool TransferEntry::isDone() const
{
  return isDone_;
}



// Returns true if the transfer is incoming
bool TransferEntry::isIncoming() const
{
  return incoming_;
}



// Return the file name
QString TransferEntry::getFileName() const
{
  return filename_;
}



// Mark the transfer as failed
void TransferEntry::failTransfer( const QString &message )
{
  if( isDone_ )
  {
#ifdef KMESSDEBUG_TRANSFERENTRY
    kmDebug() << "already done.";
#endif
    return;
  }

#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "Displaying error message.";
#endif

  // Update the widgets
  if(message == 0 || message.isEmpty())
  {
    statusLabel_->setText( i18n("Failed!") );
  }
  else
  {
    statusLabel_->setText( message );
  }

  timer_->stop();

  // Make sure the widget does not resize when the progressbar hides
  setMinimumHeight( height() );

  progressBar_->hide();
  cancelLabel_->setEnabled(false);
  cancelLabel_->hide();

  isDone_ = true;
}



// Mark the transfer as complete
void TransferEntry::finishTransfer()
{
#ifdef KMESSTEST
  KMESS_ASSERT( ! isDone_ );
#endif

  if( isDone_ )
  {
#ifdef KMESSDEBUG_TRANSFERENTRY
    kmDebug() << "already done.";
#endif
    return;
  }

#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "Displaying success message.";
#endif

  // Make sure the widget does not resize when the progressbar hides
  setMinimumHeight( height() );

  // Update the widgets
  statusLabel_->setText( i18n("Completed") );

  progressBar_->hide();
  cancelLabel_->setEnabled(false);
  cancelLabel_->hide();
  openLabel_  ->setEnabled(true);
  openLabel_  ->show();
  timer_      ->stop();

  isDone_ = true;
}



// Called when open is clicked
void TransferEntry::openClicked()
{
  // The file:// prefix must be followed by a full path
  if( ! filename_.startsWith( "file://" ) )
  {
    new KRun( "file://" + filename_, window() );
  }
  else
  {
    new KRun( filename_, window() );
  }
}



// Set the transfer ID to identify ourselves to the Transfer Window
void TransferEntry::setTransferID( int transferID )
{
  transferID_ = transferID;
}



// Convert a string to some more readable form
QString TransferEntry::toReadableBytes( ulong bytes )
{
  QString format;
  if(bytes > 1048576)
  {
    // Using '%.2f' instead of '%.1f' removes the ".0" part, but it's less pretty.
    format.sprintf("%.1f", (double) bytes / 1048576.0);
    return i18n( "%1 MB", format );
  }
  else if(bytes > 1024)
  {
    format.sprintf("%.1f", (double) bytes / 1024.0);
    return i18n( "%1 kB", format );
  }
  else
  {
    return i18n( "%1 bytes", bytes );
  }
}


// Set a status message
void TransferEntry::setStatusMessage( const QString &message )
{
#ifdef KMESSTEST
  KMESS_ASSERT( ! isDone_ );
#endif

  if( isDone_ )
  {
#ifdef KMESSDEBUG_TRANSFERENTRY
    kmDebug() << "already done.";
#endif
    return;
  }

#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "displaying '" << message << "'.";
#endif

  statusLabel_->setText( message );
}



// Update the progress bar
void TransferEntry::updateProgress( ulong bytesTransferred )
{
#ifdef KMESSTEST
  KMESS_ASSERT( ! isDone_ );
#endif

  if( isDone_ )
  {
#ifdef KMESSDEBUG_TRANSFERENTRY
    kmDebug() << "already done.";
#endif
    return;
  }

  // Start the ETA timer if it hasn't already
  if( ! timer_->isActive() )
  {
    timer_->start( 3000 );
  }

  bytesTransferred_ = bytesTransferred;

  int percent = (int) ( ( (double) bytesTransferred * 100.0 ) / (double) filesize_ );
  QString transferred( toReadableBytes( bytesTransferred ) );
  QString total      ( toReadableBytes( filesize_ ) );

  // Avoid useless repaints
  if( ! ( percent == previousPercentage_ ) )
  {
    previousPercentage_ = percent;
    progressBar_->setValue( percent );
  }

#ifdef KMESSDEBUG_TRANSFERENTRY
  kmDebug() << "transfer is at " << ((float)percent/10) << " percent.";
#endif

  if( incoming_ )
  {
    statusText_ = i18n( "%1 of %2 received.", transferred, total );
  }
  else
  {
    statusText_ = i18n( "%1 of %2 sent.", transferred, total );
  }

  statusLabel_->setText( statusText_ + " " + speedText_ );
}



// Update the transfer rate and ETA
void TransferEntry::updateTransferRate()
{
  // To avoid to works with different transferred bytes
  ulong tempTransferred = bytesTransferred_;

  // Calculate the bytes transferred from the last calling
  ulong bytesTransferredFromLast =  tempTransferred - previousTransferred_;

  QString speed, eta;

  // Approximate the speed with the timeout of timer (3)
  int bytesSpeed = (int)( bytesTransferredFromLast / 3 );
  int currentEta;

  // Verify if the bytesSpeed is 0
  if( ! ( bytesSpeed == 0 ) )
  {
    currentEta = (int) ( ( filesize_ - tempTransferred ) / bytesSpeed );
    QTime timeEta;
    eta = timeEta.addSecs( currentEta ).toString();
    previousTransferred_ = tempTransferred;
  }
  else
  {
    // Is impossible to calculate ETA
    eta = i18n( "infinite" );
  }

  speedText_ = QString("Speed: %1, ETA: %2").arg( toReadableBytes( bytesSpeed ) ).arg( eta );

  statusLabel_->setText( statusText_ + " " + speedText_ );
}

#include "transferentry.moc"
