/***************************************************************************
 *   Copyright (C) 2005 by James Thorniley                                 *
 *   james@uncommonlygood.co.uk                                            *
 *                                                                         *
 *   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.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "burnaudiocdconfigwidget.h"
#include "burnsidebarplugin.h"
#include "burnplaylistviewitem.h"

#include <fileref.h>
#include <tag.h>
#include <tstring.h>

#include <qheader.h>
#include <qlabel.h>
#include <klocale.h>
#include <k3baudiodoc.h>
#include <k3bcore.h>
#include <k3bpluginmanager.h>
#include <qlayout.h>
#include <klistview.h>
#include <qptrlist.h>
#include <k3bplugin.h>
#include <k3baudiodecoder.h>
#include <k3bglobals.h>
#include <qwidgetstack.h>
#include <kstandarddirs.h>

#include <stdio.h>
#include <time.h>

#include <kio/global.h>
#include <qtimer.h>

BurnAudioCDConfigWidget::BurnAudioCDConfigWidget(BurnSidebarPlugin *plugin, QWidget *parent, const char *name)
 : QFrame(parent, name),
   m_plugin( plugin )
{
  setLineWidth( 2 );
  setMargin( 5);

  QBoxLayout *layout = new QBoxLayout(this, QBoxLayout::TopToBottom);
  layout->setMargin( 0);

  m_playlistView = new KListView( this );
  m_playlistView->addColumn(QString::null);
  m_playlistView->addColumn(QString::null);
  m_playlistView->header()->hide();
  m_playlistView->setSizePolicy(  QSizePolicy::Ignored, QSizePolicy::Ignored  );
  m_playlistView->setAllColumnsShowFocus( true );
  m_playlistView->setAcceptDrops( true );
  m_playlistView->setDragEnabled( true );
  m_playlistView->setSorting( -1 );

  connect( m_playlistView, SIGNAL( moved() ), this, SLOT( slotMoved() ) );

  m_emptyLabel = new QLabel( i18n( "No audio files found" ), this );

  m_widgetStack = new QWidgetStack( this );
  m_widgetStack->addWidget( m_playlistView );
  m_widgetStack->addWidget( m_emptyLabel );
  m_widgetStack->raiseWidget( m_emptyLabel );
  m_widgetStack->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored );

  layout->addWidget( m_widgetStack );

  m_playlistMap = new QMap<KFileItem*,KListViewItem*>;

  m_savedItems = new QValueList<KURL>();
  m_timer = new QTimer( this );
  connect( m_timer, SIGNAL( timeout() ),
           this, SLOT( slotTimeout() ) );

  if( m_plugin->dirLister()->isFinished() )
    initPlaylist();
  else
    connect( m_plugin->dirLister(), SIGNAL( completed() ),
             this, SLOT( initPlaylist() ) );

}

BurnAudioCDConfigWidget::~BurnAudioCDConfigWidget()
{
  delete m_playlistMap;
  delete m_savedItems;
}

void BurnAudioCDConfigWidget::initPlaylist()
{

  KFileItemList files = m_plugin->dirLister()->items(KDirLister::AllItems);
  for( KFileItem *item = files.first();
       item;
       item = files.next() )
  {
    //kdDebug() << "got " << item->url().path() << endl;
    addFile( item );
  }

  if( m_playlistView->childCount() == 0 )
    m_widgetStack->raiseWidget( m_emptyLabel );
  else
    m_widgetStack->raiseWidget( m_playlistView );
  
  disconnect( m_plugin->dirLister(), SIGNAL( completed() ) , this, SLOT( initPlaylist() ) );
  connect( m_plugin->dirLister(), SIGNAL( newItems(const KFileItemList &) ),
           this, SLOT( slotNewItems(const KFileItemList&) ) );
  connect( m_plugin->dirLister(), SIGNAL( deleteItem( KFileItem * ) ),
           this, SLOT( slotDeleteItem( KFileItem * ) ) );
  connect( m_plugin->dirLister(), SIGNAL( refreshItems( const KFileItemList& ) ),
           this, SLOT( slotRefreshItems(const KFileItemList& ) ) );
}

void BurnAudioCDConfigWidget::slotNewItems( const KFileItemList& newItems )
{
  //kdDebug() << "BurnAudioCDConfigWidget::slotNewItems" << endl;
 
  QString rootDir( m_plugin->dirLister()->url().directory()+"/data" );

  KFileItemList items = newItems ;

  for( KFileItem *item = items.first(); item; item = items.next() )
  {

    //kdDebug() << "Saving " << item->url().path() << " for later" << endl;

    if( item->url().directory() != rootDir )
      continue; //we're only interested in the root directory

    if( item->isDir() )
      continue;
   
    //item pointers that we have will be deleted by KDirLister when this function
    //finished. To get long lived pointers, we must wait
    m_savedItems->append( item->url() );
    m_timer->start( 1000, true );

  }
}

void BurnAudioCDConfigWidget::addFile( KFileItem *item )
{

  static QString rootDir( m_plugin->dirLister()->url().directory()+"/data" );
  static QPtrList<K3bPlugin> fl = K3bCore::k3bCore()->pluginManager()->plugins( "AudioDecoder" );

    for( QPtrListIterator<K3bPlugin> it( fl ); it.current(); ++it ) 
    {
      
      if( item->url().directory() != rootDir )
        return; //we're only interested in the root directory
      if( item->isDir() )
        return;

      K3bAudioDecoderFactory* f = dynamic_cast<K3bAudioDecoderFactory*>( it.current() );
      if( f && f->canDecode( item->url() ) ) 
      {
        char track[3];
        int trackno = m_playlistView->childCount();
        if( trackno == 99 )
          break; //we don't allow more than 99 tracks per CD

        sprintf( track, "%02d", trackno+1 );

        TagLib::FileRef f( item->url().path() );
        QString text;
        if( !f.isNull() )
        {
          //kdDebug() << "non-null file" << endl;
          TagLib::String artist = f.tag()->artist();
          if( artist == TagLib::String::null )
            text = item->url().filename();
          else
          {
            text = TStringToQString( artist );
            text += "\n" + TStringToQString( f.tag()->title() );
          }
        }
        else
          text = item->url().filename();

        KListViewItem *i = new KListViewItem( m_playlistView, m_playlistView->lastItem() );
        i->setMultiLinesEnabled(true);
        i->setDragEnabled( true );
        i->setText( 0, QString::fromLocal8Bit(track) );
        i->setText( 1, text );
        m_playlistMap->insert( item , i ); 
        break;
      }
    }
}


void BurnAudioCDConfigWidget::slotRefreshItems( const KFileItemList &items )
{
  KFileItemList list( items );
  KFileItem *item;
  for( item = list.first(); item; item = list.next() )
  {
    //kdDebug() << "Refresh: " << item->url().prettyURL() << endl;
    if( !m_playlistMap->contains( item ) )
    {
      m_savedItems->append( item->url() );
      m_timer->start( 1000, true );
    }
  }
}


void BurnAudioCDConfigWidget::slotDeleteItem( KFileItem *item )
{
  //kdDebug() << "BurnAudioCDConfigWidget::slotDeleteItem( " << item->url().prettyURL() << " ) " << endl;
  if( m_playlistMap->contains(item) )
  {
    delete (*m_playlistMap)[item];

    m_playlistMap->remove(item);

    slotMoved(); //update track numbers

    if( m_playlistView->childCount() == 0 )
      m_widgetStack->raiseWidget( m_emptyLabel );
    else
      m_widgetStack->raiseWidget( m_playlistView );
  }
}

void BurnAudioCDConfigWidget::slotMoved( )
{
  //kdDebug() << "void BurnAudioCDConfigWidget::slotMoved( )" << endl;
  QListViewItem *temp;
  int i = 1;
  char track[3];
  for( temp = m_playlistView->firstChild(); temp; temp = temp->itemBelow() )
  {
    sprintf( track, "%02d", i );
    temp->setText(0, track);
    i++;
  }
}

void BurnAudioCDConfigWidget::slotTimeout()
{
  //kdDebug() << "void BurnAudioCDConfigWidget::slotTimeout()" << endl;

  for( QValueList<KURL>::iterator it = m_savedItems->begin();
       it != m_savedItems->end(); 
       it = m_savedItems->remove(it) )
  {
    //kdDebug() << "adding " << (*it).path() << endl;
    QFile file( (*it).path() );
    if(!(file.exists() && file.open(IO_ReadOnly)))
    {
      //kdDebug() << "skipping..." << endl;
      file.close();
      continue;
    }
    addFile( m_plugin->dirLister()->findByURL( *it ) );
    file.close();
  }

  if( m_playlistView->childCount() == 0 )
    m_widgetStack->raiseWidget( m_emptyLabel );
  else
    m_widgetStack->raiseWidget( m_playlistView );

}
K3bDoc *BurnAudioCDConfigWidget::k3bDoc()
{
  if( m_playlistView->childCount() == 0 )
    return 0;

  K3bAudioDoc *doc = new K3bAudioDoc(this);

  doc->setWritingMode( K3b::WRITING_MODE_AUTO );
  doc->setOnTheFly( true );
  doc->setSpeed(0);
  doc->setRemoveImages(true);
  doc->setWritingApp( K3b::DEFAULT );
  QString tempDir = locateLocal( "tmp", "konqburn-" + QString::number( getpid() ) );
  doc->setTempDir( tempDir );
  doc->setOnlyCreateImages(false);
  doc->setCopies( 1 );

  QMap<int,QString> orderedUrls;
  
  for( QMap<KFileItem*,KListViewItem*>::iterator it = m_playlistMap->begin();
       it != m_playlistMap->end();
       it++ )
    orderedUrls[it.data()->text(0).toInt()] = it.key()->url().url();
      
  //orderedUrls.values() is now a list of KURLs sorted by the track 
  //number (taken from the list view)
  doc->addUrls( KURL::List(QStringList( orderedUrls.values() )) );
  
  doc->setNormalize( false );
  return doc;
}

#include "burnaudiocdconfigwidget.moc"
