/***************************************************************************
 *   Copyright (C) 2005 by Patrick Steiner                                 *
 *   patrick.steiner@a1.net                                                *
 *   Copyright (C) 2005 by Martin Kleinhans                                *
 *   mkleinhans@web.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.                                   *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <dcopclient.h>
#include <kapplication.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#include <kconfig.h>
#include <kurl.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qxml.h>
#include <qdom.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "amarokcontroller.h"

AmarokController::AmarokController(QObject* parent) :
    Controller(parent)
{
    dcopClient = KApplication::dcopClient();
    controllerInfo.name = "amarok";
    controllerInfo.pathToApp = "amarok";
    controllerInfo.playlistMgr= "Server";

    amarokDCOPApp = "amarok";
}

DCOPCall AmarokController::createDCOPCaller(QString sub)
{
    QCStringList apps = dcopClient->registeredApplications();
    QString targetApp = "amarok";

    if(targetApp.isEmpty()) {
        targetApp = "amarok";
    }

    amarokDCOPApp = targetApp;
    return DCOPCall(dcopClient, targetApp, sub);
}

void AmarokController::commandDINF(unsigned int &bitrate,
    unsigned int &sampleRate, unsigned int &channels)
{
    // Gets detailed information about the current song
    // FIXME: amaroK has no dcop call for channels
    QString temp;

    DCOPCall caller = createDCOPCaller();
    
    caller.call("bitrate()");
    caller.ret() >> temp;
    // remove kbps text from string
    QStringList splitTemp = QStringList::split( " ", temp );
    bitrate = splitTemp[0].toInt();
    
    int l;
    caller.call("sampleRate()");
    caller.ret() >> l;
    sampleRate = l/1000;
    
    channels = 2;
}

void AmarokController::commandFADE() {
    // Stops the current song by fading it out
    commandSTOP();
}

// TODO: function not working
void AmarokController::commandFFWD() {
    // Fast-forwards by five seconds
    setPosition(getPosition()+5);
}

Controller::SongInfo AmarokController::commandINFO() {
    // Gets information from the application
    Controller::SongInfo info;
    info.currentTime = getPosition();
    info.length = 0;
    info.playState = 0;
    info.repeat = false;
    info.shuffle = false;
    info.trackName = "Pure morning";

    DCOPCall caller = createDCOPCaller();
    if (caller.call("trackTotalTime()") != "int") {
        kdWarning() << "Error calling amarok::Amarok::trackTotalTime()" << endl;
    }
    else {
        int l;
        caller.ret() >> l;
        info.length = l;
    }

    if (caller.call("status()") != "int") {
        kdWarning() << "Error calling amarok::Amarok::status()" << endl;
    }
    else {
        int s;
        caller.ret() >> s;
        //  Amarok: 0=stopped 1=paused  2=playing
        // Bemused: 0=stopped 1=playing 3=paused
        if(s > 0)
            s = (s==1)? 3 : 1;
        info.playState = s;
    }

    if (caller.call("nowPlaying()") != "QString") {
        kdWarning() << "Error calling amarok::amarok::nowPlaying()" << endl;
    }
    else {
        QString t;
        caller.ret() >> t;
        info.trackName = t;
    }

    return info;
}

Controller::SongInfo AmarokController::commandINF2() {
    return commandINFO();
}

void AmarokController::commandLADD(QString filename) {
    // Adds the specified file to the playlist
    DCOPCall caller = createDCOPCaller("playlist");
	caller.args() << KURL(filename,0);
    if(caller.call("addMedia(KURL)") != "void") {
        kdWarning() << "Error calling amarok::playlist::addMedia()" << endl;
    }

}

void AmarokController::commandNEXT() {
    // Plays the next song in the playlist
    DCOPCall caller = createDCOPCaller();
    if (caller.call("next()") != "void") {
        kdWarning() << "Error calling amarok::player::forward()" << endl;
    }
}

void AmarokController::commandPAUS() {
    // Pauses the current song
    DCOPCall caller = createDCOPCaller();
    if (caller.call("playPause()") != "void") {
        kdWarning() << "Error calling amarok::Amarok::pause()" << endl;
    }
}

void AmarokController::commandPLAY(QString filename, bool clear) {
    // Plays the specified file
    if(clear)
        commandRMAL();

    DCOPCall caller = createDCOPCaller("playlist");
	caller.args() << KURL(filename,0);
    if (caller.call("playMedia(KURL)") != "void") {
        kdWarning() << "Error calling amarok::playlist::addMedia()" << endl;
    }
}

bool AmarokController::startElement(const QString &namespaceURI, const QString &localName,
        const QString &qName, const QXmlAttributes &atts )
{
	cdata = QString::null;
    if (qName == "item")
	{
		for (int i=0; i<atts.count(); i++) {
			QString att = atts.qName(i);
			QString val= atts.value(i);
			if(att == "url")
			{
				curEntry.url = val;
			}
		}
		curEntry.track = numTracks++;
		curEntry.title = QString::null;
		curEntry.artist = QString::null;
	}
    return true;
}

bool AmarokController::endElement( const QString &, const QString &, const QString &qn )
{
	if(qn == "item")
		playlistEntries.push_back(curEntry);
	else if(qn == "Artist")
		curEntry.artist = cdata;
	else if(qn == "Title")
		curEntry.title = cdata;

	return true;
}

bool AmarokController::characters( const QString &chars )
{
	cdata = cdata + chars;

	return true;
}

QStringList AmarokController::commandPLST(int &curPos, bool useFilenames) {
    // Writes the current playlist to the phone
    curPos = 0;
    QStringList playlist;

    DCOPCall caller = createDCOPCaller("playlist");
    // Save Playlist
    if (caller.call("saveCurrentPlaylist()") != "void") {
        kdWarning() << "Error calling amarok::playlist::saveCurrentPlaylist()" << endl;
    }
    // parse Playlist
    QString playlistFile =  locate("data", "amarok/current.xml");
    QFile f(playlistFile);
    if(f.open( IO_ReadOnly )) {
        QXmlInputSource source(&f);
        QXmlSimpleReader reader;
        reader.setContentHandler(this);
        playlistEntries.clear();
        numTracks = 0;
        reader.parse(source);
        f.close();
        // Generate Bemused Playlist
        std::vector<PlaylistEntry>::iterator it;
        for (it = playlistEntries.begin(); it!=playlistEntries.end(); ++it) {
            if(it->artist != QString::null and it->title != QString::null)
                playlist.append(it->artist + " - " + it->title);
                else
                {
                    KURL url = KURL(it->url);
                    playlist.append(url.fileName(1));
                }
            }
    }
    return playlist;
}

void AmarokController::commandPREV() {
    // Plays the previous song in the playlist
    DCOPCall caller = createDCOPCaller();
    if (caller.call("prev()") != "void") {
        kdWarning() << "Error calling amarok::Amarok::back()" << endl;
    }
}

// TODO: function not working
void AmarokController::commandREPT(bool /*repeat*/) {
    // Enables or disables repeat mode
    //DCOPCall caller = createDCOPCaller();
    //if (caller.call("loop()") != "void") {
    //   kdWarning() << "Error calling amarok::Amarok::repeat()" << endl;
    //}
}

void AmarokController::commandRMAL() {
    // Removes all songs from the playlist
    DCOPCall caller = createDCOPCaller("playlist");
    if (caller.call("clearPlaylist()") != "void") {
        kdWarning() << "Error calling amarok::playlist::clearPlaylist()" << endl;
    }
}

void AmarokController::commandRWND() {
    // Rewinds by five seconds
    setPosition(getPosition()-5);
}

void AmarokController::commandSHFL(bool shuffle) {
    // Enables or disables shuffle mode
    DCOPCall caller = createDCOPCaller();
    caller.args() << shuffle;
    if (caller.call("enableRandomMode(bool)") != "void") {
        kdWarning() << "Error calling amarok::player::enableRandomMode()" << endl;
    }
}

void AmarokController::commandSLCT(Q_UINT16 index) {
    // Selects song at [index] in playlist
    DCOPCall caller = createDCOPCaller("playlist");
    caller.args() << int(index);
    if(caller.call("playByIndex(int)") != "void") {
		kdWarning() << "Error calling amarok::playlist::playByIndex()" << endl;
	}
}

void AmarokController::commandSTEN() {
    // Stops playing at the end of the current song
    DCOPCall caller = createDCOPCaller("playlist");
	caller.args() << true;
    caller.call("setStopAfterCurrent(bool)");
}

void AmarokController::commandSTOP() {
    // Stops the current song immediately
    DCOPCall caller = createDCOPCaller();
    if (caller.call("stop()") != "void") {
        kdWarning() << "Error calling amarok::Amarok::stop()" << endl;
    }
}

void AmarokController::commandSTRT() {
    // Starts playing the current song
    DCOPCall caller = createDCOPCaller();
    if (caller.call("play()") != "void") {
        kdWarning() << "Error calling amarok::Amarok::play()" << endl;
    }
}

void AmarokController::commandVOLM(Q_UINT8 volume) {
    // Sets the volume to the value specified
    DCOPCall caller = createDCOPCaller();
    caller.args() << volume*100/255;
    if (caller.call("setVolume(int)") != "void") {
        kdWarning() << "Error calling amarok::Amarok::setVolume(int)" << endl;
    }
}

bool AmarokController::commandFULL() {
    // Toggle fullscreen mode
	// amaroK has nothing like this
    return false;
}

int AmarokController::getPosition()
{
    DCOPCall caller = createDCOPCaller();
    if (caller.call("trackCurrentTime()") != "int") {
        kdWarning() << "Error calling amarok::Amarok::position(int)" << endl;
        return 0;
    }
    int ret = 0;
    caller.ret() >> ret;
    
    return ret;
}

void AmarokController::setPosition(int pos)
{
    DCOPCall caller = createDCOPCaller();
    caller.args() << int(pos*1000);
    if (caller.call("seek(int)") != "void") {
        kdWarning() << "Error calling amarok::amarok::seek(int)" << endl;
    }
}

void AmarokController::commandSEEK(Q_UINT32 seconds) {
    // Jump to specified position
    setPosition(seconds*1000); // milliseconds
}

Q_UINT32 AmarokController::commandPLEN() {
    return numTracks;
}

bool AmarokController::commandGVOL(Q_UINT8 &volume) {
    // Get current volume
    DCOPCall caller = createDCOPCaller();
    if (caller.call("getVolume()") != "int") {
        kdWarning() << "Error calling amarok::Amarok::setVolume(int)" << endl;
        return false;
    }
    Q_UINT8 ret = 0;
    caller.ret() >> ret;
    volume=Q_UINT8(2.55*ret);
    return true;
}

int AmarokController::currentIndex() {
    DCOPCall caller = createDCOPCaller("playlist");
    if(caller.call("getActiveIndex()") == "int") {
		int ret;
		caller.ret() >> ret;
  		return ret;
    }
	return 0;
}

AmarokController::~AmarokController()
{
}

#include "amarokcontroller.moc"
