/***************************************************************************
 *   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 <iostream>
#include <vdr/osdbase.h>
#include <vdr/tools.h>
#include "menuAmarok.h"
#include "menuAmarokSetup.h"
#include "amarok_i18n.h"
#include "amarokPlayer.h"
#include "amarokData.h"


#define AMAROK_SEEK_PLUS 20
#define AMAROK_SEEK_MINUS -20
#define AMAROK_SEEK_FASTPLUS 40
#define AMAROK_SEEK_FASTMINUS -40

using namespace std;

/////////////////////////////////////////////////////////////////////////
////////// cMenuAmBase
/////////////////////////////////////////////////////////////////////////

cMenuAmBase::cMenuAmBase(): cOsdMenu("amaroK"), p_Player(0), b_initAction(false)
{}


cMenuAmBase::~cMenuAmBase()
{}

bool cMenuAmBase::setCurrentOsdItem(int index)
{

    cOsdItem *item=Get(index);
    if (item && index != Current())
    {
        SetCurrent(item);
        Display();
        return true;
    }
    return false;
}

void cMenuAmBase::setOsdItemText(const char* text,int index)
{

    //    if (b_EditMode)
    //        return;

    cOsdItem *item=Get(index);
    if (item)
    {
        item->SetText(text);
        Display();
    }

}

void cMenuAmBase::addOsdItem(const char* text, bool bselect, int after)
{

    cOsdItem *osd_item = 0;
    if (-1==after)
        Add(osd_item = new cOsdItem(text));
    else
    {
        cOsdItem *behind=Get(after);
        Add(osd_item = new cOsdItem(text),true,behind);
    }
    if (!bselect)
        osd_item->SetSelectable(false);
}

eOSState cMenuAmBase::checkSleepKey(eKeys Key)
{
    eOSState ret=osUnknown;

    switch (Key)
    {

    case kUp:

    case kDown:
        //case kLeft|k_Repeat:
    case kLeft:
        //case kRight|k_Repeat:
    case kRight:
        p_Player->setSleep(true);
        ret=osContinue;
        break;
    default:
        break;
    }
    return ret;
}

/////////////////////////////////////////////////////////////////////////
////////// cMenuAmarok
/////////////////////////////////////////////////////////////////////////

cMenuAmarok::cMenuAmarok():b_EditMode(false)
{

    SetTitle(tr("Trying to connect to amaroK..."));
}


cMenuAmarok::~cMenuAmarok()
{

    if (HasSubMenu())
        CloseSubMenu();

    delete p_Player;
    p_Player=0;
}


void cMenuAmarok::initialize()
{
    p_Player=new cAmarokPlayer(this);
    const char* msg=p_Player->initialize();
    if(msg)
    {
        // error case
        SetTitle (msg);
        Display();
    }
    else
        SetButtons();

}

eOSState cMenuAmarok::SetButtons()
{
    if (!b_EditMode)
    {
        SetTitle(tr("amaroK Player"));
        SetHelp(tr("Track"), "<<", ">>", tr("Change"));
    }
    else
    {
        SetTitle(tr("amaroK Playlist Editor"));
        SetHelp(tr("Query"), tr("Shuffle"), tr("Remove"), tr("Clear l."));
    }
    Display();
    return osContinue;
}



eOSState cMenuAmarok::ProcessKey(eKeys Key)
{
#ifdef AMAROK_DEBUG
    debugRemoteKey(Key);
#endif

    if (!p_Player)
        initialize();

    eOSState state = cOsdMenu::ProcessKey(Key);

    checkSleepKey(Key);

    if (state == osUnknown || (b_EditMode && state==osBack))
    {

        state= osContinue;
	cMenuAmBase *menu=0;
	int cur=0;
        switch (Key)
        {
        case kPlay:
            p_Player->playPause();
            break;
        case kOk:
            cur=Current();
            if (b_EditMode)
            {
                p_Player->rebuildPlaylist();
                p_Player->play(cur);
            }
            else
                p_Player->play(cur);
            break;
        case kStop:
            p_Player->stop();
            break;
        case kPrev:
            p_Player->prev();
            break;
        case kNext:
            p_Player->next();
            break;
        case kPause:
            p_Player->pause();
            break;
        case kRed:
            if (b_EditMode && !HasSubMenu())
            {
                menu= new cMenuAmarokQuery(p_Player);
                AddSubMenu(menu);
                menu->initialize();
            }
            else if (!HasSubMenu())
            {
                menu= new cMenuAmarokTrack(p_Player);
                AddSubMenu(menu);
                menu->initialize();
            }
            break;
        case kGreen:
            if (b_EditMode)
                p_Player->shufflePlaylist();
            else
                p_Player->seekRelative(AMAROK_SEEK_MINUS);
            break;
        case kYellow:
            if (b_EditMode)
            {
                cur=Current();
                Del(cur);
                p_Player->removeTrack(cur);
                Display();
            }
            else
                p_Player->seekRelative(AMAROK_SEEK_PLUS);

            break;
        case kBlue:
            if (b_EditMode)
            {
                p_Player->clearPlaylist();
            }
            else
            {
                b_EditMode=true;
                SetButtons();
            }
            break;
        case kFastRew:
            p_Player->seekRelative(AMAROK_SEEK_FASTMINUS);
            break;
        case kFastFwd:
            p_Player->seekRelative(AMAROK_SEEK_FASTPLUS);
            break;
        case kVolUp:
            p_Player->volumeUp();
            break;
        case kVolDn:
            p_Player->volumeDown();
            break;
        case kMute:
            p_Player->mute();
            break;
        case kBack:
            if (b_EditMode)
            {
                b_EditMode=false;
                p_Player->rebuildPlaylist();
                SetButtons();
            }
        default:
            break;
        }
    }

    return state;
}


/////////////////////////////////////////////////////////////////////////
////////// cMenuAmarokTrack
/////////////////////////////////////////////////////////////////////////



cMenuAmarokTrack::cMenuAmarokTrack(cAmarokPlayer *player)
{
    p_Player=player;
    SetTitle (tr("amaroK Current Track View"));
    Display();

}


cMenuAmarokTrack::~cMenuAmarokTrack()
{
    p_Player->detachTrackMenu();
    p_Player=0;

}

void cMenuAmarokTrack::initialize()
{

    SetButtons();
    p_Player->attachTrackMenu(this);
    p_Player->buildTrackview();
}

void cMenuAmarokTrack::showTrackinfo(TrackItem* track)
{
    const char *line   = "----------------------------------------------------------------------------------------";
    //const char *line = "******************************************************************************";
    if (track)
    {
        char str[MAX_ITEM_CHAR_SIZE];
        track->getFormatTimeTrIdx(str,tr("Time"),tr("Track"));
        addOsdItem(str,false);
        track->getShortTextContent(str,-1);
        addOsdItem(str,false);
        addOsdItem(line,false);
        snprintf(str, MAX_ITEM_CHAR_SIZE, "%s: %s", tr("Album"),track->Album);
        addOsdItem(str,false);
        snprintf(str, MAX_ITEM_CHAR_SIZE, "%s: %s  -  %s: %s  -  %s: %s kbit/s",
                 tr("Year"),
                 track->Year,
                 tr("Genre"),
                 track->Genre,
                 tr("Bitrate"),
                 track->Bitrate);
        addOsdItem(str,false);
        addOsdItem("",false);
        snprintf(str, MAX_ITEM_CHAR_SIZE, "%s:", tr("Current track statistics"));
        addOsdItem(str,false);
        addOsdItem(track->Statistics.c_str(),false);
        addOsdItem(line,false);
        snprintf(str, MAX_ITEM_CHAR_SIZE, "%s:", tr("Comment"));
        addOsdItem(str,false);
        snprintf(str, MAX_ITEM_CHAR_SIZE, "%s", track->Comment);
        addOsdItem(str,false);


    }
    else
    {
        addOsdItem(tr("Trackinfos not available"),false);
    }

    Display();

}

eOSState cMenuAmarokTrack::SetButtons()
{
    SetHelp(NULL, "<<", ">>", tr("show OSD"));
    return osContinue;
}

eOSState cMenuAmarokTrack::ProcessKey(eKeys Key)
{
    //eOSState state = cOsdMenu::ProcessKey(Key);
    eOSState state = osUnknown;
    switch (Key)
    {
    default:
    case kOk:
        state=osContinue;
        break;
    case kFastRew:
        p_Player->seekRelative(AMAROK_SEEK_FASTMINUS);
        state=osContinue;
        break;
    case kFastFwd:
        p_Player->seekRelative(AMAROK_SEEK_FASTPLUS);
        state=osContinue;
        break;
    case kBlue:
    	p_Player->showOsd();
    	break;
    case kYellow:
        p_Player->seekRelative(AMAROK_SEEK_PLUS);
        state=osContinue;
        break;
    case kGreen:
        p_Player->seekRelative(AMAROK_SEEK_MINUS);
        state=osContinue;
    case kPlay:
        p_Player->playPause();
        state=osContinue;
        break;
    case kStop:
        p_Player->stop();
        state=osContinue;
        break;
    case kPrev:
    case kUp:
        p_Player->prev();
        state=osContinue;
        break;
    case kNext:
    case kDown:
        p_Player->next();
        state=osContinue;
        break;
    case kVolUp:
        p_Player->volumeUp();
        state=osContinue;
        break;
    case kVolDn:
        p_Player->volumeDown();
        state=osContinue;
        break;
    case kMute:
        p_Player->mute();
        state=osContinue;
        break;
    case kBack:
        p_Player->detachTrackMenu();
        state = osBack;
        break;
    }
    return state;
}

/////////////////////////////////////////////////////////////////////////
////////// cMenuAmarokQuery
/////////////////////////////////////////////////////////////////////////

cMenuAmarokQuery::cMenuAmarokQuery(cAmarokPlayer *player)
{
    p_Player=player;
    SetTitle (tr("amaroK Database Query"));
    Display();

}


cMenuAmarokQuery::~cMenuAmarokQuery()
{
    p_Player=0;

}

void cMenuAmarokQuery::initialize()
{
    b_initAction=true;
    showWaitMessage();

}


eOSState cMenuAmarokQuery::SetButtons()
{
    switch (m_Result.getType())
    {
    case CMD_REQUEST_ARTISTLIST:
        SetHelp(tr("Add"),NULL, tr("Lists"),tr("Genre"));
        break;
    case CMD_REQUEST_ALBUMLIST:
        SetHelp(tr("Add"), tr("Artist"),tr("Lists"), tr("Genre"));
        break;
    case CMD_REQUEST_GENRELIST:
        SetHelp(tr("Add"), tr("Artist"),tr("Lists"), NULL);
        break;
    default:
        //    esyslog ("wrong query list type");
        break;
    }

    return osContinue;
}

eOSState cMenuAmarokQuery::ProcessKey(eKeys Key)
{
    if (b_initAction)
    {
        doArtistQuery();
        b_initAction=false;
    }

    eOSState state = cOsdMenu::ProcessKey(Key);
    cMenuAmBase *menu=0;
    //    if (state == osUnknown)
    //    {
    switch (Key)
    {
    case kOk:
        handleNode();
        state = osContinue;
        break;
    case kRed:
        addToPlaylist();
        state = osContinue;
        break;
    case kGreen:
        doArtistQuery();
        state = osContinue;
        break;
    case kYellow:
        menu= new cMenuAmarokLists(p_Player);
        AddSubMenu(menu);
        menu->initialize();
        state = osContinue;
        break;
    case kBlue:
        doGenreQuery();
        state = osContinue;
        break;
    case kBack:
        p_Player->rebuildPlaylist();
    default:
        break;
    }
    //  }
    return state;
}


void cMenuAmarokQuery::showWaitMessage()
{
    clearMenu();
    SetTitle(tr("Please wait ! Database query has started."));
    //addOsdItem(tr("Please wait ! Database query has started ..."));
    //Display();
    SetButtons();
    Display();

}

void cMenuAmarokQuery::addToPlaylist()
{
    unsigned int index= Current();
    cOsdItem *osd=Get(index);
    const char *osdtext=osd->Text();
    const char *listtext=m_Result.getTextItemByOsdIndex(index);

    if (osdtext[0]=='+' || osdtext[0]=='-')
    {
        addNodeEntry(listtext);
    }
    else
    {
        addSubEntry(listtext);
    }

}

void cMenuAmarokQuery::addNodeEntry(const char* addStr)
{
    switch (m_Result.getType())
    {
    case CMD_REQUEST_ARTISTLIST:
        p_Player->addArtist(addStr);
        break;
    case CMD_REQUEST_GENRELIST:
        p_Player->addGenre(addStr);
        break;
    case CMD_REQUEST_ALBUMLIST:
        p_Player->addAlbum(addStr);
        break;
    default:
        esyslog ("wrong query list type");

    }
}

void cMenuAmarokQuery::addSubEntry(const char* addStr)
{
    switch (m_Result.getType())
    {
    case CMD_REQUEST_ARTISTLIST:
        p_Player->addAlbum(addStr);
        break;
    case CMD_REQUEST_GENRELIST:
        p_Player->addArtist(addStr);
        break;
    case CMD_REQUEST_ALBUMLIST:
        p_Player->addArtist(addStr);
    default:
        esyslog ("wrong query list type");

    }

}


void cMenuAmarokQuery::handleNode()
{
    const unsigned int index= Current();
    unsigned int addIndex = index;
    cOsdItem *osd=Get(index);
    const char *text=osd->Text();
    if (text[0]=='+' ) // has sub node
    {
        //osd node != result node when nodes are open !!!!
        unsigned int node=m_Result.getNodeIndex(index);
        if (AmarokQueryResultItem* item=m_Result.getItem(node))
        {

            if (!item->getShow())
            {
                item->setShow();
                for (unsigned int sub=0; sub < item->getSubItemSize(); sub++)
                {
                    char tmp[MAX_ITEM_CHAR_SIZE];
                    m_Result.getSubItemFormated(tmp,node,sub);
                    addOsdItem(tmp,true,addIndex++);
                }

            }
            else
            {
                addIndex++; // move to first sub item
                item->setShow(false);
                for (unsigned int sub=0; sub < item->getSubItemSize(); sub++)
                    Del(addIndex);

            }
        } // if item
    } // has sub node
    else
        dsyslog ("handleNode do nothing: %s", text);

    setCurrentOsdItem(index);
    Display();
}

void cMenuAmarokQuery::displayResult(bool remember)
{
#ifdef AMAROK_DEBUG
    m_Result.debugList();
#endif

    int current=0;
    if (remember)
    {
        current=Current();
    }

    clearMenu();
    SetTitle (tr("amaroK Database Query"));
    if (!m_Result.getListSize())
    {
        addOsdItem(tr("Empty list"),false);
    }
    else
    {
        for (unsigned int index =0; index< m_Result.getListSize();index++)
        {
            unsigned int subcount=0;
            char tmp[MAX_ITEM_CHAR_SIZE];

            if (m_Result.getItemFormated(tmp,index,subcount))
            {
                addOsdItem(tmp);
                for (unsigned int sub=0; sub< subcount; sub++)
                {
                    char tmp2[MAX_ITEM_CHAR_SIZE];
                    m_Result.getSubItemFormated(tmp2,index,sub);
                    addOsdItem(tmp2);
                }
            }
            else
                addOsdItem(tmp);
        }

        if (remember)
            setCurrentOsdItem(current);
    }


    Display();

}

void cMenuAmarokQuery::doArtistQuery()
{
    m_Result.setType( CMD_REQUEST_ARTISTLIST);
    showWaitMessage();
    p_Player->queryLists(m_Result);
    displayResult();

}

void cMenuAmarokQuery::doAlbumQuery()
{
    m_Result.setType( CMD_REQUEST_ALBUMLIST);
    showWaitMessage();
    p_Player->queryLists(m_Result);
    displayResult();

}

void cMenuAmarokQuery::doGenreQuery()
{
    m_Result.setType( CMD_REQUEST_GENRELIST);
    showWaitMessage();
    p_Player->queryLists(m_Result);
    displayResult();

}

void cMenuAmarokQuery::doTitleQuery()
{}


/////////////////////////////////////////////////////////////////////////
////////// cMenuAmarokLists
/////////////////////////////////////////////////////////////////////////


// unfortunately these playlists are not managed by the amarok DB in v1.4 or older
char *AMAROK_STATIC_PLAYLISTS []=
    {
        "50 Random Tracks",
        "All Collection",
        "Ever Played",
        "Favorite Tracks",
        "Last Played",
        "Most Played",
        "Never Played",
        "Newest Tracks"
    };

cMenuAmarokLists::cMenuAmarokLists(cAmarokPlayer *player)
{
    p_Player=player;
    SetTitle (tr("amaroK's smart playlists"));
    Display();
}

cMenuAmarokLists::~cMenuAmarokLists()
{
    p_Player=0;
}
void cMenuAmarokLists::initialize()
{

    for(unsigned int i = 0; i < sizeof(AMAROK_STATIC_PLAYLISTS) / sizeof(char*); i++)
    {
        addOsdItem(tr(AMAROK_STATIC_PLAYLISTS[i]));
    }
    SetButtons();
    Display();
}

eOSState cMenuAmarokLists::SetButtons()
{
    SetHelp(NULL, NULL, NULL, NULL);
    return osContinue;
}
eOSState cMenuAmarokLists::ProcessKey(eKeys Key)
{
    eOSState state = cOsdMenu::ProcessKey(Key);
    if (osUnknown == state)
    {
        switch (Key)
        {
        case kOk:
            loadSelectedList();
            break;
        case kStop:
            p_Player->stop();
            break;
        case kYellow:
            p_Player->seekRelative(AMAROK_SEEK_PLUS);
            break;
        case kFastFwd:
            p_Player->seekRelative(AMAROK_SEEK_FASTPLUS);
            break;
        case kGreen:
            p_Player->seekRelative(AMAROK_SEEK_MINUS);
            break;
        case kFastRew:
            p_Player->seekRelative(AMAROK_SEEK_FASTMINUS);
            break;
        case kRed:
            break;
        case kBlue:
            break;
        default:
            break;
        }
    }
    return state;
}
void cMenuAmarokLists::loadSelectedList()
{

    p_Player->loadPlaylist(Get(Current())->Text());

}

#ifdef AMAROK_DEBUG
void cMenuAmBase::debugRemoteKey(eKeys key)
{

    switch (key)
    {
    case kUp:
        cout << "kup" << endl;
        break;

    case kDown:
        cout << "kDown" << endl;
        break;

    case kMenu:
        cout << "kMenu" << endl;
        break;

    case kOk:
        cout << "kOk" << endl;
        break;

    case kBack:
        cout << "kBack" << endl;
        break;

    case kLeft:
        cout << "kLeft" << endl;
        break;

    case kRight:
        cout << "kRight" << endl;
        break;

    case kRed:
        cout << "kRed" << endl;
        break;

    case kGreen:
        cout << "kGreen" << endl;
        break;

    case kYellow:
        cout << "kYellow" << endl;
        break;

    case kBlue:
        cout << "kBlue" << endl;
        break;

    case k0:
        cout << "k0" << endl;
        break;
    case k1:
        cout << "k1" << endl;
        break;
    case k2:
        cout << "k2" << endl;
        break;
    case k3:
        cout << "k3" << endl;
        break;
    case k4:
        cout << "k4" << endl;
        break;
    case k5:
        cout << "k5" << endl;
        break;
    case k6:
        cout << "k6" << endl;
        break;
    case k7:
        cout << "k7" << endl;
        break;
    case k8:
        cout << "k8" << endl;
        break;
    case k9:
        cout << "k9" << endl;
        break;
    case kInfo:
        cout << "kInfo" << endl;
        break;

    case kPlay:
        cout << "kPlay" << endl;
        break;

    case kPause:
        cout << "kPause" << endl;
        break;

    case kStop:
        cout << "kStop" << endl;
        break;

    case kRecord:
        cout << "kRecord" << endl;
        break;

    case kFastFwd:
        cout << "kFastFwd" << endl;
        break;

    case kFastRew:
        cout << "kFastRew" << endl;
        break;

    case kNext:
        cout << "kNext" << endl;
        break;

    case kPrev:
        cout << "kPrev" << endl;
        break;

    case kPower:
        cout << "kPower" << endl;
        break;

    case kChanUp:
        cout << "kChanUp" << endl;
        break;

    case kChanDn:
        cout << "kChanDown" << endl;
        break;

    case kChanPrev:
        cout << "kChanPrev" << endl;
        break;

    case kVolUp:
        cout << "kVolup" << endl;
        break;

    case kVolDn:
        cout << "kVolDown" << endl;
        break;

    case kMute:
        cout << "kMute" << endl;
        break;

    case kAudio:
        cout << "kAudio" << endl;
        break;

    case kSchedule:
        cout << "kSchedule" << endl;
        break;

    case kChannels:
        cout << "kChannels" << endl;
        break;

    case kTimers:
        cout << "kTimers" << endl;
        break;

    case kRecordings:
        cout << "kRecordings" << endl;
        break;

    case kSetup:
        cout << "kSetup" << endl;
        break;

    case kCommands:
        cout << "kCommands" << endl;
        break;

    case kUser1:
        cout << "kUser1" << endl;
        break;
    case kUser2:
        cout << "kUser2" << endl;
        break;
    case kUser3:
        cout << "kUser3" << endl;
        break;
    case kUser4:
        cout << "kUser4" << endl;
        break;
    case kUser5:
        cout << "kUser5" << endl;
        break;
    case kUser6:
        cout << "kUser6" << endl;
        break;
    case kUser7:
        cout << "kUser7" << endl;
        break;
    case kUser8:
        cout << "kUser8" << endl;
        break;
    case kUser9:
        cout << "kUser9" << endl;
        break;

    case kKbd:
        cout << "kKbd" << endl;
        break;
    default:
        cout << "k Unknownkode:"<< key << endl;
        break;

    }
}
#endif
