/***************************************************************************
 *   Copyright (C) 2006 by Jens Koehler                                    *
 *   irimi_at_gmx_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.                                   *
 *                                                                         *
 *   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 <vdr/device.h>
#include <linux/dvb/video.h>

#include "amarokPlayer.h"
#include "menuAmarok.h"
#include "menuAmarokSetup.h"

//#include <iostream>


namespace
{

const char *PLAYER_MAIN_BACKROUND = "/amarokmain.mpg";
const int THREAD_WAIT_TIME = 7000;
const int SYNC_NOW = 8;
};

/////////////////////////////////////////////////////////////////////////
////////// cStillPlayer
/////////////////////////////////////////////////////////////////////////

cStillPlayer::cStillPlayer()
{
    cDevice::PrimaryDevice()->AttachPlayer(this);
}


cStillPlayer::~cStillPlayer()
{}

// code has been copied from vdr-radio plugin class cRadioAudio
void cStillPlayer::showImage(const char *file)
{
    //DeviceFreeze();
    uchar *buffer;
    int fd;
    struct stat st;
    struct video_still_picture sp;
    if ((fd = open (file, O_RDONLY)) >= 0)
    {
        fstat (fd, &st);
        sp.iFrame = (char *) malloc (st.st_size);
        if (sp.iFrame)
        {
            sp.size = st.st_size;
            if (read (fd, sp.iFrame, sp.size) > 0)
            {
                buffer = (uchar *) sp.iFrame;
                DeviceStillPicture(buffer, sp.size);
            }
            free (sp.iFrame);
        }
        close (fd);
    }
    else
        esyslog ("still picture file %s not found", file);
}
/////////////////////////////////////////////////////////////////////////
////////// cAmarokPlayer
/////////////////////////////////////////////////////////////////////////


cAmarokPlayer::cAmarokPlayer(cMenuAmBase* pOsdMenu) :cThread("AmarokPlayer"),
        p_StillPlayer(0),
        p_ListMenu(pOsdMenu),
        p_TrackMenu(0),
        p_Track(0),
        b_Sleep(false)
{}


cAmarokPlayer::~cAmarokPlayer()
{
    m_commander.stop();
    m_commander.client_shutdown();
    deleteCurrentTrack();

    delete p_StillPlayer;
}

const char* cAmarokPlayer::initialize()
{

    const char* tmp=0;
    if ( !(tmp=connectHost()) )
    {
        startStillPlayer();
        createPlaylist();
        Activate(true);
    }

    return tmp;
}

void cAmarokPlayer::deleteCurrentTrack()
{
    delete p_Track;
    p_Track=0;
}

void cAmarokPlayer::startStillPlayer()
{
    p_StillPlayer = new cStillPlayer();
    if (g_amarokConfig.p_ConfigDir)
    {
        std::string tmp (g_amarokConfig.p_ConfigDir);
        tmp.append(PLAYER_MAIN_BACKROUND);
        p_StillPlayer->showImage(tmp.c_str());
    }
}
const char* cAmarokPlayer::connectHost()
{

    if (!m_commander.connect(g_amarokConfig.m_AmarokHost,g_amarokConfig.m_AmarokPort))
        return tr("Connection to amaroK host has failed");
    else if (!m_commander.login(g_amarokConfig.m_AmarokUser,g_amarokConfig.m_AmarokPw))
        return tr("amaroK host login has failed");


    return 0;
}

void cAmarokPlayer::setSleep(bool bSleep)
{
    Lock();
    b_Sleep = bSleep;
    Unlock();
}

bool cAmarokPlayer::getSleep()
{
    Lock();
    bool ret = b_Sleep;
    Unlock();
    return ret;
}

void cAmarokPlayer::Action()
{
    static int sync=0;

    while (Running())
    {
        cCondWait::SleepMs(THREAD_WAIT_TIME);
        while (getSleep())
        {
            setSleep (false);
            cCondWait::SleepMs(THREAD_WAIT_TIME);
        }

        if (!p_TrackMenu)
            updatePlaylist();
        else
            updateTrackview();


        if (sync++ > SYNC_NOW)
        {
            sync=0;
            checkSyncPlaylist();
        }
    }
}
void cAmarokPlayer::Activate(bool On)
{
    if    (On)
        Start();
    else
        Cancel();
}
void cAmarokPlayer::attachTrackMenu(cMenuAmBase* pMenu)
{
    Lock();
    p_TrackMenu = pMenu;
    deleteCurrentTrack();
    Unlock();

}

void cAmarokPlayer::detachTrackMenu()
{
    Lock();
    if (Active())
        Activate(false);
    p_TrackMenu = 0;
    Activate(true);
    Unlock();

}

void cAmarokPlayer::createPlaylist()
{
    Lock();
    m_commander.getCurrentPlaylist(m_Playlist);
    Unlock();
    if (m_Playlist.getListSize())
    {
        for (unsigned int i=0; i<m_Playlist.getListSize(); i++)
        {
            PlaylistItem *item=0;
            m_Playlist.getPlaylistItem(&item,i);
            if (item)
            {
                char str[MAX_ITEM_CHAR_SIZE];
                item->getShortTextContent(str,i);
                p_ListMenu->addOsdItem(str);
            }
        }
    }
    else
        p_ListMenu->addOsdItem(tr("Empty list"),false);

    p_ListMenu->Display();
}

void cAmarokPlayer::clearPlaylist()
{
    m_Playlist.clearList();
    p_ListMenu->clearMenu();
    Lock();
    m_commander.clearPlaylist();
    Unlock();
}

void cAmarokPlayer::loadPlaylist(const char* plist)
{
    Lock();
    m_commander.loadPlaylist(plist);
    Unlock();
}

void cAmarokPlayer::shufflePlaylist()
{
    Lock();
    m_commander.shufflePlaylist();
    Unlock();

    rebuildPlaylist();

}

void cAmarokPlayer::rebuildPlaylist()
{
    // first delete old
    m_Playlist.clearList();
    p_ListMenu->clearMenu();
    // create new
    createPlaylist();
    p_ListMenu->Display();
}


void cAmarokPlayer::removeTrack(unsigned int index)
{
    Lock();
    if (index == (unsigned)m_commander.getActiveIndex()) // active is removed !
    {
        if (index<m_Playlist.getListSize())
            m_commander.next();
        else
            m_commander.prev();
    }

    m_commander.removeByIndex(index);
    Unlock();
    m_Playlist.removePlaylistItem(index);
}

void cAmarokPlayer::play(unsigned int index)
{
    Lock();
    m_commander.playByIndex(index);
    Unlock();
    //if (!Active())
    //  Activate(true);

}

void cAmarokPlayer::playPause()
{
    Lock();
    m_commander.playPause();
    Unlock();

}

void cAmarokPlayer::stop()
{
    Lock();
    m_commander.stop();
    Unlock();
    //if (Active())
    //  Activate(false);

}
void cAmarokPlayer::next()
{
    Lock();
    m_commander.next();
    Unlock();
}
void cAmarokPlayer::prev()
{
    Lock();
    m_commander.prev();
    Unlock();
}

void cAmarokPlayer::seekRelative(int seconds)
{
    Lock();
    m_commander.seekRelative(seconds);
    Unlock();
}

void cAmarokPlayer::pause()
{
    Lock();
    m_commander.pause();
    Unlock();
}

void cAmarokPlayer::mute()
{
    Lock();
    m_commander.mute();
    Unlock();
}

void cAmarokPlayer::volumeUp()
{
    Lock();
    m_commander.volumeUp();
    Unlock();
}

void cAmarokPlayer::volumeDown()
{
    Lock();
    m_commander.volumeDown();
    Unlock();
}

void cAmarokPlayer::showOsd()
{
    Lock();
    m_commander.showOsd();
    Unlock();
}

void cAmarokPlayer::checkSyncPlaylist()
{
    Lock();
    unsigned int count= m_commander.getTotalTrackCount();
    //@ Todo when current Amarok playlist size has same size as old amarok list
    Unlock();
    if (m_Playlist.getListSize()!=count)
    {
        rebuildPlaylist();
        if (p_TrackMenu && p_Track)
            p_Track->Index=-1;
    }

}

bool cAmarokPlayer::checkRemoteIsPlaying()
{
    return false;
}

void cAmarokPlayer::updatePlaylist()
{
    Lock();
    int index= m_commander.getActiveIndex();
    Unlock();
    if (index>=0)
    {
        p_ListMenu->setCurrentOsdItem(index);
    }

}

void cAmarokPlayer::updateTrackview()
{
    if (!p_Track)
        return;

    Lock();
    int index= m_commander.getActiveIndex();
    Unlock();
    // Track has changed ?
    if (index>=0 && index != p_Track->Index)
    {
        p_TrackMenu->clearMenu();
        deleteCurrentTrack();
        buildTrackview();
    }
    else
        updateTracktime();

}
void cAmarokPlayer::buildTrackview()
{
    Lock();
    int index= m_commander.getActiveIndex();
    if (index>=0)
    {
        AmarokData data;
        int count=m_commander.getTrackPlayCounter();
        int score=m_commander.getScore();
        Unlock();
        if (p_Track)
        {
            esyslog("ERROR:p_Track exists\n");
            return;
        }
        PlaylistItem *item=0;
        m_Playlist.getPlaylistItem(&item,index);


        char str[MAX_ITEM_CHAR_SIZE];
        snprintf(str, MAX_ITEM_CHAR_SIZE, "%d x %s , %s = %d",
                 count,
                 tr("played"),
                 tr("score"),
                 score);


        p_Track= new TrackItem(item,index,m_Playlist.getListSize(),str);


    }
    else
        Unlock();

    dynamic_cast<cMenuAmarokTrack *>(p_TrackMenu)->showTrackinfo(p_Track);

}

void cAmarokPlayer::updateTracktime()
{
    Lock();
    int current=m_commander.getTrackCurrentTime();
    Unlock();
    char str[MAX_ITEM_CHAR_SIZE];
    p_Track->getFormatTimeTrIdx(str,tr("Time"),tr("Track"),current,false);
    p_TrackMenu->setOsdItemText(str);

}

void cAmarokPlayer::queryLists(AmarokQueryResult &result)
{
    Lock();
    m_commander.queryLists(result);
    Unlock();
#ifdef AMAROK_DEBUG

    result.debugList();
#endif
}

void cAmarokPlayer::addArtist(const char* name)
{
    Lock();
    m_commander.addArtist(name);
    Unlock();
}
void cAmarokPlayer::addAlbum(const char* name)
{
    Lock();
    m_commander.addAlbum(name);
    Unlock();

}
void cAmarokPlayer::addGenre(const char* name)
{
    Lock();
    m_commander.addGenre(name);
    Unlock();

}
void cAmarokPlayer::addTitle(const char* name)
{
    Lock();
    m_commander.addTitle(name);
    Unlock();

}

