/***************************************************************************
 *   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.h
 
#ifndef XINE_MEDIAPLAYER_PLAYER_H_INCLUDED
#define XINE_MEDIAPLAYER_PLAYER_H_INCLUDED

#include "Reel.h"
#include "XineLib.h"

#include "SpuDecode.h"

#include <vdr/player.h>
#include <vdr/osdbase.h>

#include <string>
#include <vector>

#include "item_tree.h"

namespace Reel
{
namespace XineMediaplayer
{
    enum {PLAY_NORMAL=1, PLAY_RANDOM, PLAY_REPEAT_SINGLE, PLAY_REPEAT_PLAYLIST};
    // PLAY_REPEAT_SINGLE : plays the same file 1/0 times.

    class Player : public ::cPlayer /* final */
    {
    public:
        Player(const char *mrl, bool playlist, std::vector<std::string> playlistEntries) NO_THROW;
        ~Player() NO_THROW;

        // cPlayer
        /* override */ void Activate(bool on) NO_THROW;
        /* override */ virtual eOSState ProcessKey(eKeys key) THROWS; 

        /* override */ bool CanHandleMenuCalls() NO_THROW;
        /* override */ bool PlayerIsInMenuDomain() NO_THROW; 

        // start by Balaji
        /* override */ bool CanHandleSubtitles() NO_THROW;
        /* override */ int  NumSubtitleTracks() NO_THROW;
        /* override */ bool SetCurrentSubtitleTrack(int a);
        /* override */ int  GetCurrentSubtitleTrack();
        /* override */ const char* SubtitleTrackName(int a);
        // end by Balaji

        eOSState Number(eKeys Key);

        /* override */ cOsdObject *GetInfo(void);
        /* override */ bool GetIndex(int &Current, int &Total, bool SnapToIFrame = false);
        /* override */ void SetAudioTrack(eTrackType Type, const tTrackId *TrackId);
        /* override */ bool GetReplayMode(bool &Play, bool &Forward, int &Speed);
        //
        ///< sets given audio tracks  menu:c cDisplayTracks called by kAudio
        ///< register each track with vdr/device.h/Player::DeviceSetAvailableTrack 

        void ShowSplashScreen();

        void HandleEvents() THROWS;   

        void ProcessSpu();
        bool SpuHasOsd();
        void HideSPU();
        void SetMenuDomain(bool isInMenuDomain);
        bool Playing();
        bool IsReplayingMusic();
        bool IsReplayingDvd();
        bool IsReplayingVideo();

	int CurrentPlayNr(); // current position on playlist
	void ReplacePlayList(std::vector<std::string> newPl); // New playlist on the fly
	bool PlayFileNumber(unsigned int); // random access to files in playlist
        void SetPlayMode(int);
        int GetPlayMode();

       std::string GetTitleInfoString(); 
       ///< returns current Title Chapter and Angle if aviable 
       ///< 
       void SetTitleInfoString();
       ///< writes current Title Chapter and Angle if aviable  
       ///< updates are triggerd by xine events
       
        
       const char *GetTitleString() const;




       const char *GetAspectString() const;
       ///< can`t get valid Aspect infos ???

       void SetAllAudioTracks();
       void SetAllSpuTracks();
       ///< missing implementation of spu tracks inside vdr 

       void SetInitLangCode();
       std::string GetAudioLangCode() const;
       std::string GetSpuLangCode() const;

    private:
        Player(Player const &); // No copying.
        Player &operator=(Player const &); // No assigning.

        std::vector < cItemTree > vItemTree;

        // sets elements of vItemTree with playlistEntries items as "head"
        void CreateItemTree(); 

        // Get next mrl from tree nr. tree_num: "" is returned if tree has no more playable entries, go to next tree
        std::string GetNextFromTree(unsigned int tree_num)
        { 
            return tree_num < vItemTree.size() ? vItemTree[tree_num].GetNext(true) : ""; 
        }  
        std::string GetPrevFromTree(unsigned int tree_num)
        { 
            return tree_num < vItemTree.size() ? vItemTree[tree_num].GetNext(false): ""; 
        }    

        std::string GetNextPlayListEntryCyclic(bool up) NO_THROW; 
        void PlayNextPlayListEntry(bool up) THROWS;
        void StartPlayback() THROWS;
        void StopPlayback() NO_THROW; 
        void ReStartPlayback() THROWS;   

	void InitPlayListPos(); // sets  pl_pos according to position of  mrl_ in playlistEntries
	int pl_pos; 		// position of currently playing file in playlistEntries
        XineLib &xineLib_;

        // Indicates how Player selectes the next file to be played
        int play_mode;

        bool playing_;
        bool  mrlOpenError_;

        bool mrlIsInPlaylist_; //mrl is part of a playlist handled externally
        bool playlist_;  //playlist is handled by this plugin
        std::vector<std::string> playlistEntries_; //the playlist
        bool loopmode_;

        bool isInMenuDomain_;

        SpuDecoder spu_;

        std::string mrl_;

        std::string titleInfo_;

        int SearchAudioStream(int AudioStreamId);

        struct tTrackId_type {
            tTrackId tTID  ;
            eTrackType eTType; 
        };
        //std::vector<tTrackId_type > aviableAudioTracks_;
        std::vector<tTrackId> aviableAudioTracks_;
        std::vector<tTrackId> aviableSpuTracks_;
        void SetAvailableTracks();
        uint32_t GetAuidoPids(std::string& langCode, eTrackType TrackType);


        int currentAudioTrack;
        // XXX verify  currentLangCode 
        //char currentLangCode_[32];
        char selectedLangCode_[32];

        int currentSpuTrack;

        cTimeMs numberTimer;
	cTimeMs writeWait;
        int number;
        
    public:
        static const int MaxAudioTracks;
        static const int AudioTrackMask;
        static const int AC3AudioTrackMask;
        static const int MaxSubpStreams;
        static const int SubpStreamMask;
        /// xinelib Infos 
        bool GetInfos();
        std::string GetMrl() { return mrl_; }

	bool IsPaused();

        uint32_t GetBitrate();
        
        uint32_t Bitrate();

        uint32_t Seekable();

        uint32_t VideoWidth();

        uint32_t VideoHeight();

        uint32_t VideoRatio();

        uint32_t VideoChannels();

        uint32_t VideoStreams();

        uint32_t VideoBitrate();

        uint32_t VideoFourcc();

        uint32_t VideoHandled();

        uint32_t FrameDuration();

        uint32_t AudioChannels();

        uint32_t AudioBits();

        uint32_t AudioSamplerate();

        uint32_t AudioBitrate();

        uint32_t AudioFourcc();

        uint32_t AudioHandled();

        uint32_t HasChapters();

        uint32_t HasVideo();

        uint32_t HasAudio();

        uint32_t IgnoreVideo();

        uint32_t IgnoreAudio();

        uint32_t IgnoreSpu();

        uint32_t VideoHasStill();

        uint32_t MaxAudioChannel();

        uint32_t MaxSpuChannel();

        uint32_t AudioMode();

        uint32_t SkippedFrames();

        uint32_t DiscardedFrames();

        uint32_t VideoAfd();

        uint32_t DvdTitleNumber();

        uint32_t DvdTitleCount();

        uint32_t DvdChapterNumber();

        uint32_t DvdChapterCount();

        uint32_t DvdAngleNumber();

        uint32_t DvdAngleCount();


        // xine meta infos 
       
        const char *GetTitle() const;

        const char *Comment() const;

        const char *Artist() const;

        const char *Genre() const;

        const char *Album() const;

        const char *Year() const;

        const char *VideoCodec() const;

        std::string AudioCodec();

        const char *SystemLayer() const;

        const char *InputPlugin() const;

        const char *CDIndexDiscId() const;

        const char *TrackNumber() const;

    };

    // Inline Player 
    ///////////////////////////////////////////////////////////////////////////

    inline bool Player::IsPaused()
    {
    	return xineLib_.GetParamSpeed() == XINE_SPEED_PAUSE;
    }
    inline bool Player::CanHandleMenuCalls() 
    {
        //printf("-------Player::CanHandleMenuCalls------ return true ----\n");
        return true;
    }  

    inline bool Player::Playing() // PlayStream
    {
        return playing_;
    }

    //is inside a DVD Menu or not replaying a dvd
    inline bool Player::PlayerIsInMenuDomain() 
    { 
        return isInMenuDomain_ || !IsReplayingDvd();
    } 
    // Start by Balaji
    inline bool Player::CanHandleSubtitles()
    {
        return playing_ ;  // if playing, it can handle subtitles
    }
    inline int Player::NumSubtitleTracks()
    {
        if ( GetSpuLangCode().find("menu")!=std::string::npos) return 0;
        else
        return MaxSpuChannel() ;
    }
    inline bool Player::SetCurrentSubtitleTrack(int idx)
    {
        xineLib_.SetParamSPUChannel(idx-1);
        return true;
    }
    inline int Player::GetCurrentSubtitleTrack()
    {
        return xineLib_.GetParamSPUChannel();
    }
    inline const char* Player::SubtitleTrackName(int idx)
    {
        char *langStr = (char*) malloc(sizeof(char)*80);
        if ( xineLib_.GetSpuLangCode(langStr, idx) )
        {
            return langStr;
        }
        else 
        {
            free(langStr);
            return "";
        }
    }
    // end by Balaji
    inline void Player::ProcessSpu()
    {
        if(useOld)
          spu_.ProcessSpuEvents();
    } 
    inline bool Player::SpuHasOsd() 
    {
        //printf("------- %s ----------\n", __PRETTY_FUNCTION__);
        return useOld?spu_.HasOsd():false;
    }
    inline void Player::HideSPU() 
    {
        //printf("------- %s ----------\n", __PRETTY_FUNCTION__);
        //spu_.Hide(true);
        if(useOld)
	  spu_.TakeOsd();
        // TODO rename  spu_.OsdTaken();
    }
    inline void Player::SetMenuDomain(bool isInMenuDomain)
    {
        //printf("------- %s ----------\n", __PRETTY_FUNCTION__);
        isInMenuDomain_ = isInMenuDomain;
        if(useOld)
          spu_.SetMenuDomain(isInMenuDomain);
    }

    inline std::string Player::GetTitleInfoString()
    {
        //printf("------- %s ----------\n", __PRETTY_FUNCTION__);
        return titleInfo_;
    }

    inline const char *Player::GetAspectString() const
    {
        //printf("------- %s ----------\n", __PRETTY_FUNCTION__);
        // gets no usfull information
        return xineLib_.GetAspectString();
    }
 
    inline std::string Player::GetAudioLangCode() const
    {
        char lang[XINE_LANG_MAX];
        if (!xineLib_.GetAudioLangCode(lang))
          return "";
        else 
          return lang;
    }

    //inline const char *Player::GetSpuLangCode() const
    inline std::string Player::GetSpuLangCode() const
    {
        char lang[XINE_LANG_MAX];
        if (!xineLib_.GetSpuLangCode(lang))
          return "";
        else 
          return lang;  
    }

    inline bool Player::GetReplayMode(bool &Play, bool &Forward, int &Speed)
    {
        int speed_param = xineLib_.GetParamSpeed();
        //printf (" --- %s --- speed %d \n", __PRETTY_FUNCTION__, speed_param);

        // TODO play direction

        switch (speed_param)
        {
            case XINE_SPEED_PAUSE:
                Play=false; Forward=true;Speed= -1;
                return true;
            case XINE_SPEED_SLOW_4:
                Play=false; Forward=true;Speed= 3;
                return true;
            case XINE_SPEED_SLOW_2:
                Play=false; Forward=true;Speed= 1;
                return true;
            case XINE_SPEED_NORMAL:
                Play=true; Forward=true;Speed= -1;
                return true;
            case XINE_SPEED_FAST_2:
                Play=true; Forward=true;Speed= 1;
                return true;
            case XINE_SPEED_FAST_4:
                Play=true; Forward=true;Speed= 3;
                return true;
            default:
              return false;
       }
    }

    inline bool Player::GetIndex(int &Current, int &Total, bool SnapToFrame)
    {
        return xineLib_.GetIndex(Current, Total);
    }

    ///////////////////////////////////////////////////////////////////////////
    // Xine lib stream info and meta info

    ///////////////////////////////////////////////////////////////////////////
    // xine stream info
    inline uint32_t Player::GetBitrate()
    {
        return xineLib_.GetBitrate();
    }

    inline uint32_t Player::Seekable()
    {
        return xineLib_.Seekable();
    }

    inline uint32_t Player::VideoWidth()
    {
        return xineLib_.VideoWidth();
    }

    inline uint32_t Player::VideoHeight()
    {
        return xineLib_.VideoHeight();
    }

    inline uint32_t Player::VideoRatio()
    {
        return xineLib_.VideoRatio();
    }

    inline uint32_t Player::VideoChannels()
    {
        return xineLib_.VideoChannels();
    }

    inline uint32_t Player::VideoStreams()
    {
        return xineLib_.VideoStreams();
    }

    inline uint32_t Player::VideoBitrate()
    {
        return xineLib_.VideoBitrate();
    }

    inline uint32_t Player::VideoFourcc()
    {
        return xineLib_.VideoFourcc();
    }

    inline uint32_t Player::VideoHandled()
    {
        return xineLib_.VideoHandled();
    }

    inline uint32_t Player::FrameDuration()
    {
        return xineLib_.FrameDuration();
    }

    inline uint32_t Player::AudioChannels()
    {
        return xineLib_.AudioChannels();
    }

    inline uint32_t Player::AudioBits()
    {
        return xineLib_.AudioBits();
    }

    inline uint32_t Player::AudioSamplerate()
    {
        return xineLib_.AudioSamplerate();
    }

    inline uint32_t Player::AudioBitrate()
    {
        return xineLib_.AudioBitrate();
    }

    inline uint32_t Player::AudioFourcc()
    {
        return xineLib_.AudioFourcc();
    }

    inline uint32_t Player::AudioHandled()
    {
        return xineLib_.AudioHandled();
    }

    inline uint32_t Player::HasChapters()
    {
        return xineLib_.HasChapters();
    }

    inline uint32_t Player::HasVideo()
    {
        return playing_ && xineLib_.HasVideo();
    }

    inline uint32_t Player::HasAudio()
    {
        return xineLib_.HasAudio();
    }

    inline uint32_t Player::IgnoreVideo()
    {
        return xineLib_.IgnoreVideo();
    }

    inline uint32_t Player::IgnoreAudio()
    {
        return xineLib_.IgnoreAudio();
    }
    inline uint32_t Player::IgnoreSpu()
    {
        return xineLib_.IgnoreSpu();
    }

    inline uint32_t Player::VideoHasStill()
    {
        return xineLib_.VideoHasStill();
    }

    inline uint32_t Player::MaxAudioChannel()
    {
        return xineLib_.MaxAudioChannel();
    }

    inline uint32_t Player::MaxSpuChannel()
    {
        return xineLib_.MaxSpuChannel();
    }

    inline uint32_t Player::AudioMode()
    {
        return xineLib_.AudioMode();
    }

    inline uint32_t Player::SkippedFrames()
    {
        return xineLib_.SkippedFrames();
    }

    inline uint32_t Player::DiscardedFrames()
    {
        return xineLib_.DiscardedFrames();
    }

    inline uint32_t Player::VideoAfd()
    {
        return xineLib_.VideoAfd();
    }

    inline uint32_t Player::DvdTitleNumber()
    {
        return xineLib_.DvdTitleNumber();
    }

    inline uint32_t Player::DvdTitleCount()
    {
        return xineLib_.DvdTitleCount();
    }

    inline uint32_t Player::DvdChapterNumber()
    {
        return xineLib_.DvdChapterNumber();
    }

    inline uint32_t Player::DvdChapterCount()
    {
        return xineLib_.DvdChapterCount();
    }

    inline uint32_t Player::DvdAngleNumber()
    {
        return xineLib_.DvdAngleNumber();
    }

    inline uint32_t Player::DvdAngleCount()
    {
        return xineLib_.DvdAngleCount();
    }


    ///////////////////////////////////////////////////////////////////////////
    // xine meta infos 

    inline const char *Player::GetTitle() const
    {
        return xineLib_.GetTitle()?xineLib_.GetTitle():"";
    }

    inline const char *Player::Comment() const
    {
        return xineLib_.Comment();
    }

    inline const char *Player::Artist() const
    {
        return xineLib_.Artist();
    }

    inline const char *Player::Genre() const
    {
        return xineLib_.Genre();
    }

    inline const char *Player::Album() const
    {
        return xineLib_.Album();
    }

    inline const char *Player::Year() const
    {
        return xineLib_.Year();
    }

    inline const char *Player::VideoCodec() const
    {
        return xineLib_.VideoCodec();
    }

    inline std::string Player::AudioCodec()
    {
        const char *buf  = xineLib_.AudioCodec();
        if (!buf)
          return "";
        else 
          return buf;
    }

    inline const char *Player::SystemLayer() const
    {
        return xineLib_.SystemLayer();
    }

    inline const char *Player::InputPlugin() const
    {
        return xineLib_.InputPlugin();
    }

    inline const char *Player::CDIndexDiscId() const
    {
        return xineLib_.CDIndexDiscId();
    }

    inline const char *Player::TrackNumber() const
    {
        return xineLib_.TrackNumber();
    }
}
}

#endif // XINE_MEDIAPLAYER_PLAYER_H_INCLUDED
