#include "cdmanager.h"
#include "paranoia.h"
#include "cddb.h"
#include "conversionoptions.h"

#include <tqstringlist.h>
#include <tqvaluelist.h>

#include <klocale.h>
#include <kmessagebox.h>
#include <kinputdialog.h>
#include <dcopref.h>


// ### soundkonverter 0.4 implement reading of milliseconds/frames

// TODO implement reading of cd data

CDDevice::CDDevice( const TQString& _device )
{
    TQStringList s;
    bool init = false;
    TQValueList<int> qvl;
    int i;
    TQStringList dcopList, devList;
    bool ok = false;

    tags.clear();

    if( !_device.isEmpty() )
        s.append( _device );
    else {
        DCOPRef mediamanager( "kded", "mediamanager" );
        DCOPReply reply = mediamanager.call( "fullList()" );
        if( reply.isValid() ) {
            dcopList = reply;
            i = 0;
            while( i < (int)dcopList.count() ) {
                if( dcopList[i+10] == "media/audiocd" ) {
                    devList.append( dcopList[i+5] );
                }
                i += 13;
            }
            if( devList.count() > 1 ) {
                TQString choice = KInputDialog::getItem( i18n("Audio CD"), i18n("Several audio CDs found. Choose one:"), devList, 0, false, &ok );
                if( ok ) s.append( choice );
                else s.append( 0 ); // TODO if canceled, the cd opener should close, not use the first item
            }
            else if( devList.count()==1 ) {
                s.append( devList[0] );
            }
            else {
                s.append( "/dev/cdrom" );
                s.append( "/dev/dvd" );
            }
        }
        else {
            s.append( "/dev/cdrom" );
            s.append( "/dev/dvd" );
        }
    }

    para = new Paranoia();
    for( i = 0; i < (int)s.count(); i++ ) {
        if( init = para->init(s[i]) ) {
            device = s[i];
            break;
        }
    }
    if( init ) {
        trackCount = para->getTracks();
        timeCount = para->trackTime( -1 );
        for( i = 0; i < para->getTracks(); i++) {
            qvl.append( para->trackFirstSector(i+1) + 150 );
        }
        qvl.append( para->discFirstSector() );
        qvl.append( para->discLastSector() );
        CDDB* cddb = new CDDB();
        cddb->save_cddb( true );
        if( cddb->queryCD(qvl) ) {
            for( i = 0; i < para->getTracks(); i++ ) {
               tags += new TagData( cddb->artist(i), "", cddb->title(), cddb->track(i), cddb->genre(), "",
                                      i+1, cddb->disc(), cddb->year(), para->trackTime(i) );
            }
        }
        else {
            cddb->set_server( "freedb.freedb.org", 8880 );
            if( cddb->queryCD(qvl) ) {
                for( i = 0; i < para->getTracks(); i++ ) {
                    tags += new TagData( cddb->artist(i), "", cddb->title(), cddb->track(i), cddb->genre(), "",
                                           i+1, cddb->disc(), cddb->year(), para->trackTime(i) );
                }
            }
            else {
                for( i = 0; i < para->getTracks(); i++ ) {
                    tags += new TagData( i18n("Unknown"), "", i18n("Unknown"), i18n("Unknown"), "", "", i+1, 1, 0, para->trackTime(i) );
                }
            }
        }
        delete cddb;
    }
    else {
        KMessageBox::information( 0, i18n("No audio CD found."), i18n("Warning") );
        device = "";
        delete para;
        para = 0;
    }
}

CDDevice::~CDDevice()
{}


CDManager::CDManager()
{}

CDManager::~CDManager()
{
    while( cdDevices.count() > 0 ) delete cdDevices.first();
}

TQString CDManager::newCDDevice( const TQString& device )
{
    CDDevice* cdDevice = new CDDevice( device );

    for( TQValueList<CDDevice*>::Iterator it = cdDevices.begin(); it != cdDevices.end(); ++it ) {
        if( (*it)->device = cdDevice->device ) {
            cdDevices.remove( *it );
            delete (*it);
            break;
        }
    }

    cdDevices += cdDevice;
    return cdDevice->device;
}

TQValueList<TagData*> CDManager::getTrackList( const TQString& device )
{
    for( TQValueList<CDDevice*>::Iterator it = cdDevices.begin(); it != cdDevices.end(); ++it ) {
        if( (*it)->device = device ) return (*it)->tags;
    }

    TQValueList<TagData*> list;
    return list;
}

TagData* CDManager::getTags( const TQString& device, int track )
{
    for( TQValueList<CDDevice*>::Iterator it = cdDevices.begin(); it != cdDevices.end(); ++it ) {
        if( (*it)->device = device ) {
            if( track > 0 ) {
                TQValueList<TagData*>::Iterator tag = (*it)->tags.at( track - 1 );
                return (*tag);
            }
            else {
                return (*it)->discTags;
            }
        }
    }

    return 0;
}

int CDManager::getTrackCount( const TQString& device )
{
    for( TQValueList<CDDevice*>::Iterator it = cdDevices.begin(); it != cdDevices.end(); ++it ) {
        if( (*it)->device = device ) return (*it)->trackCount;
    }

    return 0;
}

int CDManager::getTimeCount( const TQString& device )
{
    for( TQValueList<CDDevice*>::Iterator it = cdDevices.begin(); it != cdDevices.end(); ++it ) {
        if( (*it)->device = device ) return (*it)->timeCount;
    }

    return 0;
}

void CDManager::setDiscTags( const TQString& device, TagData* tags )
{
    for( TQValueList<CDDevice*>::Iterator it = cdDevices.begin(); it != cdDevices.end(); ++it ) {
        if( (*it)->device = device ) (*it)->discTags = tags;
    }
}