/***************************************************************************
 *   Copyright (C) 2005 by Reel Multimedia                                 *
 *                                                                         *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

// Player.c
#include <memory>
#include <linux/types.h>
#include <linux/dvb/video.h>  // video_still_picture

#include <vdr/status.h>
#include <vdr/remote.h>
#include <vdr/plugin.h>
#include <vdr/debugmacros.h>
#include <vdr/resumeDvd.h>

#include "Player.h"
#include "Control.h"
#include "XineEvent.h"
#include "xineOsd.h"
#include "Utils.h"

#include "tree.hh"

//#define DEBUG_PLAYER(format, args...) printf (format, ## args)
#define DEBUG_PLAYER(format, args...)

//#define DEBUG_XINE_EVENT(format, args...) printf (format, ## args)
#define DEBUG_XINE_EVENT(format, args...)

//#define DEBUG_AUDIO_ID(format, args...) printf (format, ## args)
#define DEBUG_AUDIO_ID(format, args...)

using std::string;


// TODO  Xine Setup
//static int XineSetup_Display = 0;
                        //0;  short
                      //1; // medium
                      //2; // long

namespace Reel
{
namespace XineMediaplayer
{

   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Tools
   inline std::string GetFileName(const std::string &path)
   {
       return path.substr(path.find_last_of("/") + 1, path.size());
   }

   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   // Player

   const int Player::MaxAudioTracks    = 0x20;
   const int Player::AudioTrackMask    = 0x1F;
   const int Player::AC3AudioTrackMask = 0x07;
   const int Player::MaxSubpStreams    = 0x20;
   const int Player::SubpStreamMask    = 0x1F;


    Player::Player(const char *mrl, bool playlist, std::vector<std::string> playlistEntries) NO_THROW :
        cPlayer(useOld?pmAudioVideo:pmExtern_THIS_SHOULD_BE_AVOIDED),
        xineLib_(XineLib::Instance()),
        playing_(false),
        mrlIsInPlaylist_(playlist),
        playlist_(playlist && !playlistEntries.empty()),
        playlistEntries_(playlistEntries),
        loopmode_(false),
        isInMenuDomain_(useOld?true:false),
        mrl_(mrl),
        titleInfo_(""),
        writeWait(60000),
        number(0)
    {
        srand((unsigned)time(0)); 
      
        HERE;
       DEBUG_PLAYER ("DEBUG [xinemedia]:  Player::Player  --- mrl  %s \n", mrl);

        CreateItemTree();
	InitPlayListPos();

        play_mode = PLAY_NORMAL;

       // depends of mrl
       SetInitLangCode();
       xineLib_.SetParamAudioReportLevel(5);
    }

    Player::~Player() NO_THROW
    {
        DEBUG_PLAYER ("DEBUG [xinemedia]:  Player::~Player  \n");

        cXineOsd::isPlaying = false;

        xineLib_.Exit();
        Detach();
    }

    void Player::InitPlayListPos()
    {
	    unsigned int i = 0;
	    std::string myMrl = mrl_; 
	    size_t found;
	    // remove 'file://'
	    if ((found=myMrl.find("file://")) != std::string::npos)
		    myMrl.erase(found,found+7);

	    for (; i < playlistEntries_.size() ; ++i)
	    {
	    	//printf("(%s:%d) \t%d...(%s\t%s)\n", __FILE__, __LINE__, i, myMrl.c_str(), playlistEntries_[i].c_str() );
		    if( playlistEntries_[i] == myMrl)
		    {
                            LOC;printf("mrl(%s)==(%s)playlistentry(%i)\n",myMrl.c_str(), playlistEntries_.at(i).c_str(), i);
			    pl_pos = i;
			    return;
		    }
	    }
	// mrl_ not in playlistEntries
            LOC; printf("\n\nmrl not found in playlist.\n\n");
	/***
	 * Play the new playlist if possible
	 ***/
	if ( !playlistEntries_.empty() )
	{
		pl_pos = 0;
                // get mrl from the tree
                vItemTree[pl_pos].Rewind();
                mrl_ = GetNextFromTree( pl_pos );

                // nothing in the current tree; go to next tree
                if ( mrl_.empty() ) 
                  mrl_ = GetNextPlayListEntryCyclic(true);
                
		//mrl_ = playlistEntries_[pl_pos];
		ReStartPlayback();
	}
        else 
        {
          LOC; printf("playlist is empty. Stopping xinemediaplayer.\n");
          StopPlayback(); 
        }
    }

    bool Player::PlayFileNumber( unsigned int num )
    {
    		// outside bounds of playlist
     		if ( num < 0 || num >= playlistEntries_.size() )  return false;

		pl_pos = num ;
                //  get mrl from the tree
                vItemTree[num].Rewind();
                mrl_ = GetNextPlayListEntryCyclic(true); 
		//mrl_ = playlistEntries_[ num ];
		ReStartPlayback();

		return true;
    }

    void Player::SetPlayMode(int mode)
    {
      play_mode = mode;

      if ( play_mode == PLAY_REPEAT_PLAYLIST ) 
          loopmode_ = true;
      else
          loopmode_ = false;
    }
    
    int Player::GetPlayMode()
    {
      return play_mode;
    }
    void Player::CreateItemTree()
    {
        HERE;
        cItemTree iTree; // tmp tree
        unsigned int i;
        vItemTree.clear();

        // iterate thro' playlist
        for (i=0; i<playlistEntries_.size();++i)
        {
            
            vItemTree.push_back(iTree);
            vItemTree[i].set_head( playlistEntries_[i] );
            
        }
    }
    void Player::ReplacePlayList(std::vector<std::string> pl)
    {
        HERE;
     playlistEntries_ = pl;
     //XXX set item_trees
     CreateItemTree();

     //update parameters with new playlist's
     playlist_ = mrlIsInPlaylist_ && !playlistEntries_.empty();

     InitPlayListPos(); // compute the new mrl position in the playlist
 
    }

    void Player::Activate(bool on) NO_THROW
    {
        HERE;
        try
        {
            if (on && !playing_)
            {
                //TODO remove this 
                vItemTree[pl_pos].Rewind();
                mrl_ = GetNextFromTree( pl_pos );

                // nothing in the current tree; go to next tree
                if ( mrl_.empty() ) 
                    mrl_ = GetNextPlayListEntryCyclic(true);

                StartPlayback();
            }
            else if (!on && playing_)
            {
                StopPlayback(); // This cannot fail.
            }
        }
        catch (XineError const &ex)
        {
            LogXineError(ex);
            Detach();
        }
    }

    void Player::ShowSplashScreen()
    {
       DEBUG_PLAYER ("DEBUG [xinemedia]:  Player::ShowSplashScreen() \n");
       string stillPicture = cPlugin::ConfigDirectory();
       // depends of mrl
       stillPicture += "/xinemediaplayer/splash.mpg";

       uchar *buffer;
       int fd;
       struct stat st;
       struct video_still_picture sp;

       if ((fd = open (stillPicture.c_str(), O_RDONLY)) >= 0)
       {
          fstat (fd, &st);
          sp.iFrame = new char[st.st_size];
          if (sp.iFrame)
          {
            sp.size = st.st_size;
            if (read (fd, sp.iFrame, sp.size) > 0)
            {
               buffer = (uchar *) sp.iFrame;
               cDevice::PrimaryDevice()->StillPicture(buffer, sp.size);
            }
            delete [] sp.iFrame;
          }
          close (fd);
        }
     }

#define NUMBERTIMEOUT 1500 

    eOSState Player::Number(eKeys Key)
    {
       printf("number: %i\n", number);
       if (numberTimer.TimedOut())
         number = 0;
       number = number * 10 + Key - k0;
       if(number) {
         PlayFileNumber(number-1);
         numberTimer.Set(NUMBERTIMEOUT);
       }
       return osContinue;
    }

    void Player::SetInitLangCode()
    {
       // maybe better to set this with
       strncpy(selectedLangCode_,xineLib_.GetSetupLang(),sizeof(selectedLangCode_));
       DEBUG_AUDIO_ID  ("DEBUG [xinemedia]: SetInitLangCode ----------------- SetInitLangCode set selectedLangCode_ to %s \n", selectedLangCode_);
    }

    eOSState Player::ProcessKey(eKeys key) THROWS
    {
    if(!IsReplayingDvd())
        switch(key)
        {
            case k0...k9: // selecting an entry by numbers
                return Number(key);
            case kDown:  // Next Entry
                if(playlist_)
                {
                    PlayNextPlayListEntry(true);
                }
                else if(mrlIsInPlaylist_)
                {
                    Detach();
                }
                break;
            //case kDown:  // Prev Entry
            case kUp:  // Prev Entry
                if (playlist_)
                {
                    PlayNextPlayListEntry(false);
                }
                break;
            default:
                break;
        }

	// if playing a DVD and not in DVD menu, write the title and chapter info into "resume DB"
	// 	So, that next time the dvd is inserted mediad gives xinemediaplayer a url 
	//	with title.chapter in it to resume playing
	if (IsReplayingDvd() && !PlayerIsInMenuDomain() && writeWait.TimedOut())
	{
		// write resume info for current DVD
		printf("Title.Chapter := %i.%i\n", DvdTitleNumber(), DvdChapterNumber());
		writeWait.Set(60000);
		ResumeDvd.SetTitleChapter(*cString::sprintf("%i.%i",DvdTitleNumber(), DvdChapterNumber()));
	}

        if(PlayerIsInMenuDomain() && IsReplayingDvd())
        {
            xineLib_.ProcessKeyMenuMode(key);
        }
        else
        { 
            xineLib_.ProcessKey(key,IsReplayingMusic());
        }
	return osContinue;
    }

    // fetch audio track infos from xine_lib
    void Player::SetAllAudioTracks()
    {
        unsigned int old_count = aviableAudioTracks_.size(); 
        aviableAudioTracks_.clear();
        SetMenuDomain(false);

        if (GetAudioLangCode().find("menu") == 0)
        {
            SetMenuDomain(true); // looks strang but works
            SetAllSpuTracks();
            DeviceClrAvailableTracks();
            SetAvailableTracks();
            DEBUG_AUDIO_ID( "\t \033[0;44m  GetAudioLangCode \"menu\"  return \033[0m \n");
            return;
        }

        // TODO  workaround for autodetect
        int currentAudioTrack = -2;
        tTrackId aTrack;
        currentAudioTrack = xineLib_.GetParamAudioChannelLogical();
        // -1:  auto detect
        snprintf(aTrack.language, sizeof(aTrack.language), "auto");
        memset (aTrack.description,0,sizeof(aTrack.description));
        aviableAudioTracks_.push_back(aTrack);
        DEBUG_AUDIO_ID( "\t \033[0;44m  current Audio track Nr %d  \033[0m \n", currentAudioTrack);

        //int dolbyTracks = 0;
        for (int i= 0;i< MaxAudioTracks;i++)
        {
             // tTrackId = {
             //  uint_16 id; // The PES packet id or the PID id;
             //  char language[8];
             //  char description[32];
             // };
             char langCode[XINE_LANG_MAX];
             if (!xineLib_.GetAudioLangCode(langCode,i))
                break;

             strn0cpy(aTrack.language,langCode, sizeof(aTrack.language));
             memset (aTrack.description,0,sizeof(aTrack.description));

             DEBUG_AUDIO_ID( "\033[0;44m  audio trackNr.  %2d.) lang: %s   \033[0m \n", i, aTrack.language);

             aviableAudioTracks_.push_back(aTrack);
        }
	if(old_count != aviableAudioTracks_.size())
            DeviceClrAvailableTracks();
        SetAvailableTracks();
    }

    //  track infos  to vdr
    void Player::SetAvailableTracks()
    {
       //DEBUG_AUDIO_ID(" \033[0;45m  %s  found %d  audio tracks \033[0m\n",__PRETTY_FUNCTION__, aviableAudioTracks_.size());
       for (unsigned int i = 0;i< aviableAudioTracks_.size(); i++)
       {
           eTrackType ttype = ttDolby; // + i;
           aviableAudioTracks_[i].id = 0x80 + i;

           //DEBUG_AUDIO_ID(" \033[0;45m register track  %d  lang: \"%s\" to vdr  \033[0m\n", i,  aviableAudioTracks_[i].language);
           DeviceSetAvailableTrack(ttype, i, aviableAudioTracks_[i].id, aviableAudioTracks_[i].language, aviableAudioTracks_[i].description);
       }
    }


     // called by vdr/menu.c   set chosen  audio track to xine Lib
     void Player::SetAudioTrack(eTrackType Type, const tTrackId *TrackId)
     {
         int currentAudioTrack = xineLib_.GetParamAudioChannelLogical();

         DEBUG_AUDIO_ID(" \033[0;48m %s  -- ttype %d TrackID %2X  current trackNum %d  !\033[0m\n", __PRETTY_FUNCTION__, Type, TrackId->id, currentAudioTrack);
         //if (!TrackId) return;

         unsigned int idx = TrackId->id - 0x80;
         if (idx < 0 || idx >= aviableAudioTracks_.size())
         {
            DEBUG_AUDIO_ID(" \033[0;48m %s  ERRRROOR Have no Track Nr %d  \033[0m\n", __PRETTY_FUNCTION__, idx );
            return;
         }

         idx--; // -1 = auto
         if (currentAudioTrack   != (int) idx)
         {
             if (currentAudioTrack >= 0)
                DEBUG_AUDIO_ID(" \033[0;48 cXineMP::SetAudioTrack: change Track- id %d - l: %s  to track id %d lang  %s ! \033[0m \n",
                     currentAudioTrack , aviableAudioTracks_[currentAudioTrack].language, idx,  aviableAudioTracks_[idx].language);
             else
                 DEBUG_AUDIO_ID("\033[0;48m cXineMp::SetAudioTrack: change Track- id AUTO - l: ?? to track id %d lang  %s !\033[0m \n",
                     idx,  aviableAudioTracks_[idx].language);

             xineLib_.SetAudioTrack(idx);
         }
         else
           DEBUG_AUDIO_ID(" Same TrackId  -- no need to change \n");
     }

    void Player::SetAllSpuTracks()
    {
        for (int i = 0;i< 32;i++)
        {
           char lang[XINE_LANG_MAX];
           if (xineLib_.GetSpuLangCode(lang,i) == 0)
             break;

           DEBUG_AUDIO_ID ( "\t \033[0;41m spu track %2d.)  lang \"%s\" --- \033[0m \n",i,  lang);
        }
    }

    void Player::HandleEvents() THROWS
    {
        for (;;)
        {
            //SetAvailableTracks(); No need to allways set tracks

            std::auto_ptr<XineEventBase> event(xineLib_.GetEvent()) ;
            if (event.get() == nullptr) break;

            if(event.get())
            {
                switch(event->type_)
                {
                    case XINE_EVENT_UI_NUM_BUTTONS:
                    {
                        DEBUG_XINE_EVENT ( "\033[0;36m  --- XINE_EVENT_UI_NUM_BUTTONS  ---- menu buttons: %d  ---- \033[0m \n", static_cast<EventUINumButtons *>(event.get())->data_.num_buttons);
                        break;

                    }
                    case XINE_EVENT_UI_PLAYBACK_FINISHED:
                    {
                        // int current, total; unused vars
                        DEBUG_XINE_EVENT ( "\033[0;36m  --- %s : REEL_XINE_EVENT_UI_PLAYBACK_FINISHED \033[0m \n",__PRETTY_FUNCTION__ );
                        SetTitleInfoString();
                        SetAllAudioTracks();
                        DEBUG_XINE_EVENT("--------------xineLib_.GetStream() = %u, event->stream_ = %u------\n",
                                     (uint)(xineLib_.GetStream()), (uint)(event->stream_));

                        if (xineLib_.GetStream() == event->stream_)
                        {
                            if (playlist_)
                            {
                                PlayNextPlayListEntry(true);
                            }
                        }
                        break;
                    }
                    case XINE_EVENT_UI_SET_TITLE:
                         {
                         DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_UI_SET_TITLE  \033[0m \n",__PRETTY_FUNCTION__ );
                         // DVD Titles spoils Title
                         SetTitleInfoString();
                         DEBUG_XINE_EVENT ( "\033[0;36m    TITLE %s \033[0m\n", static_cast<EventUISetTitle *>(event.get())->data_.str );
                         }
                        break;
                    case XINE_EVENT_UI_CHANNELS_CHANGED:
                         DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_UI_CHANNELS_CHANGED  \033[0m \n",__PRETTY_FUNCTION__ );
                         SetAllAudioTracks();
                         SetTitleInfoString();
                    DEBUG_XINE_EVENT ( "\033[0;36m   break \033[0m\n");
                         break;
                    case XINE_EVENT_UI_MESSAGE:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_UI_MESSAGE  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_FRAME_FORMAT_CHANGE :
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_FRAME_FORMAT_CHANGE  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_AUDIO_LEVEL:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_AUDIO_LEVEL  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_QUIT:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_QUIT  \033[0m \n",__PRETTY_FUNCTION__ );
                         // ProcessKey(kMenu); clean up start FileManager
                         break;
                    case XINE_EVENT_PROGRESS:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_PROGRESS  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_MRL_REFERENCE:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_MRL_REFERENCE  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_SPU_BUTTON:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_SPU_BUTTON  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_DROPPED_FRAMES:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_DROPPED_FRAMES   \033[0m \n",__PRETTY_FUNCTION__ );
                         break;
                    case XINE_EVENT_MRL_REFERENCE_EXT:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT_MRL_REFERENCE_EXT  \033[0m \n",__PRETTY_FUNCTION__ );
                         break;

                    default:
                        DEBUG_XINE_EVENT ( "\033[0;36m --- %s : XINE_EVENT not handled  \033[0m \n",__PRETTY_FUNCTION__ );
                        break;
                }
            }
        }
   }

   int Player::CurrentPlayNr() // Position in the playlist counted from 1...playlistEntries_.size()
				// 0 for error

	{
	return pl_pos;
	}
 /*  {
        uint pos=-1;
        for (pos = 0; pos < playlistEntries_.size(); pos++)
        {
            if(mrl_.find(playlistEntries_[pos]) != std::string::npos)
                break;
        }
	return pos;
   }
   */

  /*  std::string Player::GetNextPlayListEntryCyclic(bool up)
    {
        std::string currentEntry = mrl_;
        bool found = false;
        uint pos;
        for (pos = 0; pos < playlistEntries_.size(); pos++)
        {
            if(mrl_.find(playlistEntries_[pos]) != std::string::npos)
            {
                found = true;
                break;
            }
        }
        if(!found)
        {
            return "";
        }
        if(!up)
        {
            if(pos == 0)
            {
                return playlistEntries_[playlistEntries_.size()-1];
            }
            else
            {
                return playlistEntries_[--pos];
            }
        }
        else
        {
            if(pos == playlistEntries_.size() - 1)
            {
                return playlistEntries_[0];
            }
            else
            {
                return playlistEntries_[++pos];
            }
        }
    }
    */

   std::string Player::GetNextPlayListEntryCyclic(bool up)
   {
//        HERE;
       unsigned int next = pl_pos;
       DEBUG_VAR(pl_pos);
        // OSD Closed 
        // jump in the OSD playlist : the original playlist
        if (!mrlOpenError_ && !cXineOsd::isOpen)
        {
           next = up? next + 1 : next - 1;

           if ( next < 0 ) // play from last
               next = playlistEntries_.size() -1 ; // got to last file
           else if ( next > playlistEntries_.size() -1 )
               next = 0 ; // got to first file
       pl_pos = next;
        }

       std::string next_mrl = up? GetNextFromTree( next ): GetPrevFromTree( next );
       
       if (next_mrl.size() > 0) return next_mrl;
       else {
         LOC; printf("nothing found in tree#%i, trying the next tree\n\n", next);
       }

       do
       {

           next = up? next + 1 : next - 1;

           if ( next < 0 ) // play from last
               next = playlistEntries_.size() -1 ; // got to last file
           else if ( next > playlistEntries_.size() -1 )
               next = 0 ; // got to first file

           if ((int)next == pl_pos) // back again after looping through the playlist
           {
               esyslog("xinemediaplayer: (%s:%d) looped through the playlist, couldnot find a suitable file/url to play", __FILE__,__LINE__);
               return "";
           }

           next_mrl = up? GetNextFromTree( next ): GetPrevFromTree( next );

        } while ( next_mrl.size()<= 0 );

       pl_pos = next;
       return next_mrl;
   }

    void Player::PlayNextPlayListEntry(bool up)
    {
        //printf("-------PlayNextPlayListEntry, %s ----\n", mrl_.c_str());
        bool detach = false;
        std::string nextMrl = mrl_;

        switch( play_mode )
        {
            case PLAY_RANDOM:
            {
                unsigned int next_num = RandomNumberLessThan( playlistEntries_.size(), pl_pos);
                printf("RANDOM: playing %u/%u\n\n", next_num, playlistEntries_.size() );
                PlayFileNumber(next_num );
                return;
                }
            case PLAY_REPEAT_SINGLE:

                // TODO check if mrl was playable 
                // play same mrl
                if (mrlOpenError_)
                {
                // get next mrl
                }
                ReStartPlayback();
                break;

            default:
                esyslog("(%s:%d) Invalid playlist. Playing in normal mode\n", __FILE__, __LINE__);
            case PLAY_REPEAT_PLAYLIST:
                // fall through play normal
            case PLAY_NORMAL:

                if(up)
                {
                    //if(!loopmode_ && mrl_ == playlistEntries_[playlistEntries_.size() - 1])
                    if(!loopmode_ && pl_pos == (int)playlistEntries_.size()-1 )
                    {
                        detach = true;
                    }
                    nextMrl = GetNextPlayListEntryCyclic(true);
                }
                else
                {
                    //if(!loopmode_ && mrl_ == playlistEntries_[0])
                    if(!loopmode_ && pl_pos ==  0 )
                    {
                        detach = true;
                    }
                    nextMrl = GetNextPlayListEntryCyclic(false);
                }
        } // switch ( play_mode )

        if(detach)
        {
            Detach();
        }
        else
        {
            mrl_ =  nextMrl;
            ReStartPlayback();
        }

        
    }

   void Player::StartPlayback() THROWS
   {
        HERE;
        DEBUG_PLAYER(" Player::StartPlayback()\n");
        //ShowSplashScreen();  //now done by mediad

        xineLib_.Init();
        //xineLib_.PrintXineConfig();
        //xineLib_.PrintXinePlugins();
       DEBUG_VAR(mrl_) ;
       mrlOpenError_ = false;
        try
        {
          xineLib_.Open(mrl_.c_str()); //THROWS
          if(xineLib_.HasVideo() && !xineLib_.VideoHandled()) {
            cXineOsd::openError = tr("VideoCodec not supported!");
            if(xineLib_.VideoCodec()) {
              cXineOsd::openError += " ( ";
              cXineOsd::openError += xineLib_.VideoCodec();
              cXineOsd::openError += " )";
            } // if
            if(!xineLib_.HasAudio() || !xineLib_.AudioHandled()) {
              mrlOpenError_ = true;
              PlayNextPlayListEntry(true);
	      return;
            } // if
          } else {
            cXineOsd::openError = "";
          }
          // debug
          if(useOld)
            DeviceFlush();

          xineLib_.Play(0, 0); //THROWS
          playing_ = true;
        }
        
        catch (XineError const &ex)
        {
          LogXineError(ex);
          mrlOpenError_ = true;
          cXineOsd::openError = tr("Could not play file");
          //Skins.Message(mtError, tr("Could not play file"));
          /// log and silently play the next ;)
          PlayNextPlayListEntry(true);
        }
   }

    void Player::ReStartPlayback() THROWS
    {
        DEBUG_PLAYER("DEBUG [xinemedia]:  Player::ReStartPlayback(): %s\n", mrl_.c_str());

       printf("\033[0;91m DEBUG [xinemedia]:  Player::ReStartPlayback() pl_pos:%i %s\033[0m\n",pl_pos, mrl_.c_str());
       mrlOpenError_ = false;
        try
        {
            DEBUG_VAR(mrl_) ;
          xineLib_.Open(mrl_.c_str()); //THROWS
          if(xineLib_.HasVideo() && !xineLib_.VideoHandled()) {
            cXineOsd::openError = tr("VideoCodec not supported!");
            if(xineLib_.VideoCodec()) {
              cXineOsd::openError += " ( ";
              cXineOsd::openError += xineLib_.VideoCodec();
              cXineOsd::openError += " )";
            } // if
            if(!xineLib_.HasAudio() || !xineLib_.AudioHandled()) {
              mrlOpenError_ = true;
              PlayNextPlayListEntry(true);
	      return;
            } // if
          } else {
            cXineOsd::openError = "";
          }
          if(useOld) {
            sleep(1); //dirty! may skip short videos without sleep...
            vxi->SetPlayMode(0);
          } // if
          xineLib_.Play(0, 0); //THROWS

          if(useOld)
            vxi->SetPlayMode(1);
          playing_ = true;

          // display new file name/title 
          SetTitleInfoString();
          std::string titleStr = GetTitleInfoString();

          if ( !cXineOsd::isOpen )
          {
            if (titleStr.size()>40) titleStr = titleStr.substr(40);
            Skins.Message(mtInfo, titleStr.c_str());
            printf("(%s:%d) displayed %s\n", __FILE__, __LINE__, titleStr.c_str());
          }
          else
          {
              // reusing titleStr
              if (cXineOsd::k_blue == SHOUTCAST_PLUGIN )
              {
                  titleStr = tr("Opening ") + mrl_;
                  Skins.Message(mtInfo, titleStr.c_str() );
              }
          }

        } // try

        catch (XineError const &ex)
        {
          LogXineError(ex);
          mrlOpenError_ = true;
          cXineOsd::openError = tr("Could not play file");
          //Skins.Message(mtError, tr("Could not play file"));
          PlayNextPlayListEntry(true);
        }
    }

   void Player::StopPlayback() NO_THROW
   {
        HERE;
        DEBUG_PLAYER("DEBUG [xinemedia]: Player::StopPlayback()\n");

        if(playlist_ && cXineOsd::k_blue == FILEBROWSER_PLUGIN)
        {
            CallFilebrowser(xine_exit);
        /*
            struct
            {
                char const *entry;
            }fileBrowserSetPlayListEntry  =
            {
                mrl_.c_str()
            };
            printf ("----restart filebrowser %s---\n", mrl_.c_str());
            cPluginManager::CallAllServices("Filebrowser set playlist entry", &fileBrowserSetPlayListEntry);
            */
        }
        else if ( cXineOsd::k_blue == SHOUTCAST_PLUGIN)
            cRemote::CallPlugin("shoutcast");
        else if ( cXineOsd::k_blue == MMFILES_PLUGIN)
            cRemote::CallPlugin("mmfiles");

//Only call Exit with destructor        xineLib_.Exit();
        xineLib_.Close();
        playing_ = false;
   }

   bool Player::IsReplayingMusic()
   {
       if (!Playing())
       {
           return false;
       }

       bool isMusic = false;
       if ( ( std::string(InputPlugin()) == "cdda" || std::string(InputPlugin()) == "file" || std::string(InputPlugin())== "http") && HasAudio())
       {
           isMusic = true;
       }
       if (HasVideo())
       {
           isMusic = false;
       }
       return isMusic;
   }

   bool Player::IsReplayingDvd()
   {
       if (!Playing())
       {
           return false;
       }

       bool isDvd = false;
       if (std::string(InputPlugin()) == "DVD")
       {
           isDvd = true;
       }
       return isDvd;
   }

   bool Player::IsReplayingVideo()
   {
       if (!Playing())
       {
           return false;
       }

       bool isVideo = false;
       if (HasVideo() && !IsReplayingDvd())
       {
           isVideo = true;
       }
       return isVideo;
   }

   void Player::SetTitleInfoString()
   {
       DEBUG_PLAYER("DEBUG [xinemedia]: Player::SetTitleInfoString()\n");

       titleInfo_.clear();
       char titleinfo[256];
       titleinfo[0] = 0;

       if(IsReplayingDvd())
       {
           if (PlayerIsInMenuDomain())
           {
               sprintf(titleinfo, "DVD Menu");
           }
           else
           {
               int titleNumber=-1, titleCount=-1, chapterNumber=-1, chapterCount=-1;
               //int num_angle = -1, cur_angle = -1;

               titleNumber = xineLib_.DvdTitleNumber();
               titleCount = xineLib_.DvdTitleCount();
               chapterNumber = xineLib_.DvdChapterNumber();
               chapterCount = xineLib_.DvdChapterCount();

               //more detailed information
               /*if (titleCount >= 1)
               {
                   //no menu here
                   //Reflect angle info if appropriate
                   num_angle = xineLib_.DvdAngleNumber();
                   cur_angle = xineLib_.DvdAngleCount();
               }

               if (XineSetup_Display >=1)
               {
                   if(num_angle>1)
                   {
                       sprintf(titleinfo, "dvd: %d/%d %d/%d %d/%d",
                       titleNumber, titleCount,  chapterNumber, chapterCount,
                       cur_angle, num_angle);
                   }
                   else
                   {
                       sprintf(titleinfo, "dvd: %d/%d %d/%d",
                       titleNumber, titleCount,  chapterNumber, chapterCount);
                   }
               }*/
               if(xineLib_.GetTitle())
               {
                   snprintf(titleinfo, 255, "%s %s %d" ,xineLib_.GetTitle(), tr("Chapter"), chapterNumber);
               }
           }
       }
       else if(IsReplayingMusic())
       {
           if(xineLib_.GetTitle())
           {
               //snprintf(titleinfo, 255, "%s %s %s Track %s" ,xineLib_.GetTitle(), Artist(), Album(), TrackNumber());
               snprintf(titleinfo, 255, "%s" ,xineLib_.GetTitle());
           }
           else //use mrl
           {
               snprintf(titleinfo, 255, "%s" , GetFileName(GetMrl()).c_str());
           }
       }
       else
       {
           if(xineLib_.GetTitle())
           {
               snprintf(titleinfo, 255, "%s" ,xineLib_.GetTitle());
           }
           else //use mrl
           {
               snprintf(titleinfo, 255, "%s" , GetFileName(GetMrl()).c_str());
           }
       }

       if (string(titleinfo) != "")  // XXX !!
       {
          titleInfo_ = titleinfo;
       }
       else
       {
          titleInfo_ = "";// leave titleInfo_ empty // XXX !!
       }
    }

}
}
