/*
 * unity-webapps-music-player-context.c
 * Copyright (C) Canonical LTD 2011
 *
 * Author: Robert Carr <racarr@canonical.com>
 * 
 unity-webapps is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * unity-webapps 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 Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.";
 */

#include <stdio.h>

#include "unity-webapps-music-player-context.h"

#include "unity-webapps-context-private.h"

#include "unity-webapps-sanitizer.h"

#include "unity-webapps-dbus-util.h"
#include "unity-webapps-rate.h"

#include "unity-webapps-debug.h"

UnityWebappsMusicPlayerContext *
unity_webapps_music_player_context_new (UnityWebappsContext *main_context, GError **error)
{
  UnityWebappsMusicPlayerContext *context;
  
  context = g_malloc0 (sizeof (UnityWebappsMusicPlayerContext));
  context->music_player_rate = 0;
  
  context->music_player_proxy = 
    unity_webapps_gen_music_player_proxy_new_sync (unity_webapps_service_get_connection (main_context->priv->service) ,
						   G_DBUS_PROXY_FLAGS_NONE,
						   main_context->priv->context_name,
						   UNITY_WEBAPPS_MUSIC_PLAYER_PATH, 
						   NULL /* Cancellable */,
						   error);
  
  if (error && (*error != NULL))
    {
      g_critical ("Error creating music_player context proxy object for %s: %s", main_context->priv->context_name, (*error)->message);
      
      return NULL;
    }
  
  return context;
}

void 
unity_webapps_music_player_context_free (UnityWebappsMusicPlayerContext *context)
{
  g_return_if_fail (context != NULL);

  g_object_unref (G_OBJECT (context->music_player_proxy));
  
  g_free (context);
}



// TODO: NOTE: REMOVE IN NEXT RELEASE
void
unity_webapps_music_player_init (UnityWebappsContext *context,
				 const gchar *title)
{
  return;
}

UNITY_WEBAPPS_DEFINE_VOID_DBUS_HANDLER(set_playlists,music_player,MusicPlayer,MUSIC_PLAYER,"Playlists succesfully set");

#define MAXIMUM_PLAYLIST_LENGTH 60
#define MAXIMUM_PLAYLIST_LIST_LENGTH 20

void
unity_webapps_music_player_set_playlists (UnityWebappsContext *context,
					  const gchar *const *playlists)
{
  gchar **sanitized_playlists;
  
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));
  
  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  sanitized_playlists = unity_webapps_sanitizer_limit_strv_argument (playlists,
								     MAXIMUM_PLAYLIST_LIST_LENGTH,
								     MAXIMUM_PLAYLIST_LENGTH);
  unity_webapps_gen_music_player_call_set_playlists (context->priv->music_player_context->music_player_proxy,
						     (const gchar *const *)sanitized_playlists,
						     NULL /* Cancellable */,
						     set_playlists_complete_callback,
						     context);

  g_strfreev (sanitized_playlists);
  
  UNITY_WEBAPPS_NOTE (MUSIC_PLAYER, "Setting playlists");  
}

UNITY_WEBAPPS_DEFINE_VOID_DBUS_HANDLER(set_track,music_player,MusicPlayer,MUSIC_PLAYER,"Track succesfully set");


#define MAXIMUM_ARTIST_LENGTH 60
#define MAXIMUM_ALBUM_LENGTH 60
#define MAXIMUM_TITLE_LENGTH 60
#define MAXIMUM_ICON_URL_LENGTH 4096 /* For large data URIs...this seems reasonable */

void 
unity_webapps_music_player_set_track (UnityWebappsContext *context,
				      const gchar *artist,
				      const gchar *album,
				      const gchar *title,
				      const gchar *icon_url)
{
  gchar *sanitized_artist, *sanitized_album, *sanitized_title, *sanitized_icon_url;
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));
  g_return_if_fail (title != NULL);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  
  sanitized_artist = unity_webapps_sanitizer_limit_string_argument (artist, MAXIMUM_ARTIST_LENGTH);
  sanitized_album = unity_webapps_sanitizer_limit_string_argument (album, MAXIMUM_ALBUM_LENGTH);
  sanitized_title = unity_webapps_sanitizer_limit_string_argument (title, MAXIMUM_TITLE_LENGTH);
  sanitized_icon_url = unity_webapps_sanitizer_limit_string_argument (icon_url, MAXIMUM_ICON_URL_LENGTH);
  
  unity_webapps_gen_music_player_call_set_track (context->priv->music_player_context->music_player_proxy,
						 sanitized_artist, 
						 sanitized_album,
						 sanitized_title,
						 sanitized_icon_url,
						 context->priv->interest_id,
						 NULL /* Cancellable */,
						 set_track_complete_callback,
						 context);
  
  g_free (sanitized_artist);
  g_free (sanitized_album);
  g_free (sanitized_title);
  g_free (sanitized_icon_url);
  
  UNITY_WEBAPPS_NOTE (MUSIC_PLAYER, "Setting track: %s by %s from %s", title, artist, album);
}

static void
_free_callback_data (gpointer user_data,
		     GClosure *closure)
{
  g_free (user_data);
}

typedef struct _unity_webapps_music_player_playlist_callback_data {
  UnityWebappsContext *context;
  UnityWebappsMusicPlayerPlaylistCallback callback;
  gpointer user_data;
} unity_webapps_music_player_playlist_callback_data;

static void
_do_playlist_callback (UnityWebappsGenMusicPlayer *player,
		       const gchar *playlist_name,
		       gpointer user_data)
{
  unity_webapps_music_player_playlist_callback_data *data;
  
  data = (unity_webapps_music_player_playlist_callback_data *)user_data;
  g_return_if_fail(data != NULL);

  g_return_if_fail(data->context != NULL);
  if (!G_IS_OBJECT(data->context))
    return;

  if (data->callback != NULL)
    {
      data->callback (data->context, playlist_name, data->user_data);
    }
}


void 
unity_webapps_music_player_on_playlist_activated_callback (UnityWebappsContext *context,
							   UnityWebappsMusicPlayerPlaylistCallback callback,
							   gpointer user_data)
{
  unity_webapps_music_player_playlist_callback_data *data;
  
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));
  g_return_if_fail (callback != NULL);
  
  if (context->priv->remote_ready == FALSE)
    {
      return;
    }
  if (callback == NULL)
  {
    return;
  }
  
  data = g_malloc0 (sizeof (unity_webapps_music_player_playlist_callback_data));
  data->context = context;
  data->callback = callback;
  data->user_data = user_data;
  
  g_signal_connect_data (context->priv->music_player_context->music_player_proxy, "playlist-activated",
			 G_CALLBACK (_do_playlist_callback), data,
			 _free_callback_data, 0);
}



typedef struct _unity_webapps_music_player_callback_data {
  UnityWebappsContext *context;
  UnityWebappsMusicPlayerCallback callback;
  gpointer user_data;
} unity_webapps_music_player_callback_data;


static void
_do_callback (UnityWebappsGenMusicPlayer *player, gpointer user_data)
{
  unity_webapps_music_player_callback_data *data;

  data = (unity_webapps_music_player_callback_data *)user_data;
  g_return_if_fail(data != NULL);

  g_return_if_fail(data->context != NULL);
  if (!G_IS_OBJECT(data->context))
    return;

  if (unity_webapps_context_get_focus_interest (data->context) != data->context->priv->interest_id)
    return;

  if (data->callback != NULL)
    {
      data->callback (data->context, data->user_data);
    }
}

void 
unity_webapps_music_player_on_play_pause_callback (UnityWebappsContext *context, 
						   UnityWebappsMusicPlayerCallback callback,
						   gpointer user_data)
{
  unity_webapps_music_player_callback_data *data;

  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));
  g_return_if_fail (callback != NULL);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  
  g_return_if_fail (callback != NULL);
  
  data = g_malloc0 (sizeof (unity_webapps_music_player_callback_data));
  data->context = context;
  data->callback = callback;
  data->user_data = user_data;

  g_signal_handlers_disconnect_matched (context->priv->music_player_context->music_player_proxy,
					G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
					g_signal_lookup ("play_pause", UNITY_WEBAPPS_GEN_TYPE_MUSIC_PLAYER),
					0, NULL, G_CALLBACK (_do_callback), NULL);
  g_signal_connect_data (context->priv->music_player_context->music_player_proxy,
			 "play_pause", G_CALLBACK (_do_callback),
			 data, _free_callback_data, 0);
}

void 
unity_webapps_music_player_on_previous_callback (UnityWebappsContext *context, 
						 UnityWebappsMusicPlayerCallback callback, 
						 gpointer user_data)
{
  unity_webapps_music_player_callback_data *data;

  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));
  g_return_if_fail (callback != NULL);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_return_if_fail (callback != NULL);

  data = g_malloc0 (sizeof (unity_webapps_music_player_callback_data));
  data->context = context;
  data->callback = callback;
  data->user_data = user_data;

  g_signal_handlers_disconnect_matched (context->priv->music_player_context->music_player_proxy,
					G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
					g_signal_lookup ("previous", UNITY_WEBAPPS_GEN_TYPE_MUSIC_PLAYER),
					0, NULL, G_CALLBACK (_do_callback), NULL);
  g_signal_connect_data (context->priv->music_player_context->music_player_proxy, "previous", G_CALLBACK (_do_callback), data, _free_callback_data, 0);
}
void 
unity_webapps_music_player_on_next_callback (UnityWebappsContext *context, 
					     UnityWebappsMusicPlayerCallback callback,
					     gpointer user_data)
{
  unity_webapps_music_player_callback_data *data;

  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));
  g_return_if_fail (callback != NULL);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_return_if_fail (callback != NULL);

  data = g_malloc0 (sizeof (unity_webapps_music_player_callback_data));
  data->context = context;
  data->callback = callback;
  data->user_data = user_data;

  g_signal_handlers_disconnect_matched (context->priv->music_player_context->music_player_proxy,
					G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC,
					g_signal_lookup ("next", UNITY_WEBAPPS_GEN_TYPE_MUSIC_PLAYER),
					0, NULL, G_CALLBACK (_do_callback), NULL);

  g_signal_connect_data (context->priv->music_player_context->music_player_proxy,
			 "next", G_CALLBACK (_do_callback), data, _free_callback_data, 0);
}

UnityWebappsMusicPlayerPlaybackState
unity_webapps_music_player_get_playback_state (UnityWebappsContext *context)
{
  g_return_val_if_fail (context != NULL, 0);
  g_return_val_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context), 0);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return FALSE;
    }

  gint state;
  unity_webapps_gen_music_player_call_get_playback_state_sync (context->priv->music_player_context->music_player_proxy,
							       context->priv->interest_id, &state, NULL, NULL);
  return (UnityWebappsMusicPlayerPlaybackState)state;
}

gboolean
unity_webapps_music_player_get_can_go_previous (UnityWebappsContext *context)
{
  g_return_val_if_fail (context != NULL, FALSE);
  g_return_val_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context), FALSE);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return FALSE;
    }
  gboolean can_go_previous;
  unity_webapps_gen_music_player_call_get_can_go_previous_sync (context->priv->music_player_context->music_player_proxy,
								context->priv->interest_id, &can_go_previous, NULL, NULL);
  return can_go_previous;
}

gboolean
unity_webapps_music_player_get_can_go_next (UnityWebappsContext *context)
{  
  g_return_val_if_fail (context != NULL, FALSE);
  g_return_val_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context), FALSE);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return FALSE;
    }
  gboolean can_go_next;
  unity_webapps_gen_music_player_call_get_can_go_next_sync (context->priv->music_player_context->music_player_proxy,
							    context->priv->interest_id, &can_go_next, NULL, NULL);
  return can_go_next;
}

gboolean
unity_webapps_music_player_get_can_play (UnityWebappsContext *context)
{
  g_return_val_if_fail (context != NULL, FALSE);
  g_return_val_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context), FALSE);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return FALSE;
    }
  gboolean can_play;
  unity_webapps_gen_music_player_call_get_can_play_sync (context->priv->music_player_context->music_player_proxy,
							 context->priv->interest_id, &can_play, NULL, NULL);
  return can_play;
}

gboolean
unity_webapps_music_player_get_can_pause (UnityWebappsContext *context)
{
  g_return_val_if_fail (context != NULL, FALSE);
  g_return_val_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context), FALSE);

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return FALSE;
    }
  gboolean can_pause;
  unity_webapps_gen_music_player_call_get_can_pause_sync (context->priv->music_player_context->music_player_proxy,
							  context->priv->interest_id, &can_pause, NULL, NULL);
  return can_pause;
}

void 
unity_webapps_music_player_set_playback_state (UnityWebappsContext *context, UnityWebappsMusicPlayerPlaybackState state)
{
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (context->priv->music_player_context->music_player_proxy), 
				    "PlaybackState",
				    g_variant_new("i",
						  state,
						  NULL));
  unity_webapps_gen_music_player_call_set_playback_state_sync (context->priv->music_player_context->music_player_proxy,
							       context->priv->interest_id,
							       (guint) state, NULL, NULL);
}

void
unity_webapps_music_player_set_can_go_previous (UnityWebappsContext *context, gboolean can_go_previous)
{
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (context->priv->music_player_context->music_player_proxy), 
				    "CanGoPrevious",
				    g_variant_new("b",
						  can_go_previous,
						  NULL));
  unity_webapps_gen_music_player_call_set_can_go_previous_sync (context->priv->music_player_context->music_player_proxy, context->priv->interest_id, can_go_previous, NULL, NULL);
}

void
unity_webapps_music_player_set_can_go_next (UnityWebappsContext *context, gboolean can_go_next)
{
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (context->priv->music_player_context->music_player_proxy), 
				    "CanGoNext",
				    g_variant_new("b",
						  can_go_next,
						  NULL));
  unity_webapps_gen_music_player_call_set_can_go_next_sync (context->priv->music_player_context->music_player_proxy,
							    context->priv->interest_id,
							    can_go_next, NULL, NULL);
}

void
unity_webapps_music_player_set_can_play (UnityWebappsContext *context, gboolean can_play)
{
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (context->priv->music_player_context->music_player_proxy), 
				    "CanPlay",
				    g_variant_new("b",
						  can_play,
						  NULL));
  unity_webapps_gen_music_player_call_set_can_play_sync (context->priv->music_player_context->music_player_proxy,
							 context->priv->interest_id,
							 can_play, NULL, NULL);
}

void
unity_webapps_music_player_set_can_pause (UnityWebappsContext *context, gboolean can_pause)
{
  g_return_if_fail (context != NULL);
  g_return_if_fail (UNITY_WEBAPPS_IS_CONTEXT (context));

  if (unity_webapps_rate_check_music_player_rate_limit (context) == FALSE)
    {
      return;
    }
  g_dbus_proxy_set_cached_property (G_DBUS_PROXY (context->priv->music_player_context->music_player_proxy), 
				    "CanPause",
				    g_variant_new("b",
						  can_pause,
						  NULL));
  unity_webapps_gen_music_player_call_set_can_pause_sync (context->priv->music_player_context->music_player_proxy,
							  context->priv->interest_id,
							  can_pause, NULL, NULL);
}
