//  BMP
//  Copyright (C) 2005-2007 BMP development.
//
//  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.
//
//  --
//
//  The BMPx project hereby grants permission for non-GPL compatible GStreamer
//  plugins to be used and distributed together with GStreamer and BMPx. This
//  permission is above and beyond the permissions granted by the GPL license
//  BMPx is covered by.

#ifdef HAVE_CONFIG_H
#  include <config.h>
#endif //HAVE_CONFIG_H

#include <gtkmm.h>
#include <gtk/gtk.h>
#include <glibmm.h>
#include <glibmm/i18n.h>
#include <libglademm.h>

#include "network.hh"
#include "paths.hh"
#include "stock.hh"

#include "audio/audio.hh"

#include "audio/play.hh"
#include "x_vfs.hh"

#include "ui-part-radio.hh"
#include "streams-shoutcast.hh"
#include "streams-icecast.hh"

#include "dialog-play-uri.hh"

using namespace Glib;
using namespace Gtk;
using namespace Bmp::VFS;

#define RADIO_ACTION_SHOW_ICECAST   "radio-action-show-icecast"
#define RADIO_ACTION_SHOW_SHOUTCAST "radio-action-show-shoutcast"
#define RADIO_ACTION_UPDATE_LIST    "radio-action-update-list"

namespace
{
  enum Page
  {
    PAGE_SHOUTCAST,
    PAGE_ICECAST,
  };

  const char * ui_string_radio =
  "<ui>"
  ""
  "<menubar name='MenuBarMain'>"
  "   <placeholder name='PlaceholderSource'>"
  "   <menu action='MenuUiPartRadio'>"
  "     <menuitem action='" RADIO_ACTION_UPDATE_LIST "'/>" 
  "   </menu>"
  "   </placeholder>"
  "</menubar>"
  ""
  "</ui>";
}

namespace Bmp
{
  namespace UiPart
  {
    StrV
    Radio::get_schemes ()
    {
      StrV v;
      v.push_back ("http");
      v.push_back ("mms");
      v.push_back ("mmsu");
      v.push_back ("mmst");
      return v;
    }

    void
    Radio::process (VUri const& uris)
    {
      play_uri (uris[0]);
    }

    Radio::Radio (RefPtr<Gnome::Glade::Xml> const& xml,
                  RefPtr<Gtk::UIManager>    const& ui_manager)
    : PlaybackSource  (_("Radio"), PlaybackSource::NONE, F_HANDLE_STREAMINFO)
    , Base (xml, ui_manager)
    , BookmarkHandler ()
    {
      m_ref_xml->get_widget         ("notebook-radio",              m_notebook_radio);
      m_ref_xml->get_widget         ("notebook-shoutcast-streams",  m_notebook_shoutcast);
      m_ref_xml->get_widget         ("notebook-icecast",            m_notebook_icecast);
      m_ref_xml->get_widget_derived ("shoutcast-genres",            m_shoutcast_base);
      m_ref_xml->get_widget_derived ("shoutcast-streams",           m_shoutcast_list);
      m_ref_xml->get_widget_derived ("icecast-streams",             m_icecast_list);

      m_filter_entry = manage (new Sexy::IconEntry());
      m_filter_entry->add_clear_button ();
      m_filter_entry->show();

      Label * label = manage (new Label());
      label->set_markup_with_mnemonic (_("_Search:"));
      label->set_mnemonic_widget (*m_filter_entry);
      label->show();

      m_filter_entry->signal_changed().connect (
        sigc::mem_fun (*this, &Radio::on_filter_changed));
       
      dynamic_cast<Gtk::HBox*> (m_ref_xml->get_widget ("radio-hbox-filter"))->pack_start (*label, false, false);
      dynamic_cast<Gtk::HBox*> (m_ref_xml->get_widget ("radio-hbox-filter"))->pack_start (*m_filter_entry, true, true);

      dynamic_cast<Gtk::Image *> (m_ref_xml->get_widget ("throbber-icecast"))->set (build_filename (BMP_IMAGE_DIR,BMP_THROBBER));
      dynamic_cast<Gtk::Image *> (m_ref_xml->get_widget ("throbber-shoutcast"))->set (BMP_IMAGE_DIR G_DIR_SEPARATOR_S BMP_THROBBER);

      m_shoutcast_base->signal_start().connect
        (sigc::bind (sigc::mem_fun (*m_notebook_shoutcast, &Gtk::Notebook::set_current_page), 1));
      m_shoutcast_base->signal_stop().connect
        (sigc::bind (sigc::mem_fun (*m_notebook_shoutcast, &Gtk::Notebook::set_current_page), 0));
      m_shoutcast_base->signal_start().connect
        (sigc::bind (sigc::mem_fun (*m_shoutcast_base, &Gtk::Widget::set_sensitive), false));
      m_shoutcast_base->signal_stop().connect
        (sigc::bind (sigc::mem_fun (*m_shoutcast_base, &Gtk::Widget::set_sensitive), true));
      m_shoutcast_base->signal_list_updated().connect
        (sigc::mem_fun (*this, &Radio::on_shoutcast_list_updated));
      m_shoutcast_list->signal_row_activated().connect
        (sigc::mem_fun (*this, &Radio::on_row_activated));
      m_shoutcast_list->get_selection()->signal_changed().connect
        (sigc::bind (sigc::mem_fun (*this, &Radio::on_selection_changed), dynamic_cast<RadioDirectory::ViewBase*>(m_shoutcast_list) ) );

      m_icecast_list->signal_start().connect
        (sigc::bind (sigc::mem_fun (*m_icecast_list, &Gtk::Widget::set_sensitive), false));
      m_icecast_list->signal_stop().connect
        (sigc::bind (sigc::mem_fun (*m_icecast_list, &Gtk::Widget::set_sensitive), true));
      m_icecast_list->signal_stop().connect
        (sigc::mem_fun (*this, &Radio::on_icecast_list_updated));
      m_icecast_list->signal_row_activated().connect
        (sigc::mem_fun (*this, &Radio::on_row_activated));
      m_icecast_list->get_selection()->signal_changed().connect
        (sigc::bind (sigc::mem_fun (*this, &Radio::on_selection_changed), dynamic_cast<RadioDirectory::ViewBase*>(m_icecast_list) ) );

      m_actions = ActionGroup::create ("Actions_Radio");
      m_actions->add (Action::create ("MenuUiPartRadio", _("Radio")));

      m_actions->add  (Action::create (RADIO_ACTION_UPDATE_LIST,
                                        Gtk::Stock::REFRESH,
                                        _("Update Icecast List")), 
                                        AccelKey("<control>r"), 
                                        (sigc::mem_fun (*this, &Radio::on_update_list)));

      Gtk::RadioButtonGroup gr1;
      m_actions->add  (RadioAction::create (gr1, RADIO_ACTION_SHOW_SHOUTCAST,
                                            Gtk::StockID (BMP_STOCK_XIPH),
                                            "Shoutcast"),
                                            (sigc::mem_fun (*this, &Radio::on_set_notebook_page)));

      m_actions->add  (RadioAction::create (gr1, RADIO_ACTION_SHOW_ICECAST,
                                            Gtk::StockID (BMP_STOCK_XIPH),
                                            _("Icecast")),
                                            (sigc::mem_fun (*this, &Radio::on_set_notebook_page)));

      RefPtr<Gtk::RadioAction>::cast_static (m_actions->get_action (RADIO_ACTION_SHOW_SHOUTCAST))->property_value() = 0; 
      RefPtr<Gtk::RadioAction>::cast_static (m_actions->get_action (RADIO_ACTION_SHOW_ICECAST))->property_value() = 1; 

      m_actions->get_action (RADIO_ACTION_SHOW_SHOUTCAST)->connect_proxy
            (*(dynamic_cast<ToggleToolButton *>(m_ref_xml->get_widget ("radio-tooltb-shoutcast"))));

      m_actions->get_action (RADIO_ACTION_SHOW_ICECAST)->connect_proxy
            (*(dynamic_cast<ToggleToolButton *>(m_ref_xml->get_widget ("radio-tooltb-icecast"))));

      m_ui_manager->insert_action_group (m_actions);


      on_set_notebook_page ();
    }

    void
    Radio::on_set_notebook_page ()
    {
      int page = RefPtr<Gtk::RadioAction>::cast_static (m_actions->get_action (RADIO_ACTION_SHOW_SHOUTCAST))->get_current_value();
      m_notebook_radio->set_current_page (page);

      RadioDirectory::ViewBase * p = (page == PAGE_SHOUTCAST) ? m_shoutcast_list : m_icecast_list;
      p->set_filter (m_filter_entry->get_text());

      if( p->get_selection ()->count_selected_rows() ) 
            m_caps = Caps (m_caps |  PlaybackSource::CAN_PLAY);
      else
            m_caps = Caps (m_caps & ~PlaybackSource::CAN_PLAY);
      mSignalCaps.emit (m_caps);
    }

    void
    Radio::on_update_list ()
    {
      if( m_notebook_radio->get_current_page() == 1)
      {
        m_notebook_icecast->set_current_page(1);
        m_icecast_list->refresh();
      }
    }

    void
    Radio::play_uri (ustring const& uri)
    {
      Bmp::URI u (uri);
      Bmp::URI::Protocol p = u.get_protocol();

      if( p == URI::PROTOCOL_MMS || p == URI::PROTOCOL_MMSU || p == URI::PROTOCOL_MMST )
      {
            m_current_uri   = uri; 
            m_current_name  = ustring();
            mSignalPlayRequest.emit ();
            return;
      }

      if( p == URI::PROTOCOL_HTTP )
      {
            if( Audio::is_audio_file (uri) )
            {
                  m_current_uri = uri; 
            }
            else
            {
                  VFS::Handle handle = VFS::Handle (uri);
                  VUri list;

                  try{
                          vfs->read (handle, list);
                    }
                  catch (VFS::Exception & cxe)
                    { 
                          return;
                    }

                  if( list.empty() )
                          m_current_uri = uri; 
                  else
                          m_current_uri = list[0];
            }

            m_current_name  = ustring();
            mSignalPlayRequest.emit ();
      }
    }

    void
    Radio::on_row_activated (Gtk::TreeModel::Path const& path,
                             Gtk::TreeViewColumn       * column)
    {
      m_current_uri = ustring ();
      mSignalPlayRequest.emit ();
    }

    void
    Radio::on_filter_changed ()
    {
      RadioDirectory::ViewBase * p = (m_notebook_radio->get_current_page() == PAGE_SHOUTCAST) ? m_shoutcast_list : m_icecast_list;
      p->set_filter (m_filter_entry->get_text());
    }

    void
    Radio::on_selection_changed (RadioDirectory::ViewBase * view)
    {
      if( view->get_selection ()->count_selected_rows() == 1 )
            m_caps = Caps (m_caps |  PlaybackSource::CAN_PLAY);
      else
            m_caps = Caps (m_caps & ~PlaybackSource::CAN_PLAY);
      mSignalCaps.emit (m_caps);
    }

    void
    Radio::on_icecast_list_updated ()
    {
      m_icecast_list->set_filter (m_filter_entry->get_text());
      m_notebook_icecast->set_current_page (0);
    }

    void
    Radio::on_shoutcast_list_updated (RadioDirectory::StreamListT const& list)
    {
      m_shoutcast_list->set_stream_list (list);
      m_shoutcast_list->set_filter (m_filter_entry->get_text());
      m_shoutcast_base->queue_draw ();
      m_shoutcast_base->set_sensitive (1);
      m_notebook_shoutcast->set_current_page (0);
    }

    // PlaybackSource 
    ustring
    Radio::get_uri ()
    {
      return m_current_uri;
    }

    bool
    Radio::go_next ()
    {
      return false;
    }

    bool
    Radio::go_prev ()
    {
      return false;
    }

    void
    Radio::stop ()
    {
      if ( !m_shoutcast_list->get_selection()->count_selected_rows() && !m_icecast_list->get_selection()->count_selected_rows())
      {
        m_caps = Caps (m_caps & ~PlaybackSource::CAN_PLAY);
      }

      m_current_uri = ustring();
      m_current_name = ustring();
      m_caps = Caps (m_caps & ~PlaybackSource::CAN_PAUSE);
      mSignalCaps.emit (m_caps);
    }

    bool
    Radio::play ()
    {
      if( m_current_uri.empty() )
      {
        int page = m_notebook_radio->get_current_page ();
        if( page == PAGE_SHOUTCAST )
        {
              ustring uri;
              m_shoutcast_list->get (m_current_name, uri);

              VFS::Handle handle = VFS::Handle (uri);
              VUri list;

              try{
                      vfs->read (handle, list);
                }
              catch (VFS::Exception & cxe)
                { 
                      return false; 
                }

              m_current_uri = list[0]; //FIXME: We would want to get the other URIs listed as well..
        }

        if( page == PAGE_ICECAST )
        {
              m_icecast_list->get (m_current_name, m_current_uri);
        }
      }

      return true;
    }

    void
    Radio::play_post ()
    {
      TrackMetadata metadata;
      metadata.artist = m_current_name; 
      metadata.title  = m_current_uri;
      mSignalMetadata.emit (metadata);
      m_caps = Caps (m_caps | PlaybackSource::CAN_PAUSE);
      m_caps = Caps (m_caps | PlaybackSource::CAN_BOOKMARK);
    }

    void
    Radio::restore_context ()
    {
    }

    guint
    Radio::add_ui ()
    {
      return m_ui_manager->add_ui_from_string (ui_string_radio); 
    }

    // BookmarkHandler
    bool 
    Radio::get_bookmark (ustring const& id, /* the id to be used as the hostname part, but otherwise ignored */
                  ustring & url,
                  ustring & title)
    {
      static boost::format url_f ("ibs://%s/?streamurl=%s&title=%s");
  
      if( m_current_uri.empty() )
        return false;

      url = (url_f % id % m_current_uri % Bmp::URI::escape_string (m_current_name)).str();
      title = m_current_name;

      return true;
    }

    bool 
    Radio::set_bookmark (ustring const& url)
    {
      Bmp::URI u (url);
      Bmp::URI::Query q;
      u.parse_query (q);
    
      Bmp::URI::Query::iterator i = q.find ("streamurl");
      if( i != q.end() )
      {
        m_current_name = Bmp::URI::unescape_string (q.find ("title")->second.second);
        m_current_uri = i->second.second;
        mSignalPlayRequest.emit ();
        return true;
      }
      return false;
    }

  } // UiPart
} // Bmp
