package com.peterjosling.scroball;

import android.content.ComponentName;
import android.content.Context;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.media.MediaMetadata;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.media.session.PlaybackState;
import android.net.ConnectivityManager;
import android.service.notification.NotificationListenerService;
import android.support.annotation.NonNull;
import android.support.v4.app.NotificationManagerCompat;
import android.util.Log;

import com.google.common.collect.Sets;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;

public class ListenerService extends NotificationListenerService
    implements MediaSessionManager.OnActiveSessionsChangedListener {

  private List<MediaController> mediaControllers = new ArrayList<>();
  private Map<MediaController, MediaController.Callback> controllerCallbacks = new WeakHashMap<>();
  private PlaybackTracker playbackTracker;
  private SharedPreferences sharedPreferences;

  @Override
  public void onCreate() {
    ScroballApplication application = (ScroballApplication) getApplication();
    sharedPreferences = application.getSharedPreferences();

    ConnectivityManager connectivityManager =
        (ConnectivityManager) this.getSystemService(Context.CONNECTIVITY_SERVICE);

    ScroballDB scroballDB = application.getScroballDB();

    ScrobbleNotificationManager scrobbleNotificationManager =
        new ScrobbleNotificationManager(this, sharedPreferences);

    LastfmClient lastfmClient = application.getLastfmClient();

    Scrobbler scrobbler = new Scrobbler(
        lastfmClient,
        scrobbleNotificationManager,
        scroballDB, connectivityManager);

    playbackTracker = new PlaybackTracker(
        scrobbleNotificationManager,
        scroballDB,
        connectivityManager,
        scrobbler);

    Log.d("Scroball", "NotificationListenerService started");

    MediaSessionManager mediaSessionManager = (MediaSessionManager) getApplicationContext()
        .getSystemService(Context.MEDIA_SESSION_SERVICE);

    ComponentName componentName = new ComponentName(this, this.getClass());
    mediaSessionManager.addOnActiveSessionsChangedListener(this, componentName);

    NetworkStateReceiver networkStateReceiver = new NetworkStateReceiver(scrobbler);
    IntentFilter filter = new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION);
    this.registerReceiver(networkStateReceiver, filter);

    // Trigger change event with existing set of sessions.
    List<MediaController> initialSessions = mediaSessionManager.getActiveSessions(componentName);
    onActiveSessionsChanged(initialSessions);

  }

  public static boolean isNotificationAccessEnabled(Context context) {
    return NotificationManagerCompat.getEnabledListenerPackages(context)
        .contains(context.getPackageName());
  }

  @Override
  public void onActiveSessionsChanged(List<MediaController> activeMediaControllers) {
    Log.d("Scroball", "Active MediaSessions changed");

    Set<MediaController> existingControllers = new HashSet<>(mediaControllers);
    Set<MediaController> newControllers = new HashSet<>(activeMediaControllers);

    Set<MediaController> toRemove = Sets.difference(existingControllers, newControllers);
    Set<MediaController> toAdd = Sets.difference(newControllers, existingControllers);

    for (MediaController controller : toRemove) {
      if (controllerCallbacks.containsKey(controller)) {
        controller.unregisterCallback(controllerCallbacks.get(controller));
        playbackTracker.handleSessionTermination(controller.getPackageName());
      }
    }

    for (final MediaController controller : toAdd) {
      String packageName = controller.getPackageName();
      String prefKey = "player." + packageName;

      if (!sharedPreferences.contains(prefKey)) {
        boolean defaultVal = sharedPreferences.getBoolean("scrobble_new_players", true);

        SharedPreferences.Editor editor = sharedPreferences.edit();
        editor.putBoolean(prefKey, defaultVal);
        editor.apply();
      }

      if (!sharedPreferences.getBoolean(prefKey, true)) {
        continue;
      }

      MediaController.Callback callback = new MediaController.Callback() {
        @Override
        public void onPlaybackStateChanged(@NonNull PlaybackState state) {
          controllerPlaybackStateChanged(controller, state);
        }

        @Override
        public void onMetadataChanged(MediaMetadata metadata) {
          controllerMetadataChanged(controller, metadata);
        }
      };

      controllerCallbacks.put(controller, callback);
      controller.registerCallback(callback);

      // Media may already be playing - update with current state.
      controllerPlaybackStateChanged(controller, controller.getPlaybackState());
      controllerMetadataChanged(controller, controller.getMetadata());
    }

    mediaControllers = activeMediaControllers;
  }

  private void controllerPlaybackStateChanged(MediaController controller, PlaybackState state) {
    playbackTracker.handlePlaybackStateChange(controller.getPackageName(), state);
  }

  private void controllerMetadataChanged(MediaController controller, MediaMetadata metadata) {
    playbackTracker.handleMetadataChange(controller.getPackageName(), metadata);
  }
}

@@ -912,16 +912,86 @@
 ener %7B%0A%0A
+  private static final String TAG = ListenerService.class.getName();%0A%0A
   privat
@@ -2103,28 +2103,21 @@
     Log.
-d(%22Scroball%22
+i(TAG
 , %22Notif
@@ -3205,64 +3205,8 @@
 ) %7B%0A
-    Log.d(%22Scroball%22, %22Active MediaSessions changed%22);%0A%0A
     
@@ -3273,32 +3273,81 @@
 iaControllers);%0A
+    Log.i(TAG, %22Active MediaSessions changed%22);%0A%0A
     Set%3CMediaCon
@@ -4384,25 +4384,174 @@
     
-continue;%0A      %7D
+Log.i(TAG, String.format(%22Ignoring player %25s%22, packageName));%0A        continue;%0A      %7D%0A%0A      Log.i(TAG, String.format(%22Listening for events from %25s%22, packageName));
 %0A%0A  

Fix ListenerService Log TAG, add more logging