/*
    Copyright (C) 2000 - 2001 Kai Heitkamp, kai@kde.org
    aRts parts Copyright (C) 2000 Stefan Westerfeld, stefan@space.twc.de

    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.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 */

#include <config.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h> 
#include <iostream>

#include <qcursor.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qdragobject.h>
#include <qcheckbox.h>
#include <qcombobox.h>
#include <qmultilineedit.h>
#include <qprogressbar.h>
#include <qprogressdialog.h>
#include <qpushbutton.h>
#include <qradiobutton.h>
#include <qinputdialog.h>
#include <qlabel.h>
#include <qtimer.h>

#include <kapplication.h>
#include <kconfig.h>
#include <klocale.h>
#include <kfiledialog.h>
#include <kmessagebox.h>
#include <kurldrag.h>
#include <klistview.h>
#include <kpopupmenu.h>
#include <ktempfile.h>
#include <kstddirs.h>
#include <kdebug.h>

#include <arts/kmedia2.h>
#include <arts/debug.h>
#include <arts/dynamicrequest.h>
#include <arts/connect.h>
#include <arts/flowsystem.h>

#include "audiocd.h"
#include "audiocd.moc"
#include "tracklistviewitem.h"
#include "convertaudio.h"

using namespace Arts;
using namespace std;

/* copypasted from simplesoundserver_impl.cc */
PlayObject createPlayObject( const string& filename ){
  string objectType = "";

  /*
   * figure out extension (as lowercased letters)
   */
  string extension = "";
  bool extensionok = false;
  string::const_reverse_iterator i;
  for( i = filename.rbegin(); i != filename.rend() && !extensionok; i++ ){
    if( *i == '.' )
      extensionok = true;
    else
      extension = ( char )tolower( *i ) + extension;
  }

  /*
   * query trader for PlayObjects which support this
   */
  if( extensionok ){
    arts_debug( "search playobject, extension = %s", extension.c_str() );

    TraderQuery query;
    query.supports( "Interface", "Arts::PlayObject" );
    query.supports( "Extension", extension );

    vector<TraderOffer> *offers = query.query();
    if( ! offers->empty() )
      objectType = offers->front().interfaceName();  // first offer

    delete offers;
  }

  /*
   * create a PlayObject and connect it
   */
  if( objectType != "" ){
    arts_debug( "creating %s to play file", objectType.c_str() );

    PlayObject result = SubClass( objectType );
    if( result.loadMedia( filename ) ){
      result._node()->start();
      return result;
    }
    else arts_warning( "couldn't load file %s", filename.c_str() );
  }
  else arts_warning( "file format extension %s unsupported", extension.c_str() );

  return PlayObject::null();
}

//Constructor
AudioCD::AudioCD(QWidget *parent, const char *name) : AudioCD_GUI(parent, name, true) {
  //allow drag 'n drop
   setAcceptDrops( true );

  //reset
  QProgress_CDSize->setProgress( 0 );
  labelsize = 0, trackcount = 0, alltracks = 0, allmp3tracks = 0, alloggtracks = 0, convertcount = 0;

  //Connects for 'QRadioButton_DaO' toogle and 'QRadioButton_TaO' toggle
  connect( QRadioButton_DaO, SIGNAL(clicked()), this, SLOT(slot_toggleTaO()) );
  connect( QRadioButton_TaO, SIGNAL(clicked()), this, SLOT(slot_toggleDaO()) );

  // Initializes the KListView
  KListView_Tracklist->setItemsRenameable( true );
  KListView_Tracklist->setRenameable ( 0, false );
  KListView_Tracklist->setRenameable ( 2, true );
  KListView_Tracklist->setAcceptDrops( true );
  KListView_Tracklist->setDragEnabled( true );
  KListView_Tracklist->setSorting( -1 );

  //Read config
  config = kapp->config();
  config->setGroup( "Config - audiocd" );

  QCheckBox_Simulate->setChecked( config->readBoolEntry("QCheckBox_Simulate") );
  QCheckBox_Force->setChecked( config->readBoolEntry("QCheckBox_Force") );
  QRadioButton_TaO->setChecked( config->readBoolEntry("QRadioButton_TaO") );
  QRadioButton_DaO->setChecked( config->readBoolEntry("QRadioButton_DaO") );

  QComboBox_CDRWBlanking->setCurrentItem( config->readNumEntry("QComboBox_CDRWBlanking") );
  QComboBox_WriterSpeed->setCurrentItem( config->readNumEntry("QComboBox_WriterSpeed") );

  //Check for RW-Device
  config->setGroup( "CD-Writer" );
  if ( config->readEntry( "isRW" ) == "false" ){
    QComboBox_CDRWBlanking->clear();
    QComboBox_CDRWBlanking->insertItem(i18n( "Non-RW!" ));
    QComboBox_CDRWBlanking->setEnabled( false );
  }

  //Read program paths into public variables
  config->setGroup("Program paths");
  cdrecord = config->readEntry("cdrecord_path");
  cdrdao = config->readEntry("cdrdao_path");

  //Read tracklist
  config->setGroup( "Config - tracklist" );

  if ( config->readEntry( "Source" ) == "" ){
    tracklistChanged();
  }
  else {
    char buf[256];
    int fsize, tcount = 0;
    QString track;

    QStringList tracks = config->readListEntry( "Source" );
    QStringList cdtext = config->readListEntry( "CD-Text" );

    do {
      TrackListViewItem *tracklist = new TrackListViewItem ( KListView_Tracklist, tcount + 1, tracks[tcount], cdtext[tcount], 3 );

      track = tracks[tcount];
      QFileInfo file(track);
      fsize = file.size();
      if ( checkMimeType( track ) == MP3 ){
        labelsize += ( fsize * 12 );
        tracklist->setSize( (fsize * 12) / 1048676 );
      }
      else if ( checkMimeType( track ) == WAVE ){
        labelsize += fsize;
        tracklist->setSize ( fsize / 1048676 );
      }
      else if ( checkMimeType( track ) == OGGVORBIS ){
        labelsize += ( fsize * 12 );
        tracklist->setSize( (fsize * 12) / 1048676);
      }

      sprintf( buf, "%d MB", labelsize / 1048676 );
      QTextLabel_CDSize->setText( buf );
      QProgress_CDSize->setProgress( labelsize );

      tcount++;
    }
    while ( tcount < config->readNumEntry( "Count" ) );

    QLineEdit_Performer->setText( config->readEntry( "Performer" ) );
    QLineEdit_CDTitle->setText( config->readEntry( "CD-Title" ) );

    slot_sortTracklist();

    if ( labelsize / 1048676 >= 650 ) {
      QCheckBox_overburn->setChecked( true );
      KMessageBox::information( 0, i18n("The CD is over 650 MB. 'Overburn' option was activated!\nNote: Your CD writer must support this."), i18n("KOnCD - Audio CD - Info") );
    }
  }
}

AudioCD::~AudioCD(){
  //Remove temp .wav files
  int tcount = 0;
  int tc = KListView_Tracklist->childCount();
  do {
    if ( isTempFile(tracklist[tcount]) ) 
      QFile::remove( tracklist[tcount] );
    tcount++;
  }
  while ( tcount < tc );

  // Remove temp toc file
  if ( QFile::exists( tempFile ) ) QFile::remove( tempFile );
}

bool AudioCD::isTempFile(const QString &f)
{
  QString tmpDir = KGlobal::dirs()->saveLocation("tmp");
  return f.startsWith(tmpDir) && QFile::exists(f);
}

//'QRadioButton_TaO' clicked , toggle 'QRadioButton_DaO'
void AudioCD::slot_toggleDaO(){
  if ( ! QRadioButton_DaO->isChecked() ){
    QRadioButton_TaO->setChecked( true );
  }
  else{
    QRadioButton_TaO->setChecked( true );
    QRadioButton_DaO->setChecked( false );
  }
}

//'QRadioButton_DaO' clicked , toggle 'QRadioButton_TaO'
void AudioCD::slot_toggleTaO(){
  if ( ! QRadioButton_TaO->isChecked() ){
    QRadioButton_DaO->setChecked( true );
  }
  else{
    QRadioButton_TaO->setChecked( false );
    QRadioButton_DaO->setChecked( true );
  }
}

// Right click of KListView
void AudioCD::slot_KListView_popupMenu(QListViewItem*,const QPoint&,int){
  // If tracklist empty, return
  if ( KListView_Tracklist->childCount() == 0 ) return;

  // Setup popup menu entries
  KPopupMenu *popupMenu = new KPopupMenu;
  popupMenu->insertItem( i18n( "Delete &track" ), this, SLOT( slot_deleteTrack() ) );
  popupMenu->insertItem( i18n( "&Set CD-Text" ), this, SLOT( slot_setCDText() ) );
  popupMenu->insertItem( i18n( "&Delete CD-Text" ), this, SLOT( slot_deleteCDText() ) );
  popupMenu->move( QCursor::pos() );
  popupMenu->show();
}

// Set CD-Text
void AudioCD::slot_setCDText(){
  bool ok = true;
  QString cdtext = QInputDialog::getText( i18n( "KOnCD - Set CD-Text" ), i18n( "Please enter the new CD-Text:\n(In this form: 'Performer-Title', example: Britney Spears-Baby One More Time)" ), QLineEdit::Normal, KListView_Tracklist->currentItem()->text( 2 ), &ok, this );
  if ( ! ok ) return;
  if ( ! cdtext.find( "-" ) || cdtext.find( " - " ) ){
    KMessageBox::error( 0, i18n("Wrong format. Use: Performer-Title."), i18n("KOnCD - Audio CD - Error") );
    return;
  }
  KListView_Tracklist->currentItem()->setText( 2, cdtext );
}

// Delete CD-Text
void AudioCD::slot_deleteCDText(){
  KListView_Tracklist->currentItem()->setText( 2, "" );
}

//'Add'-Button' clicked
void AudioCD::slot_addTrack(){
  int fsize;
  char buf[256];

  QStringList getName = KFileDialog::getOpenFileNames(0, "*.wav *.WAV *.mp3 *.MP3 *.ogg *.OGG", this, 0);
  // QListView is kindof messed the newly appended item is shown on top this destroys the mode
  for (QStringList::Iterator it = getName.begin();it!=getName.end();++it) {

    int index = KListView_Tracklist->childCount( );
    TrackListViewItem *tracklist = new TrackListViewItem ( KListView_Tracklist, index + 1, *it, "", 3 );

    QFileInfo file( (*it) );
    fsize = file.size();
    if ( checkMimeType( (*it) ) == MP3 ){
      labelsize += ( fsize * 12 );
      tracklist->setSize( (fsize * 12) / 1048676 );
    }
    else if ( checkMimeType( (*it) ) == WAVE ){
      labelsize += fsize;
      tracklist->setSize ( fsize / 1048676 );
    }
    else if ( checkMimeType( (*it) ) == OGGVORBIS ){
      labelsize += ( fsize * 12 );
      tracklist->setSize( (fsize * 12) / 1048676);
    }

    sprintf( buf, "%d MB", labelsize / 1048676 );
    QTextLabel_CDSize->setText( buf );
    QProgress_CDSize->setProgress( labelsize );
  }

  KListView_Tracklist->setSorting( 0, true );
  KListView_Tracklist->sort( );
  KListView_Tracklist->setSorting( -1 );

  if ( labelsize / 1048676 >= 650 ) {
    QCheckBox_overburn->setChecked( true );
    KMessageBox::information( 0, i18n("The CD is over 650 MB. 'Overburn' option was activated!\nNote: Your CD writer must support this."), i18n("KOnCD - Audio CD - Error") );
  }

  tracklistChanged();
}

//'Delete'-Button' clicked
void AudioCD::slot_deleteTrack(){
  int fsize;
  char buf[256];

  TrackListViewItem *item = (TrackListViewItem *) KListView_Tracklist->currentItem( );
  if ( item == 0 ) return;
  QFileInfo file( item->source() );
  fsize = file.size();

  if ( checkMimeType( item->source() ) == MP3 ){
    labelsize -= ( fsize * 12 );
  }
  else if ( checkMimeType( item->source() ) == WAVE ){
    labelsize -= fsize;
  }
  else if ( checkMimeType( item->source() ) == OGGVORBIS ){
      labelsize -= ( fsize * 12 );
  }

  sprintf( buf, "%d MB", labelsize / 1048676 );
  QTextLabel_CDSize->setText( buf );
  QProgress_CDSize->setProgress( labelsize );
  if ( labelsize / 1058676 <= 650 ) {
    QCheckBox_overburn->setChecked( false );
  }
  delete item;

  slot_Moved();
  tracklistChanged();
}

//'Delete all tracks'-Button' clicked
void AudioCD::slot_deleteAllTracks(){
  KListView_Tracklist->clear( );
  QTextLabel_CDSize->setText( "0 MB" );
  QProgress_CDSize->setProgress( 0 );
  labelsize = 0;
  tracklistChanged();
}

//Start write
void AudioCD::slot_start(){
  //If tracklist empty, return
  if ( KListView_Tracklist->childCount() == 0 ){
    KMessageBox::error( 0, i18n("You need to add tracks to the tracklist!"), i18n("KOnCD - Audio CD - Error") );
    return;
  }

  //If TaO and DaO RadioButton false, return
  if ( ! QRadioButton_TaO->isChecked() && ! QRadioButton_DaO->isChecked() ){
    KMessageBox::error( 0, i18n("You must select 'Track at Once' or 'Disc at Once'!"), i18n("KOnCD - Audio CD - Error") );
    return;
  }

  trackcount = 1;
  timer = new QTimer( this );
  progress = new QProgressDialog( i18n( "Converting compressed files..." ), i18n( "&Abort" ), KListView_Tracklist->childCount(), this, "progress", true, 0 );

  connect( progress, SIGNAL( cancelled() ), this, SLOT( slot_cancel() ) );
  connect( timer, SIGNAL( timeout() ), this, SLOT( slot_perform() ) );

  progress->setCaption( i18n( "KOnCD - Converting" ) );
  progress->setMinimumDuration( 0 );
  progress->show();
  timer->start( 0 );
  progress->setProgress( 0 );
}

void AudioCD::slot_perform(){
  item = (TrackListViewItem *) KListView_Tracklist->itemAtIndex( trackcount - 1 );

  if ( checkMimeType( item->source() ) != WAVE ){
    QString file = locateLocal("tmp", QString("track%1.cdr").arg(trackcount));
    tracklist[trackcount - 1] = file;
    convert( item->source(), file );
  }
  else{
     tracklist[trackcount - 1] = item->source();
  }

  trackcount++;

  if ( trackcount > progress->totalSteps() ){
    timer->stop();
    slot_createTOCfile();
  }

  progress->setProgress( trackcount - 1 );
}

void AudioCD::slot_cancel(){
  timer->stop();
}

//Create toc file for cdrdao
void AudioCD::slot_createTOCfile(){
  KTempFile file;
  
  if ( file.status() != 0 ){
    KMessageBox::error( 0, i18n( "Could not create temp file!" ), i18n("KOnCD - Audio CD - Error") );
    return;
  }
  tempFile = file.name();

  QTextStream &stream = *(file.textStream());

  QString performer = QLineEdit_Performer->text();
  QString cdtitle = QLineEdit_CDTitle->text();

  stream << "CD_DA\n";
  stream << "CD_TEXT {\n";
  stream << " LANGUAGE_MAP {\n";
  stream << " 0 : EN\n";
  stream << " }\n";
  stream << " LANGUAGE 0 {\n";
  stream << "  TITLE \"" + cdtitle + "\"\n";
  stream << "  PERFORMER \"" + performer + "\"\n";
  stream << " }\n";
  stream << "}\n";
  stream << "\n";

  QString tmp;
  int pos;
  int tcount = 0;
  int tc = KListView_Tracklist->childCount();
  do {
    stream << "TRACK AUDIO\n";

    tmp = KListView_Tracklist->itemAtIndex( tcount )->text( 2 );
    pos = tmp.find( "-", 0, false );
    QString performer = tmp.left( pos );

    tmp = KListView_Tracklist->itemAtIndex( tcount )->text( 2 );
    pos = tmp.find( "-", 0, false );
    QString tracktitle = tmp.mid( pos + 1, tmp.length() );

    stream << "CD_TEXT {\n";
    stream << " LANGUAGE 0 {\n";
    stream << "  TITLE \"" + tracktitle + "\"\n";
    stream << "  PERFORMER \"" + performer + "\"\n";
    stream << " }\n";
    stream << "}\n";

    if ( QRadioButton_TaO->isChecked() && tcount > 0 ) 
      stream << "PREGAP 0:2:0\n";

    stream << "FILE \"" + tracklist[tcount] + "\" 0" + "\n";
    stream << "\n";
    tcount++;
  }
  while ( tcount < tc );

  file.close();

  //Write the CD
  if ( QComboBox_CDRWBlanking->currentItem() != 0 ){
    slot_blankingCDRW();
  }
  else{
    slot_writeCD();
  }
}

//Blanking CDRW
void AudioCD::slot_blankingCDRW(){
  //KProcess argument
  process.clearArguments();
  process << cdrecord << "-v";

  //Set the CD-Writer first
  config->setGroup("CD-Writer");
  process << config->readEntry("SCSI-Target");

  //Set fifo size
  switch( config->readNumEntry("Fifosize") )
  {
     case 0:  process << "fs=4m";
            break;
     case 1: process << "fs=8m";
            break;
     case 2: process << "fs=12m";
            break;
     case 3: process << "fs=16m";
            break;
     case 4: process << "fs=20m";
            break;
     case 5: process << "fs=24m";
            break;
    case 6: process << "fs=28m";
            break;
    case 7: process << "fs=32m";
            break;
  }

  //Set CD-RW Options to KProcess
  switch( QComboBox_CDRWBlanking->currentItem() )
  {
     case 1:  process << "blank=all";
            break;
     case 2: process << "blank=fast";
            break;
     case 3: process << "blank=track";
            break;
     case 4: process << "blank=unreserve";
            break;
     case 5: process << "blank=trtrail";
            break;
     case 6: process << "blank=unclose";
            break;
    case 7: process << "blank=session";
            break;
  }

  //Set CD-Writer Speed to KProcess
  switch( QComboBox_WriterSpeed -> currentItem() )
  {
     case 0:  process << "speed=1";
            break;
     case 1:  process << "speed=2";
            break;
     case 2:  process << "speed=4";
            break;
     case 3:  process << "speed=6";
            break;
     case 4:  process << "speed=8";
            break;
     case 5:  process << "speed=10";
            break;
     case 6:  process << "speed=12";
            break;
     case 7:  process << "speed=16";
            break;
     case 8:  process << "speed=20";
            break;
     case 9:  process << "speed=24";
            break;
  }

  //Connect the Abort-Button from ImgProOut-Dialog to Abort-Handler
  connect( procoutdlg.QPushButton_OK, SIGNAL(clicked()), this, SLOT(abort_handler()));

  //Connect the 'processExited' Signal to the 'slotProcessFinished' Slot
  connect( &process, SIGNAL(processExited(KProcess *)), this, SLOT(slot_BlankingProcessExited(KProcess *)));

  //Connect with slotRecStderr to update KProgress (Write- / Buffer-Status) and StatusLine
  connect( &process, SIGNAL(receivedStdout (KProcess *, char *, int) ), this, SLOT(slot_BurnRecStderr (KProcess *, char *, int) ));
  connect( &process, SIGNAL(receivedStderr (KProcess *, char *, int) ), this, SLOT(slot_BurnRecStderr (KProcess *, char *, int) ));

  //Start KProcess
  if( ! process.start( KProcess::NotifyOnExit, KProcess::AllOutput ) ){
    KMessageBox::error( 0, i18n("Could not start cdrecord!"), i18n("KOnCD - Audio CD - Error") );
    process.disconnect();
    return;
  }

  procoutdlg.QPushButton_OK->setText( i18n( "&Abort" ) );
  if ( ! procoutdlg.isVisible() ) procoutdlg.show();
}

//Write the cd
void AudioCD::slot_writeCD(){
  //KProcess argument
  process.clearArguments();
  process << cdrdao;

  if( QCheckBox_Simulate->isChecked() ) {
    process << "simulate";
  }
  else {
    process << "write";
  }

  //No wait
  process << "-n";

  //Set the CD-Writer first
  config->setGroup("CD-Writer");
  process << "--device" << config->readEntry("Device");

  //Set CD-Writer Options to KProcess
  if( QCheckBox_Force->isChecked() ) process << "--force";

  //Set CD-Writer Options to KProcess
  if( QCheckBox_overburn->isChecked() ) process << "--overburn";

  //Set fifo size
  switch( config->readNumEntry("Fifosize") )
  {
     case 0:  process << "--buffers" << "10";
            break;
     case 1: process << "--buffers" << "10";
            break;
     case 2: process << "--buffers" << "12";
            break;
     case 3: process << "--buffers" << "16";
            break;
     case 4: process << "--buffers" << "20";
            break;
     case 5: process << "--buffers" << "24";
            break;
    case 6: process << "--buffers" << "28";
            break;
    case 7: process << "--buffers" << "32";
            break;
  }

  //Set CD-Writer Speed to KProcess
  switch( QComboBox_WriterSpeed -> currentItem() )
  {
     case 0:  process << "--speed" << "1";
            break;
     case 1:  process << "--speed" << "2";
            break;
     case 2:  process << "--speed" << "4";
            break;
     case 3:  process << "--speed" << "6";
            break;
     case 4:  process << "--speed" << "8";
            break;
     case 5:  process << "--speed" << "10";
            break;
     case 6:  process << "--speed" << "12";
            break;
     case 7:  process << "--speed" << "16";
            break;
     case 8:  process << "--speed" << "20";
            break;
     case 9:  process << "--speed" << "24";
            break;
  }

  //Add toc file
  process << tempFile;

  //Connect the Abort-Button from ImgProOut-Dialog to Abort-Handler
  connect( procoutdlg.QPushButton_OK, SIGNAL(clicked()), this, SLOT(abort_handler()));

  //Connect the 'processExited' Signal to the 'slotProcessFinished' Slot
  connect( &process, SIGNAL(processExited(KProcess *)), this, SLOT(slot_BurnProcessExited(KProcess *)));

  //Connect with slotRecStderr to update KProgress (Write- / Buffer-Status) and StatusLine
  connect( &process, SIGNAL(receivedStdout (KProcess *, char *, int) ), this, SLOT(slot_BurnRecStderr (KProcess *, char *, int) ));
  connect( &process, SIGNAL(receivedStderr (KProcess *, char *, int) ), this, SLOT(slot_BurnRecStderr (KProcess *, char *, int) ));

  //Start KProcess
  if( ! process.start( KProcess::NotifyOnExit, KProcess::AllOutput ) ){
    KMessageBox::error( 0, i18n("Could not start cdrdao!"), i18n("KOnCD - Audio CD - Error") );
    process.disconnect();
    return;
  }

  procoutdlg.QPushButton_OK->setText( i18n( "&Abort" ) );
  if ( ! procoutdlg.isVisible() )  procoutdlg.show();
}

//KProcess outout analysis
void AudioCD::slot_BurnRecStderr(KProcess *, char *buffer, int buflen) {
  char *c, buf[1024];
  int wrote, total, load;

  if( !buflen ) {
    return;
  }
  memset( buf, 0, sizeof( buf ) );
  strncpy( buf, buffer, buflen > (int) sizeof( buf ) ? sizeof(buf) - 1 : buflen );

  //Add cdrecord messages to the output window
  procoutdlg.Output->append( buf );
  //Go to the end of the output text
  procoutdlg.Output->setCursorPosition( procoutdlg.Output->length(), 0 );

  //Blanking the CD-RW
  if( strstr( buf, "Blanking" )) {
    procoutdlg.StatusLabel -> setText( i18n("Blanking the CDRW...") );
  }

  //Blanking finished
  if( strstr( buf, "Blanking time" )) {
    procoutdlg.StatusLabel -> setText( i18n("Blanking finished.") );
  }

  //Blanking failed
  if( strstr( buf, "Inserted disk is not empty" )) {
    procoutdlg.StatusLabel -> setText( i18n("Error: Inserted disk is not empty!") );
  }

  //Blanking failed
  if( strstr( buf, "Cannot blank disk" )) {
    procoutdlg.StatusLabel -> setText( i18n("Error: Blanking failed!") );
  }

  //Reloading disk...
  if( strstr( buf, "Drive needs to reload" )) {
    procoutdlg.StatusLabel -> setText( i18n("Disk must be reloaded...") );
  }

  //Waiting for writer device...
  if( strstr( buf, "WARNING: Unit not ready, still trying..." )) {
    procoutdlg.StatusLabel -> setText( i18n("Waiting for writer device...") );
  }

  //Executing power calibration
  if( strstr( buf, "Executing power calibration..." )) {
    procoutdlg.StatusLabel -> setText( i18n("Calibrating...") );
  }

  //Writing CD-Text
  if( strstr( buf, "Writing CD-TEXT" )) {
    procoutdlg.StatusLabel -> setText( i18n("Writing CD-Text...") );
  }

  //Fixating the CD
  if( strstr( buf, "Flushing cache..." )) {
    procoutdlg.StatusLabel -> setText( i18n("Writing TOC...") );
  }

  //Burn process complete
  if( strstr( buf, "finished successfully." ) ) {
    procoutdlg.StatusLabel->setText( i18n("Burn-Process complete.") );
  }

  //Set statuslabel
  if( strstr( buf, "Writing track" )) {
    if( QCheckBox_Simulate->isChecked() ) {
      c = strtok( buf, "Writing track " );
      if( strstr( c, "0" )) c = strtok( c, "0" );
      QString msg = i18n( "Writing track %1 in dummy mode..." ).arg(c);
      procoutdlg.StatusLabel->setText( msg );
    }
    else{
      c = strtok( buf, "Writing track " );
      if( strstr( c, "0" )) c = strtok( c, "0" );
      QString msg = i18n( "Writing track %1..." ).arg(c);
      procoutdlg.StatusLabel->setText( msg );
    }
  }

  if( strstr( buf, "MB" )) {
    c = strstr( buf, "Wrote" );
    if( c && *c ) {
      c = strtok( c, " \r\t " );
      if( c ) {
        c = strtok( NULL, "\r\t " );
        wrote = atoi( c );
        c = strtok( NULL, "of " );
        if( c ) {
          total = atoi( c );
          c = strtok( NULL, "\r" );
          c = strstr( c, "Buffer " );
          if( c ) {
            c = strtok( c + 7, "%" );
            if( c ) {
              load = atoi( c );
              procoutdlg.WriteProgress -> setProgress( total ? wrote * 100 / total : 0 );
              procoutdlg.BufferProgress -> setProgress( load );
            }
          }
        }
      }
    }
  }
}

//KProcess finished
void AudioCD::slot_BlankingProcessExited(KProcess *rcproc) {
  process.disconnect();

  if( rcproc->exitStatus() != 0 ) {
    QString statusout;
    statusout.sprintf( I18N_NOOP( "Exit status: %d" ), rcproc->exitStatus() );
    KMessageBox::error( 0, I18N_NOOP("An error is occurred!\n" + statusout), i18n("KOnCD - Audio CD - Error") );
    procoutdlg.QPushButton_OK->setText( i18n( "&OK" ) );
    if ( QFile::exists( tempFile ) ) QFile::remove( tempFile );
     return;
  }
  else{
    slot_writeCD();
  }
}

//KProcess finished
void AudioCD::slot_BurnProcessExited(KProcess *rcproc) {
  process.disconnect();

  //Check, if KProcess exited normally...
  if( rcproc->exitStatus() != 0 ) {
    QString statusout;
    statusout.sprintf( I18N_NOOP( "Exit status: %d" ), rcproc->exitStatus() );
    KMessageBox::error( 0, I18N_NOOP("An error is occurred!\n" + statusout), i18n("KOnCD - Audio CD - Error") );
  }

  procoutdlg.QPushButton_OK->setText( i18n( "&OK" ) );
}

//Abort-Handler
void AudioCD::abort_handler(){
  if ( process.isRunning() ){
    int pid = process.getPid();
    process.kill();
    waitpid( pid, 0, 0 );
  }

  if ( shellProcess.isRunning() ){
    int pid = shellProcess.getPid();
    shellProcess.kill();
    waitpid( pid, NULL, 0 );
  }

  imgprocoutdlg.StatusLabel->setText( i18n("Creating CD image...") );
  imgprocoutdlg.Output->setText( "" );
  imgprocoutdlg.ImgProgress->setProgress( 0 );
  if ( imgprocoutdlg.isVisible() ) imgprocoutdlg.close();

  procoutdlg.setCaption( i18n( "KOnCD - Writing CD..." ) );
  procoutdlg.StatusLabel->setText( i18n( "Prepare for write..." ) );
  procoutdlg.Output->setText( "" );
  procoutdlg.WriteProgress->setProgress( 0 );
  procoutdlg.BufferProgress->setProgress( 0 );
  if ( procoutdlg.isVisible() ) procoutdlg.close();

  process.disconnect();
  shellProcess.disconnect();

  // Remove temp toc file
  if ( QFile::exists( tempFile ) ) QFile::remove( tempFile );
}

void AudioCD::dragEnterEvent(QDragEnterEvent* event){
  KURL::List urls;
  QString mimetype;

  //Check mimetype
  if ( KURLDrag::decode( event, urls ) && urls.count() > 0 ){
    KURL::List::ConstIterator it( urls.begin() );
    for( ;it != urls.end(); ++it ){
      if ( ( *it ).isLocalFile() ){
        KMimeType::Ptr typ = KMimeType::findByURL( ( *it ).path( 0 ),true );
        mimetype = typ->name();
      }
    }
  }

  //Isn't mimetype 'audio/x-wav', 'audio/x-mp3' or 'audio/x-ogg' don't accept it !
  if ( mimetype == "audio/x-wav" || mimetype == "audio/x-mp3" || mimetype == "audio/x-ogg" ) event->accept( QUrlDrag::canDecode( event ) );
}

void AudioCD::dropEvent(QDropEvent *event){
  QStringList files;
  int fsize;
  char buf[256];

  if ( QUrlDrag::decodeLocalFiles( event, files ) ) {
    for (QStringList::Iterator it = files.begin();it!=files.end();++it) {
      if( checkMimeType( (*it) ) == WAVE || checkMimeType( (*it) ) == MP3 || checkMimeType( (*it) ) == OGGVORBIS ){
        int index = KListView_Tracklist->childCount();
        TrackListViewItem *tracklist = new TrackListViewItem ( KListView_Tracklist, index + 1, *it, "", 3 );
        QFileInfo file( (*it) );
        fsize = file.size();
        if ( checkMimeType( (*it) ) == MP3 ){
          labelsize += ( fsize * 12 );
          tracklist->setSize( fsize * 12  / 1048676 );
        }
        else if ( checkMimeType( (*it) ) == WAVE ){
          labelsize += fsize;
          tracklist->setSize( fsize  / 1048676 );
        }
        else if ( checkMimeType( (*it) ) == OGGVORBIS ){
          labelsize += (fsize * 12 );
          tracklist->setSize( fsize * 12  / 1048676);
        }
        sprintf( buf, "%d MB", labelsize / 1048676 );
        QTextLabel_CDSize->setText( buf );
        QProgress_CDSize->setProgress( labelsize );
      }
    }
  }

  slot_sortTracklist();

  if ( labelsize / 1048676 >= 650 ) {
    QCheckBox_overburn->setChecked( true );
    KMessageBox::information( 0, i18n("The CD is over 650 MB. 'Overburn' option was activated!\nNote: Your CD writer must support this."), i18n("KOnCD - Audio CD - Error") );
  }

  tracklistChanged();
}

void AudioCD::slot_Up( ){
  int index;
  TrackListViewItem *item;
  TrackListViewItem *item2;

  item = (TrackListViewItem *) KListView_Tracklist->currentItem( );
  index = KListView_Tracklist->itemIndex( item );
  if( KListView_Tracklist->childCount() == 0 || item == 0 )
    return;
  item->setTrack( index );
  item2 = (TrackListViewItem *) KListView_Tracklist->itemAtIndex( index -1 );
  item2->setTrack( index + 1 );

  slot_sortTracklist();
}

void AudioCD::slot_Down( ){
  int index;
  TrackListViewItem *item;
  TrackListViewItem *item2;

  item = (TrackListViewItem *) KListView_Tracklist->currentItem( );
  index = KListView_Tracklist->itemIndex( item );
  if( KListView_Tracklist->childCount( ) == 0 || item == 0 )
    return;
  item->setTrack( item->tracknumber( ) + 1 );
  item2 = (TrackListViewItem *) KListView_Tracklist->itemAtIndex( index + 1 );
  item2->setTrack( item->tracknumber( ) -1 );

  slot_sortTracklist();
}

// KListView_TrackList a item was moved
void AudioCD::slot_Moved(){
  TrackListViewItem *item;
  for( int i = 0; i < KListView_Tracklist->childCount(); i++ ){
    item = ( TrackListViewItem * ) KListView_Tracklist->itemAtIndex( i );
    item->setTrack( i + 1);
  }
}

void AudioCD::convert( QString source, QString target ){
  Dispatcher d;

  kdDebug() << "decompress '" << source << "' to '" << target << "'" << endl;

  if ( QFile::exists( target ) ) QFile::remove( target );

  PlayObject playObject = createPlayObject( source.local8Bit().data() );
  if( playObject.isNull() ){
    kdDebug() << "can't read inputfile " << source << endl;
    return;
  }

  playObject.play();

  ConvertAudio convertAudio;
  convertAudio.filename( target.local8Bit().data() );

  Arts::connect( playObject, "left", convertAudio,"left" );
  Arts::connect( playObject, "right", convertAudio,"right" );

  usleep(100000);
  if( playObject._base()->_isCompatibleWith( "DecoderBaseObject" ) )
    if( ! DynamicRequest( playObject ).method( "_set_blocking" ).param( true ).invoke() )
      kdDebug() << "mpeglib, and blocking attribute can't be changed ?" << endl;

  convertAudio.start();

  while( playObject.state() != posIdle )
    convertAudio.goOn();
}

//'Quit-Button' clicked
void AudioCD::slot_sortTracklist(){
  KListView_Tracklist->setSorting( 0, true );
  KListView_Tracklist->sort( );
  KListView_Tracklist->setSorting( -1 );
}

// Check on mimetype
int AudioCD::checkMimeType( QString filename ){
  if ( KMimeType::findByURL( filename, 0, true )->name() == "audio/x-mp3" ) return MP3;
  if ( KMimeType::findByURL( filename, 0, true )->name() == "application/x-ogg" ) return OGGVORBIS;
  if ( KMimeType::findByURL( filename, 0, true )->name() == "audio/x-wav" ) return WAVE;
}

void AudioCD::tracklistChanged(){
  if ( KListView_Tracklist->childCount() == 0 ){
    QPushButton_Up->setEnabled( false );
    QPushButton_Down->setEnabled( false );
    QPushButton_Del->setEnabled( false );
    QPushButton_DelAllTracks->setEnabled( false );
  }
  else {
    QPushButton_Up->setEnabled( true );
    QPushButton_Down->setEnabled( true );
    QPushButton_Del->setEnabled( true );
    QPushButton_DelAllTracks->setEnabled( true );
  }
}

//'Quit-Button' clicked
void AudioCD::slot_exit(){
  //Write config
  config->setGroup( "Config - audiocd" );

  config->writeEntry( "QCheckBox_Simulate", QCheckBox_Simulate->isChecked() );
  config->writeEntry( "QCheckBox_Force", QCheckBox_Force->isChecked() );
  config->writeEntry( "QRadioButton_TaO", QRadioButton_TaO->isChecked() );
  config->writeEntry( "QRadioButton_DaO", QRadioButton_DaO->isChecked() );

  config->writeEntry( "QComboBox_CDRWBlanking", QComboBox_CDRWBlanking->currentItem() );
  config->writeEntry( "QComboBox_WriterSpeed", QComboBox_WriterSpeed->currentItem() );

  //Remove temp .wav files
  int tcount = 0;
  int tc = KListView_Tracklist->childCount();
  do {
    if ( isTempFile( tracklist[tcount] ) )
    	QFile::remove( tracklist[tcount] );
    tcount++;
  }
  while ( tcount < tc );

  // Remove temp toc file
  if ( QFile::exists( tempFile ) )
    QFile::remove( tempFile );

  //Reset
  QProgress_CDSize->setProgress( 0 );
  labelsize = 0, trackcount = 0, alltracks = 0, allmp3tracks = 0, convertcount = 0;

  //If tracklist empty, save empty tracklist and exit
  if ( KListView_Tracklist->childCount() == 0 ){
    config->setGroup( "Config - tracklist" );
    config->writeEntry( "Source", "" );
    config->writeEntry( "Count", "" );
    close();
    return;
  }

  //Save tracklist
  config->setGroup( "Config - tracklist" );

  tcount = 0;
  tc = KListView_Tracklist->childCount();
  QStringList source, cdtext;

  do {
    source.append( KListView_Tracklist->itemAtIndex( tcount )->text( 1 ) );
    tcount++;
  }
  while ( tcount < tc );

  tcount = 0;
  do {
    cdtext.append( KListView_Tracklist->itemAtIndex( tcount )->text( 2 ) );
    tcount++;
  }
  while ( tcount < tc );

  //write QStringList in config file
  config->writeEntry( "Source", source );
  config->writeEntry( "CD-Text", cdtext );
  config->writeEntry( "Performer", QLineEdit_Performer->text() );
  config->writeEntry( "CD-Title", QLineEdit_CDTitle->text() );
  config->writeEntry( "Count", tc );

  close();
}
