/*
**************************************************************************
                                 description
                             --------------------
    copyright            : (C) 2001-2002 by Andreas Zehender
    email                : zehender@kde.org
**************************************************************************

**************************************************************************
*                                                                        *
*  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 "pmpovraywidget.h"
#include "pmpovrayrenderwidget.h"
#include "pmpovrayoutputwidget.h"
#include "pmshell.h"

#include <klocale.h>
#include <kmessagebox.h>
#include <kimageio.h>
#include <kfiledialog.h>
#include <ktemporaryfile.h>
#include <kio/netaccess.h>
#include <kglobalsettings.h>
#include <kpushbutton.h>
#include <KStandardGuiItem>
#include <qlayout.h>
#include <QProgressBar>
#include <qlabel.h>
#include <q3scrollview.h>
#include <qtimer.h>
#include <qapplication.h>
//Added by qt3to4:
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QImageWriter>
const int timerIntervall = 1000;
bool PMPovrayWidget::s_imageFormatsRegistered = false;

PMPovrayWidget::PMPovrayWidget( QWidget* parent )
      : KDialog( parent )
{
	QWidget* c = new QWidget( this );
   QVBoxLayout* topLayout = new QVBoxLayout( c );
   topLayout->setSpacing( KDialog::spacingHint( ) );
   topLayout->setMargin( 0 );
   topLayout->addStretch( );

   QHBoxLayout* renderLayout = new QHBoxLayout( );
   topLayout->addLayout( renderLayout, 2 );
   m_pScrollView = new Q3ScrollView( c );
   renderLayout->addWidget( m_pScrollView, 2 );
   m_pRenderWidget = new PMPovrayRenderWidget( m_pScrollView->viewport( ) );
   m_pRenderWidget->setFixedSize( 200, 200 );
   m_pScrollView->addChild( m_pRenderWidget );
   topLayout->addStretch( );

   QHBoxLayout* progressLayout = new QHBoxLayout( );
   topLayout->addLayout( progressLayout );
   m_pProgressBar = new QProgressBar( c );
   m_pProgressBar->hide( );
   progressLayout->addWidget( m_pProgressBar, 1 );
   m_pProgressLabel = new QLabel( c );
   progressLayout->addWidget( m_pProgressLabel, 2 );

   QHBoxLayout* buttonLayout = new QHBoxLayout( );
   topLayout->addLayout( buttonLayout );
   m_pStopButton = new QPushButton( i18n( "Stop" ), c );
   m_pStopButton->setEnabled( false );
   buttonLayout->addWidget( m_pStopButton );
   m_pSuspendButton = new QPushButton( i18n( "Suspend" ), c );
   m_pSuspendButton->setEnabled( false );
   buttonLayout->addWidget( m_pSuspendButton );
   m_pResumeButton = new QPushButton( i18n( "Resume" ), c );
   m_pResumeButton->setEnabled( false );
   buttonLayout->addWidget( m_pResumeButton );
   buttonLayout->addStretch( 1 );
   m_pPovrayOutputButton = new QPushButton( i18n( "Povray Output" ), c );
   buttonLayout->addWidget( m_pPovrayOutputButton );

   buttonLayout = new QHBoxLayout( );
   topLayout->addLayout( buttonLayout );
   m_pSaveButton = new KPushButton( KStandardGuiItem::saveAs(), c );
   m_pSaveButton->setEnabled( false );
   buttonLayout->addWidget( m_pSaveButton );
   buttonLayout->addStretch( 1 );
   QPushButton* closeButton = new KPushButton( KStandardGuiItem::close(), c );
   buttonLayout->addWidget( closeButton );

	setMainWidget( c );
	setButtons( 0 );
	setWindowModality( Qt::NonModal );
	
   connect( m_pRenderWidget, SIGNAL( finished( int ) ),
            SLOT( slotRenderingFinished( int ) ) );
   connect( m_pRenderWidget, SIGNAL( progress( int ) ),
            SLOT( slotProgress( int ) ) );
   connect( m_pRenderWidget, SIGNAL( lineFinished( int ) ),
            SLOT( slotLineFinished( int ) ) );

   connect( m_pStopButton, SIGNAL( clicked( ) ), SLOT( slotStop( ) ) );
   connect( m_pSuspendButton, SIGNAL( clicked( ) ), SLOT( slotSuspend( ) ) );
   connect( m_pResumeButton, SIGNAL( clicked( ) ), SLOT( slotResume( ) ) );
   connect( m_pSaveButton, SIGNAL( clicked( ) ), SLOT( slotSave( ) ) );
   connect( closeButton, SIGNAL( clicked( ) ), SLOT( slotClose( ) ) );
   connect( m_pPovrayOutputButton, SIGNAL( clicked( ) ),
            SLOT( slotPovrayOutput( ) ) );

   m_bRunning = false;
   m_pProgressTimer = new QTimer( this );
   connect( m_pProgressTimer, SIGNAL( timeout( ) ),
            SLOT( slotUpdateSpeed( ) ) );
   m_pProgressTimer->setSingleShot( true );
   setCaption( i18n( "Render Window" ) );

   m_height = m_width = 0;
   m_stopped = false;

   m_pPovrayOutputWidget = new PMPovrayOutputWidget( );
   connect( m_pRenderWidget, SIGNAL( povrayMessage( const QString& ) ),
            m_pPovrayOutputWidget, SLOT( slotText( const QString& ) ) );
}

PMPovrayWidget::~PMPovrayWidget( )
{
   delete m_pPovrayOutputWidget;
}

bool PMPovrayWidget::render( const QByteArray& scene, const PMRenderMode& m,
                             const KUrl& documentURL )
{
   bool updateSize = ( m_height != m.height( ) ) || ( m_width != m.width( ) );
   m_height = m.height( );
   m_width = m.width( );
   m_bRunning = false;
   m_pPovrayOutputWidget->slotClear( );
   m_stopped = false;

   m_pRenderWidget->setFixedSize( m_width, m_height );
   QSize maxSize( m_width + m_pScrollView->frameWidth( ) * 2,
                  m_height + m_pScrollView->frameWidth( ) * 2 );
   m_pScrollView->setMaximumSize( maxSize );

   if( updateSize )
   {
      int w, h;

      w = maxSize.width( ) + KDialog::spacingHint( ) * 2;
      h = maxSize.height( ) + m_pSaveButton->sizeHint( ).height( ) * 2
         + KDialog::spacingHint( ) * 6;
      if( m_pProgressLabel->sizeHint( ).height( )
          > m_pProgressBar->sizeHint( ).height( ) )
         h += m_pProgressLabel->sizeHint( ).height( );
      else
         h += m_pProgressBar->sizeHint( ).height( );

      w += 16;
      h += 16;

      QRect dw = KGlobalSettings::desktopGeometry(this);
      if( w > dw.width() )
         w = dw.width();
      if( h > dw.height() )
         h = dw.height();

      resize( w, h );
   }

   if( m_pRenderWidget->render( scene, m, documentURL ) )
   {
      m_bRunning = true;
      m_pProgressBar->setValue( 0 );
      m_pProgressBar->show( );
      m_pProgressLabel->setText( i18n( "running" ) );
      m_pStopButton->setEnabled( true );
      m_pSuspendButton->setEnabled( true );
      m_pResumeButton->setEnabled( false );
      m_pSaveButton->setEnabled( false );

      m_lastSpeedTime = QTime( );
      //m_pProgressTimer->setSingleShot( true );
      m_pProgressTimer->start( timerIntervall );
      m_speedInfo = false;
      m_speed = 0;
      m_line = 0;
      m_immediateUpdate = false;
      showSpeed( 0 );
   }

   return m_bRunning;
}

void PMPovrayWidget::slotStop( )
{
   m_stopped = true;
   m_pRenderWidget->killRendering( );
   m_pSaveButton->setEnabled( true );
}

void PMPovrayWidget::slotSuspend( )
{
   m_pRenderWidget->suspendRendering( );
   m_pSuspendButton->setEnabled( false );
   m_pResumeButton->setEnabled( true );
   m_pSaveButton->setEnabled( true );

   m_pProgressTimer->stop( );
   m_lastSpeedTime = QTime( );
   m_speedInfo = false;
   m_immediateUpdate = false;
   m_pProgressLabel->setText( i18n( "suspended" ) );
}

void PMPovrayWidget::slotResume( )
{
   m_pRenderWidget->resumeRendering( );
   m_pSuspendButton->setEnabled( true );
   m_pResumeButton->setEnabled( false );
   m_pSaveButton->setEnabled( false );
   m_pProgressTimer->start( timerIntervall );
   showSpeed( m_speed );
}

void PMPovrayWidget::slotClose( )
{
   hide( );
}

void PMPovrayWidget::slotSave( )
{
   KTemporaryFile* tempFile = 0;
   QFile* file = 0;
   bool ok = true;

   if( !s_imageFormatsRegistered )
   {

      s_imageFormatsRegistered = true;
   }

   KUrl url = KFileDialog::getSaveUrl( KUrl( ), KImageIO::pattern( KImageIO::Writing ) );
   if( url.isEmpty( ) )
      return;
   if( !PMShell::overwriteURL( url ) )
      return;

   if( !url.isValid( ) )
   {
      KMessageBox::error( this, i18n( "Malformed URL" ) );
      return;
   }

#ifdef __GNUC__
#warning is this really needed?
#endif
   QString suffix = url.fileName().toUpper();
   if (suffix.lastIndexOf('.') >= 0)
     suffix = suffix.mid(suffix.lastIndexOf('.'));

   QString format;

   if (QImageWriter::supportedImageFormats().contains(suffix.toLatin1()))
      format = suffix;

   if( format.isEmpty( ) )
   {
      KMessageBox::error( this, i18n( "Unknown image format.\n"
                                      "Please enter a valid suffix." ) );
      return;
   }

   if( !KImageIO::types( ).contains(format) )
   {
      KMessageBox::error( this, i18n( "Format is not supported for writing." ) );
      return;
   }

   if( url.isLocalFile( ) )
   {
      // Local file
      file = new QFile( url.path( ) );
      if( !file->open( QIODevice::WriteOnly ) )
         ok = false;
   }
   else
   {
      // Remote file
      // provide a temp file
      tempFile = new KTemporaryFile( );
      if( !tempFile->open() )
         ok = false;
      else
         file = tempFile;
   }

   if( ok )
   {
      QImageWriter iio( file, format.toLatin1() );
      ok = iio.write(m_pRenderWidget->image( )  );

      if( ok )
      {
         if( tempFile )
         {
            tempFile->flush( );
            ok = KIO::NetAccess::upload( tempFile->fileName( ), url,this );
            file = 0;
         }
         else
            file->close( );
      }
      else
         KMessageBox::error( this, i18n( "Could not correctly write the image.\n"
                                         "Wrong image format?" ) );
   }
   else
      KMessageBox::error( this, i18n( "Could not write the image.\n"
                                      "Permission denied." ) );


   delete file;
   if (file != tempFile)
      delete tempFile;
}

void PMPovrayWidget::slotPovrayOutput( )
{
   m_pPovrayOutputWidget->show( );
}

void PMPovrayWidget::slotRenderingFinished( int returnStatus )
{
   kDebug( PMArea ) << "Povray exited with status " << returnStatus;
   m_bRunning = false;
   if( returnStatus == 0 )
      m_pSaveButton->setEnabled( true );
   m_pStopButton->setEnabled( false );
   m_pSuspendButton->setEnabled( false );
   m_pResumeButton->setEnabled( false );
   m_pProgressLabel->setText( i18n( "finished" ) );
   m_pProgressTimer->stop( );

   if( ( returnStatus != 0 ) && !m_stopped )
   {
      KMessageBox::error( this, i18n( "Povray exited abnormally (%1).\n"
                                      "See the povray output for details." ,
                            returnStatus ) );
   }
   else if( m_pRenderWidget->povrayOutput( ).contains( "ERROR" ) )
   {
      KMessageBox::error( this, i18n( "There were errors while rendering.\n"
                                      "See the povray output for details." ) );
   }
}

void PMPovrayWidget::slotProgress( int i )
{
   m_pProgressBar->setValue( i );
}

void PMPovrayWidget::slotLineFinished( int line )
{
   m_speedInfo = true;
   QTime ct = QTime::currentTime( );

   if( !m_lastSpeedTime.isNull( ) )
   {
      int msecs = m_lastSpeedTime.msecsTo( ct );
      if( msecs < 1 )
         msecs = 1;

      double g = 1.0 / ( ( double ) msecs / 500.0 + 1.0 );
      m_speed = g * m_speed +
                1000 * ( 1.0 - g ) * m_width * ( line - m_line ) / msecs;
   }

   if( m_immediateUpdate )
   {
      m_immediateUpdate = false;
      showSpeed( m_speed );
      m_pProgressTimer->start( timerIntervall );
      m_speedInfo = false;
   }

   m_lastSpeedTime = ct;
   m_line = line;
}

void PMPovrayWidget::slotUpdateSpeed( )
{
   if( m_speedInfo )
   {
      showSpeed( m_speed );
      m_pProgressTimer->start( timerIntervall );
      m_speedInfo = false;
   }
   else
      m_immediateUpdate = true;
}

void PMPovrayWidget::showSpeed( double pps )
{
   QString num;
   if( pps >= 1000000 )
   {
      num.setNum( pps / 100000, 'g', 3 );
      num += 'M';
   }
   else if( pps >= 1000 )
   {
      num.setNum( pps / 1000, 'g', 3 );
      num += 'K';
   }
   else
      num.setNum( pps, 'g', 3 );

   m_pProgressLabel->setText( i18n( "running, %1 pixels/second", num ) );
}

#include "pmpovraywidget.moc"
