//-*- Mode: C++; indent-tabs-mode: nil; -*-

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

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

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

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <iostream>
#include <fstream>
#include <vector>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <strings.h>

#include <boost/format.hpp>
#include <boost/regex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/regex.hpp>

#include "core.hh"

#include "main.hh"
#include "paths.hh"
#include "stock.hh"
#include "util.hh"

#include "lastfm.hh"
#include "lastfm-recommend-dialog.hh"

using namespace Gtk;
using namespace Glib;
using namespace Markup;
using namespace std;
using namespace Bmp;
using namespace LastFM;
using namespace LastFM::XMLRPC;
using namespace LastFM::WS;
using boost::algorithm::trim;
using boost::algorithm::split;
using boost::algorithm::split_regex;
using boost::algorithm::is_any_of;
using boost::algorithm::find_nth;
using boost::iterator_range;

namespace
{
  enum RecommendSelect
  {
    R_TRACK,
    R_ARTIST,
    R_ALBUM
  };
}

namespace Bmp
{
  namespace LastFM
  {
      RecommendDialog*
      RecommendDialog::create ()
      {
        const std::string path (build_filename (BMP_GLADE_DIR, "dialog-lastfm-recommend.glade"));
        RefPtr<Gnome::Glade::Xml> glade_xml = Gnome::Glade::Xml::create (path);
        RecommendDialog *i = 0;
        glade_xml->get_widget_derived ("recommend", i);
        return i;
      }

      RecommendDialog::~RecommendDialog ()
      {}

      RecommendDialog::RecommendDialog (BaseObjectType*                  obj,
                                        RefPtr<Gnome::Glade::Xml> const& xml)
      : Gtk::Dialog (obj)
      , m_ref_xml   (xml)
      {
        dynamic_cast<Image*>(m_ref_xml->get_widget ("image"))->set (build_filename (BMP_IMAGE_DIR, BMP_THROBBER));
        dynamic_cast<Image*>(m_ref_xml->get_widget ("image_lastfm"))->set (Gtk::StockID (BMP_STOCK_LASTFM), Gtk::ICON_SIZE_SMALL_TOOLBAR);

        m_ref_xml->get_widget ("e_artist", e_artist);
        m_ref_xml->get_widget ("e_album",  e_album);
        m_ref_xml->get_widget ("e_title",  e_title);
        m_ref_xml->get_widget ("l_artist", l_artist);
        m_ref_xml->get_widget ("l_album",  l_album);
        m_ref_xml->get_widget ("l_title",  l_title);

        m_ref_xml->get_widget ("recommend-cbox",  m_recommend_cbox);
        m_ref_xml->get_widget ("notes-view",  m_notes_view);
        m_ref_xml->get_widget ("notebook", m_notebook);
        m_ref_xml->get_widget ("view", m_view);

        Gtk::CellRendererPixbuf *cell_pixbuf = Gtk::manage (new Gtk::CellRendererPixbuf ());
        cell_pixbuf->property_ypad () = 3;
        cell_pixbuf->property_xpad () = 3;
        m_view->append_column (_("Avatar"), *cell_pixbuf);
        m_view->get_column (0)->add_attribute (*cell_pixbuf, "pixbuf", 0);
        m_view->get_column (0)->set_resizable (false);

        Gtk::CellRendererText *cell_text = Gtk::manage (new Gtk::CellRendererText ());
        cell_text->property_yalign() = 0.5;
        m_view->append_column (_("Name"), *cell_text);
        m_view->get_column (1)->add_attribute (*cell_text, "markup", 1);
        m_view->get_column (1)->set_resizable (false);

        m_notebook->set_current_page (0);
        m_recommend_cbox->signal_changed().connect
          (sigc::mem_fun (*this, &LastFM::RecommendDialog::recommend_changed));
      }

      void
      RecommendDialog::run (TrackMetadata const& item)
      {
        m_item = item;  

        if (m_item.artist)
        {
          trim (m_item.artist.get());
          e_artist->set_text (m_item.artist.get());
        }

        if (m_item.album)
        {
          trim (m_item.album.get());
          e_album->set_text (m_item.album.get());
        }
  
        if (m_item.artist)
        {
          trim (m_item.artist.get());
          e_title->set_text (m_item.artist.get());
        }

        if ((!m_item.album) || (m_item.album && m_item.album.get().empty()))
        {
          // Q&D
          Glib::RefPtr<TreeModel> model = m_recommend_cbox->get_model();
          TreePath path (TreePath::size_type (1), TreePath::value_type (2));
          gtk_list_store_remove ((GtkListStore*)(model->gobj()), const_cast<GtkTreeIter*>(model->get_iter (path)->gobj())); 
        }

        show ();
        update_view ();
        if (Dialog::run() == Gtk::RESPONSE_OK)
          {
            try {
                recommend ();
              }
            catch (LastFM::Exception& cxe)
              {
                MessageDialog dialog (cxe.what(), false,
                  MESSAGE_ERROR, BUTTONS_OK, true);
                dialog.run ();
              }
          }
        m_notes_view->get_buffer()->set_text("");
        hide ();
      }

      void
      RecommendDialog::recommend_changed ()
      {
        int current = m_recommend_cbox->get_active_row_number();

        e_artist->set_sensitive (false);
        e_album->set_sensitive (false);
        e_title->set_sensitive (false);
        l_artist->set_sensitive (false);
        l_album->set_sensitive (false);
        l_title->set_sensitive (false);

        // check whether album is empty; it's a possible case
        if (current == R_ALBUM)
        {
          set_response_sensitive (Gtk::RESPONSE_OK, bool (m_item.album)); 
        }

        switch (current)
        {
          case R_ARTIST:
          {
            e_artist->set_sensitive (true);
            l_artist->set_sensitive (true);
            break;
          }

          case R_ALBUM:
          {
            e_artist->set_sensitive (true);
            l_artist->set_sensitive (true);
            e_album->set_sensitive (true);
            l_album->set_sensitive (true);
            break;
          }

          case R_TRACK:
          {
            e_artist->set_sensitive (true);
            l_artist->set_sensitive (true);
            e_title->set_sensitive (true);
            l_title->set_sensitive (true);
            break;
          }
        }
      }

      void
      RecommendDialog::update_view ()
      {
        m_notebook->set_current_page (1);

        m_store = ListStore::create (cr);
        m_store->set_default_sort_func (sigc::mem_fun (*this, &LastFM::RecommendDialog::sort_func));
        m_store->set_sort_column (Gtk::TreeSortable::DEFAULT_SORT_COLUMN_ID, Gtk::SORT_ASCENDING);
        m_view->set_model (m_store);

        UserV x;
        users (UT_F, mcs->key_get<std::string>("lastfm", "username"), x);

        for (UserV::const_iterator i = x.begin (); i != x.end(); ++i)
        {
            User const& x (*i);
            TreeModel::iterator m_iter = m_store->append();
            (*m_iter)[cr.name] = ((boost::format ("%s") % x.username.c_str()).str());
            (*m_iter)[cr.username] = x.username;
            RefPtr<Gdk::Pixbuf> image = Util::get_image_from_uri (x.image);
            if (image)
            {
              (*m_iter)[cr.avatar] = image->scale_simple (32, 32, Gdk::INTERP_BILINEAR);
            }
            while (gtk_events_pending()) gtk_main_iteration();
        }
        m_recommend_cbox->set_active (0);
        m_notebook->set_current_page (0);
      }

      int
      RecommendDialog::sort_func (Gtk::TreeModel::iterator const& m_iter1,
                                  Gtk::TreeModel::iterator const& m_iter2)
      {
        ustring name1 ((*m_iter1)[cr.username]);
        ustring name2 ((*m_iter2)[cr.username]);

        return name1.compare (name2);
      }

      void
      RecommendDialog::recommend ()
      {
        using namespace Bmp::LastFM::XMLRPC;

        std::string artist, album, title;

        artist  =   (m_item.artist    ?   m_item.artist.get()   : std::string());
        album   =   (m_item.album     ?   m_item.album.get()    : std::string());
        title   =   (m_item.title     ?   m_item.title.get()    : std::string());

        ustring user ((*m_view->get_selection()->get_selected())[cr.username]);
        RecommendAction action (RecommendAction::RecommendItem (m_recommend_cbox->get_active_row_number()),
                                artist, album, title, user, m_notes_view->get_buffer()->get_text (false));
                                
        action.run ();
      }
  }
}
