/***************************************************************************
 *   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.             *
 ***************************************************************************/

// xine_mediaplayer.c
#include "cddb.h"

#include "xinemediaplayer.h"
#include "i18n.h"

#include "Player.h"
#include "Control.h"
#include <vdr/remote.h>

#include <cstring>
#include <string>
#include <vector>

#include "m3u_parser.h"
#include "pls_parser.h"

#include "timecounter.h"

cTimeCounter timeCounter;

static const char *VERSION = "0.0.8";

namespace Reel
{
namespace XineMediaplayer
{

        // time counter : holds the duration of the time a player session was live, minus the paused duration

	namespace {
		PCSTR VersionString     =  VERSION;
		PCSTR DescriptionString = "Xine Mediaplayer plugin";
		// TODO: maybe only add supported file types?
		static const char *DEFAULT_EXTENSIONS = "! cue bin deb txt jpg jpeg bmp tif tiff xpm m3u playlist mp3 wav ogg gif png";
	}
	
	Plugin::Plugin() : mExtensions(DEFAULT_EXTENSIONS) {
	} // Plugin::Plugin
	Plugin::~Plugin() {
	} // Plugin::~Plugin
	PCSTR Plugin::Version() {
		return VersionString;
	} // Plugin::Version
	PCSTR Plugin::Description() {
		return DescriptionString;
	} // Plugin::Description
	bool Plugin::SetupParse(const char *Name, const char *Value) {
		if (!strcasecmp(Name, "Extensions")) mExtensions = Value;
		else if (!strcasecmp(Name, "DelayAudio")) ; // Settings used by XineLib
		else if (!strcasecmp(Name, "DelaySPU"))   ; // Settings used by XineLib
		else
			return false;
		return true;
	} // Plugin::SetupParse
	bool Plugin::Initialize() { 
		RegisterI18n(Phrases);
		return true;
	} // Plugin::Initialize

        const char **Plugin::SVDRPHelpPages(void)
        {
            static const char *HelpPages[] = {
                "PLAYM3U <filename>\n"
                    "    Triggers playback of playlist 'filename'.",
                NULL
            };
            return HelpPages;
        } // Plugin::SVDRPHelpPages

        void print_vec(std::vector<std::string>& vec)
        {
          unsigned int i=0;
          for (; i<vec.size(); ++i)
           printf("%s\n",vec.at(i).c_str() );
            //std::cout<<vec.at(i)<<std::endl;
          
        }
        
    bool start_xinemediaplayer_with_m3u(const char* m3u_filename, int plugin_to_call)
    {
        std::vector<std::string> url_list, name_list;

        if ( m3u_parser( m3u_filename, url_list, name_list ) )
        {
            // set names and url_list
            cXineOsd::playListEntries = url_list;
            cXineOsd::nameListEntries = name_list;
            
            /*
            print_vec( url_list );
            
            std::cout<<std::endl<<" xine playlist entries \n";
            
            print_vec( cXineOsd::playListEntries );*/
          // std::cout<<std::endl<<"name list \n";
            
            //print_vec( name_list );
            /*
            std::cout<<std::endl<<"Xine namelist entries\n";
            
            print_vec( cXineOsd::nameListEntries );
            */

            if ( !cXineOsd::isPlaying ) // Donot launch new control if already playing, just add to existing playlist
            {
                cXineOsd::control = new Control( url_list[0].c_str() , 1, url_list );

                ::cControl *control = cXineOsd::control;
                ::cControl::Launch(control);
            }
            else
            {
                //Refresh
                cXineOsd::isNew = true; 
                LOC; printf("\n\tSetting new playlist\n");
                cXineOsd::control->SetPlayList( cXineOsd::playListEntries );
            }
            cXineOsd::k_blue = plugin_to_call;
	    cXineOsd::kPausePressed = 0;
            cRemote::CallPlugin("xinemediaplayer");
            return true;
        }
        else 
            return false;
    }
        cString Plugin::SVDRPCommand(const char* Command, const char *Option,  int &ReplyCode)
        {
           if(!strcasecmp(Command,"PLAYM3U") || !strcasecmp(Command,"PLAYM3U_SHOUTCAST") || !strcasecmp(Command,"PLAYM3U_IPOD" ) ||  !strcasecmp(Command,"PLAYM3U_FILEBROWSER") )
           {   
               if (!Option)
               {
                   ReplyCode = 550;
                   return "a m3u file missing";
               }
 
               int plugin_to_start = NO_PLUGIN;

             if ( !strcasecmp(Command,"PLAYM3U") ) plugin_to_start = NO_PLUGIN;
             else if ( !strcasecmp(Command,"PLAYM3U_FILEBROWSER") ) plugin_to_start = FILEBROWSER_PLUGIN; 
             else if ( !strcasecmp(Command,"PLAYM3U_SHOUTCAST") ) plugin_to_start = SHOUTCAST_PLUGIN;
             else if ( !strcasecmp(Command,"PLAYM3U_IPOD") ) plugin_to_start = IPOD_PLUGIN;

               if ( start_xinemediaplayer_with_m3u (Option, plugin_to_start ) )
               {
                   ReplyCode = 900;
                   return cString::sprintf("xinemediaplayer called with %s", Option );
               }
               else
               {
                   ReplyCode = 550;
                   return "m3u parser error";
               }
           }

           ReplyCode = 550;
           return NULL;
        }
        
//         
////////////////////////////////////////////////////////////////////////////////

	bool Plugin::Service(char const *id, void *data) {

                if (std::strcmp(id, "Set Xine Mode") == 0){
                  
                  int *xineMode = static_cast<int *> (data);
                  
                  if ( !xineMode ){
                    cXineOsd::k_blue = NO_PLUGIN;
                    return true;
                }
                
                  switch (*xineMode)
                  {
                    case 0: // no plugin
                      cXineOsd::k_blue = NO_PLUGIN;
                      break;
              
                    case 1: // filebrowser
                        cXineOsd::k_blue = FILEBROWSER_PLUGIN;
                        break;
              
                    case 2: // shoutcast
                          cXineOsd::k_blue = SHOUTCAST_PLUGIN;
                          break;
              
                    case 3: // shoutcast
                          cXineOsd::k_blue = MMFILES_PLUGIN;
                          break;
              
                    default: // no plugin
                        cXineOsd::k_blue = NO_PLUGIN;
                        break;
                  }
                  
                  return true;
                }
                
                
		if (std::strcmp(id, "Xine Status") == 0) {
			struct XineStatus {
				bool status;
			};
			return true;
		} // if
                

                if (std::strcmp(id, "Xine Play VideoCD")==0)
                {

                    CdIo_t *cdio;               /* libcdio CD access structure */

                    char *device = cdio_get_default_device(NULL);
                    if (!device) {
                        esyslog ("unable to get default CD device");
                        Skins.Message(mtError, tr("Unable to get default CD device")); 
                        return true;
                    }

                    printf("CD-ROM device: %s\n", device);

                    /* Load the appropriate driver and open the CD-ROM device for reading. */
                    cdio = cdio_open(device, DRIVER_UNKNOWN);
                    if (!cdio) {
                        esyslog("unable to open CD device");
                        Skins.Message(mtError, tr("Unable open CD device")); 
                        return true;
                    }

                    /* Get the track count for the CD. */
                    int count = cdio_get_num_tracks(cdio); 
                    cdio_destroy(cdio);

                    if (count == 0) 
                    {
                        esyslog("found no tracks in CD");
                        Skins.Message(mtError, tr("No tracks found in CD"));
                        return true;
                    }

                    cXineOsd::playListEntries.clear();
                    cXineOsd::nameListEntries.clear();

                    char buffer[16];
                    for (int i=1; i<= count; ++i)
                    {
                        snprintf(buffer,15, "vcd://%i", i);
                        cXineOsd::playListEntries.push_back(buffer);
                        snprintf(buffer,15, "Track - %i", i);
                        cXineOsd::nameListEntries.push_back(buffer);
                    }

                    cXineOsd::isNew = 1;

                    if ( cXineOsd::isPlaying ) // Donot launch new control if already playing, just replace existing playlist
                    {         
                        cXineOsd::control->SetPlayList( cXineOsd::playListEntries );
                        cXineOsd::firstOpen = false;
                    }
                    else
                    {
                        cXineOsd::control = new Control(cXineOsd::playListEntries.at(0).c_str(), 1, cXineOsd::playListEntries);

                        ::cControl *control = cXineOsd::control;
                        ::cControl::Launch(control);
                        cXineOsd::firstOpen = true;
                    }

                    cXineOsd::k_blue = NO_PLUGIN;
		    cXineOsd::kPausePressed = 0;
                    cRemote::CallPlugin("xinemediaplayer");
                    return true;
                }


                if (std::strcmp(id, "Xine Play AudioCD")==0)
                {
                  // Get number of cd tracks
                  cCdInfo&cdInfo = cCdInfo::GetInstance();
                  int ret = cdInfo.AudioCdInit();
                  
                  int totalCdTracks = cdInfo.TrackCount();
                  if (ret && totalCdTracks <=0 )
                  {
                      Skins.Message(mtError, tr("No audio tracks found"));

                      // shutdown splash screen
                      cPlugin *p = cPluginManager::GetPlugin("mediad");
                      if (p)
                      {
                          p->Service("HideSplashScreen");
                      }
                      return true;
                  }
                  
                  // build playlist
                  vector <string> audioCdPlaylist;
                  vector <string> trackNames;

                  char buffer[32];
                  
                  for (int i=0; i<totalCdTracks; ++i)
                  {
                    // if starting track num != 1, does xine require 
                    // track with track number or track index ? //TODO //XXX
                    snprintf(buffer,31, "cdda://%i", cdInfo.TrackNumberByIndex(i));
                    audioCdPlaylist.push_back(buffer);
                  }
                  
                  //Get Track names/titles
                  string title,artist, name;
                  for (int i=0; i< totalCdTracks; ++i)
                  {
                    title = cdInfo.TrackTitleByIndex(i);
                    artist = cdInfo.TrackArtistByIndex(i);
                    if (title.empty())
                    {
                        snprintf(buffer, 31, "%s - %i", tr("Track"), cdInfo.TrackNumberByIndex(i));
                        name = buffer;
                    }
                    else
                        name = title + " - " + artist;

                    trackNames.push_back(name);
                  }
                  
                  cXineOsd::playListEntries = audioCdPlaylist;
                  cXineOsd::nameListEntries = trackNames;
                  cXineOsd::isNew = 1;
                  
                  if ( cXineOsd::isPlaying ) // Donot launch new control if already playing, just replace existing playlist
                  {         
                    cXineOsd::control->SetPlayList( cXineOsd::playListEntries );
                  }
                  else
                  {
                    cXineOsd::control = new Control(cXineOsd::playListEntries.at(0).c_str(), 1, cXineOsd::playListEntries);

                      ::cControl *control = cXineOsd::control;
                      ::cControl::Launch(control);
                  }
                  
                  cXineOsd::k_blue = NO_PLUGIN;
		  cXineOsd::kPausePressed = 0;
                  cRemote::CallPlugin("xinemediaplayer");
                  return true;
                }



		if (std::strcmp(id, "Xine Test mrl") == 0) {

			struct XineTestData {
				char const *mrl;
				bool result;
			};
			static_cast<XineTestData *>(data)->result = checkExtension(static_cast<XineTestData *>(data)->mrl);
			//syslog(LOG_INFO, "XineMediaplayer Plugin::Service Xine Test mrl %s: %s", static_cast<XineTestData *>(data)->mrl, static_cast<XineTestData *>(data)->result?"true":"false");
			return true;
		} // if



		if (std::strcmp(id, "Xine Play mrl") == 0) {

                        struct XinePlayData {
                                char const *mrl; 
                                int instance; 
                                bool playlist;
                                std::vector<std::string> playlistEntries;
                        };
			syslog(LOG_INFO, "XineMediaplayer Plugin::Service Xine Play mrl %s", static_cast<XinePlayData *>(data)->mrl);
			//::cControl *control = new Control(static_cast<XinePlayData *>(data)->mrl);  

                        if (static_cast<XinePlayData *>(data)->mrl)
                            cXineOsd::mrl = strdup(static_cast<XinePlayData *>(data)->mrl);
                        else
                            cXineOsd::mrl =NULL;


                        cXineOsd::isNew = true; 
			cXineOsd::isPlaylist = static_cast<XinePlayData *>(data)->playlist ; 
            cXineOsd::browserInstance = static_cast<XinePlayData *>(data)->instance;
			cXineOsd::playListEntries = static_cast<XinePlayData *>(data)->playlistEntries;


                        // add mrl to playlist if playlist is empty
                        //  happens when in filebrowser no playlist is created but just a "kOk" is press to play the file
                        if ( cXineOsd::playListEntries.size() <= 0  && cXineOsd::mrl!= NULL) 
                            cXineOsd::playListEntries.push_back( cXineOsd::mrl );

                        // create a vector of empty strings, these are filled in if possible by XineOsd
                        cXineOsd::nameListEntries.clear();
                        for (unsigned int i=0; i<cXineOsd::playListEntries.size(); ++i)
                            cXineOsd::nameListEntries.push_back("");


                        //TODO REMOVE this

			/**** merge the playlists ****/
			std::vector<std::string>::iterator it1, it = static_cast<XinePlayData *>(data)->playlistEntries.begin();
			std::vector<std::string>::iterator END = static_cast<XinePlayData *>(data)->playlistEntries.end();

			printf("(%s:%d) MRL: %s\n", __FILE__,__LINE__, cXineOsd::mrl);
			if (cXineOsd::mrl != NULL)
			{
				/***add the mrl into cXineOsd::Playlist****/
				std::string mrl_str = cXineOsd::mrl;
				std::string plain_mrl ; // without 'file://' like entries in playlist
			 	size_t found = mrl_str.find("file://");
				if ( found != std::string::npos) 
					plain_mrl = mrl_str.substr(found+7); // remove file:://

				printf("(%s:%d) MRL: %s %s\n", __FILE__,__LINE__, mrl_str.c_str(), plain_mrl.c_str());

				it1 = cXineOsd::playListEntries.begin();
				while ( it1 != cXineOsd::playListEntries.end() )
				{
					if (*it1 == mrl_str || *it1 == plain_mrl)
						break;

					it1++;
				}
				// not found
				if (it1 ==  cXineOsd::playListEntries.end()) cXineOsd::playListEntries.push_back(mrl_str);
			}

			//bool isDuplicate; // no repetitions in playlist
			//playlist is handled by filebrowser, so donot add to current playlist
			/*
			for ( ; false && it != END ; ++it) 
			{
				isDuplicate = false;

				it1 = cXineOsd::playListEntries.begin();
				while( it1 != cXineOsd::playListEntries.end() )
				{
					if ( *it == *it1 ) // duplicate
					 {
					  isDuplicate = true; 
					  break;
					 }
					 it1++;
				}
				if (!isDuplicate) // then Add to playlist
					cXineOsd::playListEntries.push_back(*it);
			}
			*/
                        if ( cXineOsd::isPlaying ) // Donot launch new control if already playing, just add to existing playlist
                        {         
                          cXineOsd::control->SetPlayList( cXineOsd::playListEntries );
                          cXineOsd::firstOpen = false;
                        }
                        else
			{
				cXineOsd::control = new Control(static_cast<XinePlayData *>(data)->mrl, 
						/*static_cast<XinePlayData *>(data)->playlist*/    1, // always a playlist
						/*static_cast<XinePlayData *>(data)->playlistEntries*/ 
                                                cXineOsd::playListEntries);

				::cControl *control = cXineOsd::control;
				::cControl::Launch(control);
                                cXineOsd::firstOpen = true;
			}
                       

                        cXineOsd::k_blue = FILEBROWSER_PLUGIN;
			cXineOsd::kPausePressed = 0;
			// donot call OSD if dvd:// is played and playlist size <= 1
			 std::string mrlStr = cXineOsd::mrl;
			if ( mrlStr.find("dvd://") != std::string::npos && cXineOsd::playListEntries.size() <= 1) // playing DVD
                        cXineOsd::k_blue = NO_PLUGIN;
			else
				if (cRemote::CallPlugin("xinemediaplayer"))
					printf("(%s:%d) Called xinemediaplayer\n",__FILE__, __LINE__);

			return true;
		} // if
		return false;
	}




    bool Plugin::Start() {
#ifdef RBLITE	
		cSetupLine* lLine = Setup.Get("UseHdExt","reelbox");
		if(lLine && lLine->Value() && atoi(lLine->Value()))
		    useOld = 0;
#else
		useOld = 0;
#endif	    
		return true;
	} // Plugin::Start
	bool Plugin::checkExtension(const char *fFile) {
		if(useOld) return false;
		bool lRet = true;
		if(!fFile)
			return false;
		if (!strcmp(mExtensions.c_str(), "*"))
			return true;
		const char *lExt = strrchr(fFile, '.');
		if(!lExt)
			return false;
		lExt++;
		if(!*lExt)
			return false;
		if (!strncmp(mExtensions.c_str(), "! ", 2))
			lRet = false;
		int lLen = strlen(lExt);
		const char *lPos = mExtensions.c_str();
		const char *lNext = strchr(lPos, ' ');
		while (lPos) {
			if (lNext) {
				if ((lLen == (lNext - lPos)) && !strncasecmp(lExt, lPos, lNext - lPos))
					return lRet;
				lPos = ++lNext;
				lNext = strchr(lPos, ' ');
			} else {
				if (!strcasecmp(lExt, lPos))
					return lRet;
				lPos = lNext;
			} // if
		} // while
		return !lRet;
	} // Plugin::checkExtension
}
}

VDRPLUGINCREATOR(Reel::XineMediaplayer::Plugin); // Don't touch this!
