//  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 Version 2
//  as published by the Free Software Foundation.
//
//  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.

#ifndef BMP_UI_PART_LASTFM_HH
#define BMP_UI_PART_LASTFM_HH

#include <glibmm/ustring.h>
#include <gdkmm/pixbuf.h>
#include <gtkmm.h>
#include <libglademm/xml.h>
#include <sigc++/signal.h>

#include <boost/optional.hpp>
#include <boost/format.hpp>

#include "playbacksource.hh"
#include "ui-part-base.hh"
#include "urihandler.hh"

#include "lastfm.hh"
#include "bmp/types/types-xspf.hh"

#include "lastfm-extra-widgets.hh"

using namespace Gtk;
using namespace Glib;
using namespace Bmp::LastFM;
using namespace Bmp::LastFM::WS;

#define LASTFM_ACTION_BAN           "lastfm-action-ban"
#define LASTFM_ACTION_UPDATE_LIST   "lastfm-action-update-list"
#define LASTFM_ACTION_MATCH_TAGS    "lastfm-action-match-tags"
#define LASTFM_ACTION_DISCOVERY     "lastfm-action-discovery-mode"

namespace Bmp
{
  typedef RefPtr<TextBuffer> RefTextBuffer;

  namespace UiPart
  {
    class LASTFM

      : public  PlaybackSource
      , public  Base
      , public  UriHandler
    {

      public:

        LASTFM (RefPtr<Gnome::Glade::Xml> const& xml, RefPtr<UIManager> ui_manager);
        virtual ~LASTFM ();

        void disable_ban (); // FIXME: UGLINESS

      protected:

        // UriHandler
        virtual StrV  
        get_schemes ();

        virtual void
        process (VUri const&);
    
        // PlaybackSource
        virtual void
        play_async ();
      
        virtual void
        go_next_async ();

        virtual void
        stop ();


        virtual void
        play_post ();

        virtual void
        next_post ();

        virtual void
        prev_post ();


        virtual void
        restore_context ();
    

        virtual void
        skipped ();

        virtual void
        segment ();


        // UiPartBase
        virtual guint
        add_ui ();

        virtual guint
        add_context_ui ();

        virtual guint
        add_tray_ui ();


        virtual ustring
        get_uri ();

        virtual ustring
        get_type ();

     private:

        enum IdType
        {
          ID_TAG,
          ID_ARTIST,
          ID_AUTO,
        };

        class TagInfoViewT
          : public TreeView
        {
          public:

            TagInfoViewT (BaseObjectType*                  obj,
                      RefPtr<Gnome::Glade::Xml> const& xml);
            virtual ~TagInfoViewT () {};

            void
            set_ui_manager (RefPtr<Gtk::UIManager> const &ui_manager);

            void
            clear ();

            void
            idSetAuto (ustring const& id);
        
            void
            idSet (IdType type, ustring const& id);

            bool
            isEmpty ();

          public:

            typedef sigc::signal<void, ustring const&> SignalString;

          private:

            struct SignalsT
            {
              SignalString ArtistActivated;
              SignalString GoToMBID;
            };

            SignalsT Signals;

          public:

            SignalString&
            signalArtistActivated()
            {
              return Signals.ArtistActivated;
            }

            SignalString&
            signalGoToMBID()
            {
              return Signals.GoToMBID;
            }

          private:                    

            class Columns
              : public TreeModel::ColumnRecord
            {
              public:

                TreeModelColumn< ::Cairo::RefPtr< ::Cairo::ImageSurface> > image;
                TreeModelColumn<LastFMArtist> artist; 
                TreeModelColumn<ustring>      info; 
                TreeModelColumn<bool>         hasAlbums; 

                Columns ()
                {
                  add (image);
                  add (artist);
                  add (info);
                  add (hasAlbums);
                }
            };

            Columns mColumns;
            RefPtr<ListStore> mStore;

            ::Cairo::RefPtr< ::Cairo::ImageSurface> mUnknownArtist;
            Notebook        * mNotebook;
            Entry           * mEntry;
            ComboBox        * mCbox;
            guint             mTopRank;
            sigc::connection  mProcessIdler;
            LastFMArtistV::iterator mIterator;
            TreeIter          mTreeIterator;
            LastFMArtistV     mArtists;
            Glib::Mutex       mDisplayLock;
            bool              mEndDisplay;
            ::Cairo::RefPtr< ::Cairo::ImageSurface > mImage;
            LastFMArtist      mArtist;
            Soup::RequestRefP mArtistReq;

            bool
            on_event_cb (GdkEvent*);

            bool
            idler ();

            void
            cellDataFunc (CellRenderer* cell, TreeIter const& m_iter, int column);

            void
            displayThread ();

            void
            showArtist ();

            void  
            data_cb (char const * data, guint size, guint code);

            void
            on_selection_changed ();

            void
            on_view_in_library ();

            void
            on_play_lastfm ();

            Glib::RefPtr<Gtk::UIManager> m_ui_manager;
            Glib::RefPtr<Gtk::ActionGroup> m_actions;
        };

        class ProfileViewT
          : public TreeView
        {
          public:

            typedef sigc::signal<void, ustring const&> StationActivated;

          private:

            StationActivated
            station_activated_;

          public:

            ProfileViewT (BaseObjectType*                  obj,
                          RefPtr<Gnome::Glade::Xml> const& xml);
            virtual ~ProfileViewT ();

            StationActivated&
            station_activated ()
            {
              return station_activated_;
            }

            void user_set (ustring const& user, bool subscriber, bool match_tags);
            void user_clear ();

          protected:

            virtual void on_row_activated (TreePath const& path,
                                           TreeViewColumn* column);

          private:

            void  user_get_match_tags_tags (std::string const& username);
            void  user_set_match_tags ();
            void  cell_data_func (CellRenderer* cell, TreeIter const& m_iter);

            enum RowType
            {
              ROW_MAINUSER,
              ROW_SYSREC_ROOT,
              ROW_ARTIST,
              ROW_URL,
              ROW_NEIGHBOUR_ROOT,
              ROW_NEIGHBOUR,
              ROW_FRIEND_ROOT,
              ROW_FRIEND,
              ROW_TAG_ROOT,
              ROW_TAG,
            };

            class Columns
              : public TreeModel::ColumnRecord
            {
              public:

                TreeModelColumn<ustring>  name;
                TreeModelColumn<ustring>  station;
                TreeModelColumn<RowType>  type;
                TreeModelColumn<ustring>  score;

                Columns ()
                {
                  add (name);
                  add (station);
                  add (type);
                  add (score);
                }
            };
            Columns columns;

            Notebook              * m_notebook;
            Notebook              * m_notebook_tags;

            RefPtr<Gdk::Pixbuf>     m_pb_artist;
            RefPtr<Gdk::Pixbuf>     m_pb_rec;
            RefPtr<Gdk::Pixbuf>     m_pb_url;
            RefPtr<Gdk::Pixbuf>     m_pb_neighbour;
            RefPtr<Gdk::Pixbuf>     m_pb_friend;
            RefPtr<Gdk::Pixbuf>     m_pb_tag;
            RefPtr<Gdk::Pixbuf>     m_pb_user;
            RefPtr<Gdk::Pixbuf>     m_pb_mainuser;

            RefPtr<TreeStore>       m_store;
  
            enum RootIter          
            {
              R_STATIONS,
              R_NEIGHBOURS,
              R_FRIENDS,
              R_MATCHTAGS,
              R_USERTAGS,
        
              R_MAX
            };

            void request_cb (char const* data, guint size, guint status_code, RootIter iter);
    
            Soup::RequestRefP   m_request[R_MAX];
            TreeIter            m_iroot[R_MAX]; 
            RankedTagV          m_match_tags;
            Dispatcher          disp;
        };

        void  play_uri (ustring const& uri);

        //// Action Callbacks
        void  on_ban ();
        void  on_update_list (bool match_tags);

        void  on_tuned ();
        void  on_tune_error (Glib::ustring const&);

        void  on_playlist (XSPF::Playlist const&);
        void  on_no_playlist ();

        void  on_radio_connected ();
        void  on_radio_disconnected ();
        void  on_play_http_status (int status);

        void  get_track_tags ();
        void  got_track_tags (TagV const& tags);
        void  display_tags_limited ();
        void  display_tag_artists (ustring const& tag);
        void  display_tag_artists_clear ();
        void  display_tag_artists_activated (ustring const& url);

        void  clear_metadata_info ();
        void  start_playback ();

        struct StateDataT
        {
          TagV            Tags;
          TagsGlobReqRefP TagsReq;
          XSPF::Playlist  Playlist;
          XSPF::ItemIter  Iter;
          Glib::ustring   Uri;

          StateDataT ()
          : Iter (Playlist.Items.begin())
          {} 
        };

        StateDataT StateData;

        sigc::connection    PlayConnection;

      public:

        RefTextBuffer TagBuffer; 

        struct WidgetsT
        {
          LastFmTagView * TagView;
          HScale        * TagLimiter; 
          Label         * Station;
          Entry         * StationEntry;
          ComboBox      * StationChoice;
          ProfileViewT  * ProfileView;
          TagInfoViewT  * TagInfoView;
        };

        WidgetsT Widgets;

    }; // class LASTFM
  } // namespace UiPart
} // namespace Bmp

#endif // !BMP_UI_PART_LASTFM_HH

