/*****************************************************************************
 *   Copyright (C) 2003 by Fred Schaettgen <kdebluetooth@schaettgen.de>
 *   Copyright (C) 2004 by Alex Ibrado <alex@kdex.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.
 *****************************************************************************/

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

#ifdef HAVE_XMMS

#include "xmmscontroller.h"
#include <kprocio.h>
#include <qregexp.h>
#include <xmmsctrl.h>
#include <libkbluetooth/configinfo.h>

XmmsController::XmmsController(QObject* parent) :
    Controller(parent)
{
    stenLength = stopHits = 0;
    stenActive = false;
    controllerInfo.name = "xmms";
    controllerInfo.fileExts = "mp3,m3u,pls";
    controllerInfo.pathToApp = "xmms";
    connect( &stenTimer, SIGNAL(timeout()), SLOT(stenCheck()) );
}

void XmmsController::commandDINF(unsigned int &bitrate,
    unsigned int &sampleRate, unsigned int &channels)
{
    bitrate = 0;
    sampleRate = 0;
    channels = 0;

    // Gets detailed information about the current song
    xmms_remote_get_info(0, (gint *)&bitrate, (gint *)&sampleRate, (gint *)&channels);

    sampleRate /= 1000;
    bitrate /= 1000;
}

void XmmsController::commandFADE() {
    // Stops the current song by fading it out

    stenActive = false;
    if(xmms_remote_is_playing(0)) {
        stopHits = 0;
        int curvol = xmms_remote_get_main_volume(0);
        int deltavol = curvol / 10; // 10*0.5s = 5 seconds
        if(deltavol==0) deltavol=1;
        for(int v=curvol;v>0;v-=deltavol) {
            xmms_remote_set_main_volume(0,v);
            ::usleep(500000); // 0.5 seconds
        }
        xmms_remote_stop(0);
        waitForStop();
        xmms_remote_set_main_volume(0,curvol);
    } else {
        // Do the other stuff in commandSTOP
        commandSTOP();
    }
}

void XmmsController::commandFFWD() {
    // Fast-forwards by five seconds

    int newTime = xmms_remote_get_output_time(0)+5000;
    int maxTime = xmms_remote_get_playlist_time(0, xmms_remote_get_playlist_pos(0));

    if(newTime>maxTime) newTime=maxTime;
    xmms_remote_jump_to_time(0, newTime);

}

Controller::SongInfo XmmsController::commandINFO() {
    // Gets information from XMMS
    Controller::SongInfo info;
    int playlistPos = xmms_remote_get_playlist_pos(0);
    info.length = xmms_remote_get_playlist_time(0, playlistPos)/1000;
    info.currentTime = xmms_remote_get_output_time(0)/1000;
    info.playState = (xmms_remote_is_playing(0)?1:0) | (xmms_remote_is_paused(0)?2:0);
    info.repeat = xmms_remote_is_repeat(0);
    info.shuffle = xmms_remote_is_shuffle(0);
    info.trackName = xmms_remote_get_playlist_title(0, playlistPos);
    return info;
}

Controller::SongInfo XmmsController::commandINF2() {
    // Gets information from XMMS without waiting for PLAY
    return commandINFO();
}

void XmmsController::commandLADD(QString filename) {
    // Adds the specified file to the playlist
    GList *glist = NULL;
    glist = g_list_append(glist, (char *)(filename.latin1()));
    xmms_remote_playlist_add(0, glist);
    g_list_free(glist);
}

QStringList XmmsController::commandLIST() {
    // Lists the entire directory tree
    QStringList ret;
    return ret;
}

void XmmsController::commandNEXT() {
    // Plays the next song in the playlist
    stenActive = false;
    bool wasPlaying = xmms_remote_is_playing(0);
    int oldPos = xmms_remote_get_playlist_pos(0);
    xmms_remote_playlist_next(0);
    if(wasPlaying) waitForTrackChange(oldPos);
}

void XmmsController::commandPAUS() {
    // Pauses the current song
    // Wait for it to pause, max of 0.5s
    bool wasPaused=xmms_remote_is_paused(0);
    xmms_remote_pause(0);
    if(wasPaused)
        waitForStart();
    else
        waitForPause();
}

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

    bool wasPlaying = xmms_remote_is_playing(0);
    int oldPos = xmms_remote_get_playlist_pos(0);
    commandLADD(filename);

    // Make sure it was added
    int newPos=xmms_remote_get_playlist_length(0)-1;
    if(newPos >= 0) {
        xmms_remote_set_playlist_pos(0, newPos);
        xmms_remote_play(0);
        if(wasPlaying) waitForTrackChange(oldPos);
    }
    stenActive = false;
}

QStringList XmmsController::commandPLST(int &curPos, bool useFilenames) {
    // Writes the current playlist to the phone
    unsigned int playlistItems = xmms_remote_get_playlist_length(0);
    QStringList playlistRaw, playlist;
    for (unsigned int n=0; n<playlistItems; ++n) {
        QString s = ( useFilenames ? 
            xmms_remote_get_playlist_file(0, n) 
            : xmms_remote_get_playlist_title(0, n)
        );
        playlist.append(s);
    }
    curPos = xmms_remote_get_playlist_pos(0);
    return playlist;
}

void XmmsController::commandPREV() {
    // Plays the previous song in the playlist
    stenActive = false;
    bool wasPlaying = xmms_remote_is_playing(0);
    int oldPos = xmms_remote_get_playlist_pos(0);
    xmms_remote_playlist_prev(0);
    if(wasPlaying) waitForTrackChange(oldPos);
}

void XmmsController::commandREPT(bool repeat) {
    // Enables or disables repeat mode

    if (xmms_remote_is_repeat(0) != repeat)
        xmms_remote_toggle_repeat(0);
}

void XmmsController::commandRMAL() {
    // Removes all songs from the playlist
    xmms_remote_playlist_clear(0);
}

void XmmsController::commandRWND() {
    // Rewinds by five seconds
    int newTime = xmms_remote_get_output_time(0)-5000;
    if(newTime < 0) newTime=0;
    xmms_remote_jump_to_time(0, newTime);
}

void XmmsController::commandSHFL(bool shuffle) {
    // Enables or disables shuffle mode
    if (xmms_remote_is_shuffle(0) != shuffle)
        xmms_remote_toggle_shuffle(0);
}

void XmmsController::commandSLCT(Q_UINT16 index) {
    // Selects song at [index] in playlist
    int curIndex=xmms_remote_get_playlist_pos(0);
    if(curIndex==index && !xmms_remote_is_playing(0))
        xmms_remote_play(0);
    else
        xmms_remote_set_playlist_pos(0, index);
    stenActive=false;
}

void XmmsController::commandSTEN() {
    // Stops playing at the end of the current song

    if(xmms_remote_is_playing(0) && !stenActive) {
        // STEN is not in effect yet
        stenLength = xmms_remote_get_playlist_time(0, xmms_remote_get_playlist_pos(0));
        if(!stenTimer.isActive()) {
            stenActive=true;
            stenTimer.start(STEN_POLL_TIME);
        }
    } else {
        // User pressed STOP again... 
        // ... mmust really want to stop NOW or delete playlist entry
        commandSTOP();
    }
}

void XmmsController::commandSTOP() {
    // Stops the current song immediately
    stopHits++;
    if(xmms_remote_is_playing(0)) {
        xmms_remote_stop(0);
        stopHits=0;
        waitForStop();
    } else {
        // Secret command
        if(stopHits>=2) {
            xmms_remote_playlist_delete(0, xmms_remote_get_playlist_pos(0));
            stopHits=0;
        }
    }
    stenActive=false;
}

void XmmsController::commandSTRT() {
    // Starts playing the current song
    if(xmms_remote_is_paused(0)) {
        // Unpause
        xmms_remote_pause(0);
    } else if(xmms_remote_is_playing(0)) {
        // Do this so client remains synched
        xmms_remote_jump_to_time(0, 0);
    } else {
        xmms_remote_play(0);
    }
    waitForStart();
    stenActive=false;
}

void XmmsController::commandVOLM(Q_UINT8 volume) {
    // Sets the volume to the value specified
    xmms_remote_set_main_volume(0, 100*volume/255);
}

bool XmmsController::commandFULL() {
    // Toggle fullscreen mode
    return false;
}

void XmmsController::commandSEEK(Q_UINT32 seconds) {
    // Jump to specified position
    xmms_remote_jump_to_time(0, seconds);
}

Q_UINT32 XmmsController::commandPLEN() {
    // Return playlist length
    return xmms_remote_get_playlist_length(0);
}

bool XmmsController::commandGVOL(Q_UINT8 &volume) {
    // Get current volume
    volume=xmms_remote_get_main_volume(0)*255/100;
    return true;
}

int XmmsController::currentIndex() {
    return xmms_remote_get_playlist_pos(0);
}

void XmmsController::stenCheck() {
    // We poll since XMMS doesn't have callbacks (yet)
    if(stenActive) {
        int currentTime = xmms_remote_get_output_time(0);
        //  Check if about to end, or has moved to next
        if(stenLength-currentTime <= STEN_POLL_TIME || currentTime <= STEN_POLL_TIME) {
            stenTimer.stop();
            xmms_remote_stop(0);
            stenActive=false;
            // After stopping, move to the next if it isn't already there
            if(currentTime > STEN_POLL_TIME)
                xmms_remote_playlist_next(0);
        }
    } else {
        stenTimer.stop();
    }
}

void XmmsController::waitForTrackChange(int oldPos) {
    int i=0;
    // Wait for new track to start playing
    // This is done so the client displays the correct song
    // If it doesn't move (e.g. end of playlist), wait max of 0.05 seconds
    while(i<10 && (!xmms_remote_is_playing(0) || (oldPos==xmms_remote_get_playlist_pos(0)))
    ) {
        ::usleep(5000);
        i++;
    }
}

void XmmsController::waitForStart() {
    // Wait to start playing, to sync client display
    // Max 0.05s
    int i=0;
    while(i<10 && (!xmms_remote_is_playing(0) || xmms_remote_is_paused(0))) {
        ::usleep(5000);
        i++;
    }
}

void XmmsController::waitForPause() {
    // Wait for pause, to sync client display
    // Max 0.05s
    int i=0;
    while(i<10 && (!xmms_remote_is_paused(0))) {
        ::usleep(5000);
        i++;
    }
}

void XmmsController::waitForStop() {
    // Wait to stop playing, to sync client display
    // Max 0.05s
    int i=0;
    while(i<10 && (xmms_remote_is_playing(0))) {
        ::usleep(5000);
        i++;
    }
}

XmmsController::~XmmsController()
{
}

#include "xmmscontroller.moc"
#endif // HAVE_XMMS
