/******************************************************************************!
 * \file player-xmms.c
 * \author Sebastien Beaugrand
 * \sa http://beaugrand.chez.com/
 * \copyright CeCILL 2.1 Free Software license
 ******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xmmsclient/xmmsclient.h>
#include "player.h"
#include "mp3server.h"
#include "log.h"
#include "html.h"
#include "common.h"

xmmsc_connection_t* gConn = NULL;

/******************************************************************************!
 * \fn playerInit
 ******************************************************************************/
int playerInit()
{
    int ret = 0;

    gConn = xmmsc_init("MP3");

    if (system("xmms2-launcher -i unix:///run/xmms-ipc-ip"
               " 2>/run/xmms2-launcher.log") != EXIT_SUCCESS) {
        DEBUG("warning: system xmms2-launcher != 0");
    }
    ret = xmmsc_connect(gConn, NULL);

    return ret;
}

/******************************************************************************!
 * \fn playerIsError
 ******************************************************************************/
int playerIsError(xmmsv_t* val, const char* func)
{
    const char* err;

    if (xmmsv_is_error(val)) {
        if (xmmsv_get_error(val, &err)) {
            ERROR("%s: %s", func, err);
        } else {
            ERROR("%s", func);
        }
        return 1;
    }
    return 0;
}

/******************************************************************************!
 * \fn playerGetStatus
 ******************************************************************************/
int32_t playerGetStatus()
{
    xmmsc_result_t* res;
    xmmsv_t* val;
    int32_t status;

    res = xmmsc_playback_status(gConn);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
        xmmsc_result_unref(res);
        return 0;
    }
    xmmsv_get_int(val, &status);
    xmmsc_result_unref(res);

    return status;
}

/******************************************************************************!
 * \fn playerGetPlaytime
 ******************************************************************************/
int32_t playerGetPlaytime()
{
    xmmsc_result_t* res;
    xmmsv_t* val;
    int32_t status;
    int32_t playtime;

    // Status
    status = playerGetStatus();
    if (status != XMMS_PLAYBACK_STATUS_PLAY &&
        status != XMMS_PLAYBACK_STATUS_PAUSE) {
        return 0;
    }

    // Playtime
    res = xmmsc_playback_playtime(gConn);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
        xmmsc_result_unref(res);
        return 0;
    }
    xmmsv_get_int(val, &playtime);
    xmmsc_result_unref(res);

    return playtime;
}

/******************************************************************************!
 * \fn playerGetPosition
 ******************************************************************************/
int playerGetPosition()
{
    xmmsc_result_t* res;
    xmmsv_t* val;
    int pos;

    res = xmmsc_playlist_current_pos(gConn, XMMS_ACTIVE_PLAYLIST);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (! xmmsv_dict_entry_get_int(val, "position", &pos)) {
        ERROR("xmmsv_dict_entry_get_int");
        pos = 0;
    }
    xmmsc_result_unref(res);
    DEBUG("pos = %d", pos);

    return pos;
}

/******************************************************************************!
 * \fn playerTitleList
 ******************************************************************************/
struct Buffer* playerTitleList(struct Buffer* buffer, enum tFormat format)
{
    xmmsc_result_t* res;
    xmmsv_t* val;
    xmmsv_list_iter_t* it;
    xmmsv_t* entry;
    xmmsc_result_t* infores;
    xmmsv_t* infoval;
    int32_t id;
    int32_t playtime;
    int pos;
    int duration;
    const char* strval = NULL;
    int count = 0;
    char href[LINE_SIZE];
    FILE* buffFile = bufferInit(buffer);

    // Position
    pos = playerGetPosition();

    if (format == HTML) {
        fseek(buffFile, httpGetHttpOkSize(), SEEK_SET);
        fprintf(buffFile, "%s", htmlGetBegin());
    }

    // List
    res = xmmsc_playlist_list_entries(gConn, XMMS_ACTIVE_PLAYLIST);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);

    for (xmmsv_get_list_iter(val, &it);
         xmmsv_list_iter_valid(it);
         xmmsv_list_iter_next(it), ++count) {
        xmmsv_list_iter_entry(it, &entry);
        if (xmmsv_get_int(entry, &id)) {
            DEBUG("id = %d", id);
            if (count == pos) {
                fprintf(buffFile, "->");
                DEBUG("count == pos");
            } else {
                fprintf(buffFile, "  ");
            }
            infores = xmmsc_medialib_get_info(gConn, id);
            xmmsc_result_wait(infores);
            infoval =
                xmmsv_propdict_to_dict(xmmsc_result_get_value(infores), NULL);

            fprintf(buffFile, "[%02d] ", count + 1);
            if ((xmmsv_dict_entry_get_string) (infoval, "artist", &strval)) {
                fprintf(buffFile, "%s", strval);
            }
            if ((xmmsv_dict_entry_get_string) (infoval, "title", &strval)) {
                fprintf(buffFile, " - ");
                if (count == pos) {
                    fprintf(buffFile, "%s", strval);
                } else {
                    if (format == HTML) {
                        sprintf(href, "<a href=\"/pos/%d\">%s</a>",
                                count, strval);
                        fprintf(buffFile, "%s", href);
                    } else {
                        fprintf(buffFile, "%s", strval);
                    }
                }
                DEBUG("%s", strval);
            }
            if ((xmmsv_dict_entry_get_int) (infoval, "duration", &duration)) {
                duration /= 1000;
                if (count == pos) {
                    playtime = playerGetPlaytime();
                    if (playtime != 0) {
                        playtime /= 1000;
                        fprintf(buffFile,
                                " (%02d:%02d/%02d:%02d)",
                                playtime / 60,
                                playtime % 60,
                                duration / 60,
                                duration % 60);

                    } else {
                        fprintf(buffFile, " (%02d:%02d)",
                                duration / 60,
                                duration % 60);
                    }
                } else {
                    fprintf(buffFile, " (%02d:%02d)",
                            duration / 60,
                            duration % 60);
                }
            }
            if (format == HTML) {
                fprintf(buffFile, "<br/>");
            } else {
                fprintf(buffFile, "\n");
            }

            xmmsc_result_unref(infores);
            xmmsv_unref(infoval);
        }
    }

    if (format == HTML) {
        fprintf(buffFile, "%s", htmlGetEnd());
    }

    xmmsc_result_unref(res);

    return buffer;
}

/******************************************************************************!
 * \fn playerStop
 ******************************************************************************/
void playerStop()
{
    xmmsc_result_t* res;
    xmmsv_t* val;

    res = xmmsc_playback_stop(gConn);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
    }
    xmmsc_result_unref(res);
}

/******************************************************************************!
 * \fn playerStart
 ******************************************************************************/
void playerStart()
{
    xmmsc_result_t* res;
    xmmsv_t* val;

    res = xmmsc_playback_start(gConn);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
    }
    xmmsc_result_unref(res);
}

/******************************************************************************!
 * \fn playerStartId
 ******************************************************************************/
void playerStartId(int pos)
{
    xmmsc_result_t* res;

    res = xmmsc_playlist_set_next(gConn, pos);
    xmmsc_result_wait(res);
    xmmsc_result_unref(res);

    res = xmmsc_playback_tickle(gConn);
    xmmsc_result_wait(res);
    xmmsc_result_unref(res);

    playerStart();
}

/******************************************************************************!
 * \fn playerStartRel
 ******************************************************************************/
void playerStartRel(int pos)
{
    xmmsc_result_t* res;

    res = xmmsc_playlist_set_next_rel(gConn, pos);
    xmmsc_result_wait(res);
    xmmsc_result_unref(res);

    res = xmmsc_playback_tickle(gConn);
    xmmsc_result_wait(res);
    xmmsc_result_unref(res);

    playerStart();
}

/******************************************************************************!
 * \fn playerPause
 ******************************************************************************/
void playerPause()
{
    xmmsc_result_t* res;
    xmmsv_t* val;
    int32_t status;

    // Status
    status = playerGetStatus();

    // Pause
    if (status == XMMS_PLAYBACK_STATUS_PAUSE) {
        res = xmmsc_playback_start(gConn);
    } else {
        res = xmmsc_playback_pause(gConn);
    }
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
    }
    xmmsc_result_unref(res);
}

/******************************************************************************!
 * \fn playerResume
 ******************************************************************************/
void playerResume()
{
    xmmsc_result_t* res;
    xmmsv_t* val;
    int32_t status;
    char filename[LINE_SIZE];
    FILE* fp;
    int milliseconds;

    strcpy(filename, mp3serverGetMp3rootDir());
    strcat(filename, "/.mp3time");
    fp = fopen(filename, "r");
    if (fp == NULL) {
        return;
    }
    if (fscanf(fp, "%10d", &milliseconds) != 1) {
        fclose(fp);
        return;
    }
    fclose(fp);
    DEBUG("milliseconds = %d", milliseconds);

    // Status
    status = playerGetStatus();
    if (status != XMMS_PLAYBACK_STATUS_PLAY) {
        playerStart();
        sleep(2);
    }

    // Seek
    res = xmmsc_playback_seek_ms(gConn, milliseconds,
                                 XMMS_PLAYBACK_SEEK_SET);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
    }
    xmmsc_result_unref(res);

    unlink(filename);
}

/******************************************************************************!
 * \fn playerM3u
 ******************************************************************************/
void playerM3u(const char* m3u)
{
    xmmsc_result_t* res;
    xmmsc_result_t* res2;
    xmmsv_t* val;
    xmmsv_coll_t* coll = NULL;

    playerStop();

    // Clear
    res = xmmsc_playlist_clear(gConn, XMMS_ACTIVE_PLAYLIST);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
    }
    xmmsc_result_unref(res);

    // Coll
    res = xmmsc_coll_idlist_from_playlist_file(gConn, m3u);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (playerIsError(val, __FUNCTION__)) {
    }
    xmmsv_get_coll(val, &coll);

    // Add
//  version > 0.8 :
//  res2 = xmmsc_playlist_add_idlist(gConn, XMMS_ACTIVE_PLAYLIST, val);
    res2 = xmmsc_playlist_add_idlist(gConn, XMMS_ACTIVE_PLAYLIST, coll);
    xmmsc_result_wait(res2);
    val = xmmsc_result_get_value(res2);
    if (playerIsError(val, __FUNCTION__)) {
    }

    xmmsc_result_unref(res2);
    xmmsc_result_unref(res);

    playerStart();
}

/******************************************************************************!
 * \fn playerCurrentTitle
 ******************************************************************************/
struct Buffer* playerCurrentTitle(struct Buffer* buffer)
{
    FILE* buffFile = bufferInit(buffer);

    xmmsc_result_t* res;
    xmmsc_result_t* infores;
    xmmsv_t* val;
    xmmsv_t* infoval;
    xmmsv_list_iter_t* it;
    xmmsv_t* entry;
    int32_t status;
    int32_t id;
    int pos;
    int count = 0;
    const char* strval = NULL;
#   if defined(__arm__) || defined(__aarch64__)
    const char* c;
#   endif

    // Status
    status = playerGetStatus();
    if (status == XMMS_PLAYBACK_STATUS_PAUSE) {
        fprintf(buffFile, "PAUSE ");
    }

    // Position
    pos = playerGetPosition();
    fprintf(buffFile, "%02d ", pos + 1);

    // Title
/*
    res = xmmsc_playback_current_id(mConn);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    if (! xmmsv_get_int(val, &id)) {
        strval = "erreur: playerCurrentTitle xmmsv_get_int";
        DEBUG("%s", strval);
        fprintf(buffFile, "%s", strval);
        return buffer;
    }
    infores = xmmsc_medialib_get_info(mConn, id);
    xmmsc_result_wait(infores);
    info = xmmsv_propdict_to_dict(xmmsc_result_get_value(infores), NULL);
    if (xmmsv_dict_entry_get_string(info, "title", &strval)) {
        fprintf(buffFile, "%s", strval);
    }
    xmmsv_unref(info);
    xmmsc_result_unref(infores);
    xmmsc_result_unref(res);
 */
    res = xmmsc_playlist_list_entries(gConn, XMMS_ACTIVE_PLAYLIST);
    xmmsc_result_wait(res);
    val = xmmsc_result_get_value(res);
    for (xmmsv_get_list_iter(val, &it);
         xmmsv_list_iter_valid(it);
         xmmsv_list_iter_next(it), ++count) {
        if (count != pos) {
            continue;
        }
        xmmsv_list_iter_entry(it, &entry);
        if (! xmmsv_get_int(entry, &id)) {
            break;
        }
        infores = xmmsc_medialib_get_info(gConn, id);
        xmmsc_result_wait(infores);
        infoval = xmmsv_propdict_to_dict(xmmsc_result_get_value(infores), NULL);
        if ((xmmsv_dict_entry_get_string) (infoval, "title", &strval)) {
#           if defined(__arm__) || defined(__aarch64__)
            for (c = strval; *c != '\0'; ++c) {
                if (c[0] == ' ' &&
                    c[1] == '-' &&
                    c[2] == ' ') {
                    strval = c + 3;
                    break;
                }
            }
#           endif
            fprintf(buffFile, "%s", strval);
        }
        xmmsv_unref(infoval);
        xmmsc_result_unref(infores);
        xmmsc_result_unref(res);
        break;
    }

    return buffer;
}

/******************************************************************************!
 * \fn playerQuit
 ******************************************************************************/
void playerQuit()
{
    if (gConn != NULL) {
        xmmsc_unref(gConn);
    }
}