package com.baseflow.geolocator;

import com.baseflow.geolocator.tasks.Task;
import com.baseflow.geolocator.tasks.TaskFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/**
 * GeolocatorPlugin
 */
public class GeolocatorPlugin implements MethodCallHandler, EventChannel.StreamHandler, OnCompletionListener {

  private static final String METHOD_CHANNEL_NAME = "flutter.baseflow.com/geolocator/methods";
  private static final String EVENT_CHANNEL_NAME = "flutter.baseflow.com/geolocator/events";

  @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
  // mTasks is used to track active tasks, when tasks completes it is removed from the map
  private final Map<UUID, Task> mTasks = new HashMap<>();
  private final Registrar mRegistrar;
  private Task mStreamLocationTask;

  private GeolocatorPlugin(PluginRegistry.Registrar registrar) {
    this.mRegistrar = registrar;
  }

  /**
   * Plugin registration.
   */
  public static void registerWith(Registrar registrar) {
    GeolocatorPlugin geolocatorPlugin = new GeolocatorPlugin(registrar);

    final MethodChannel methodChannel = new MethodChannel(registrar.messenger(), METHOD_CHANNEL_NAME);
    final EventChannel eventChannel = new EventChannel(registrar.messenger(), EVENT_CHANNEL_NAME);
    methodChannel.setMethodCallHandler(geolocatorPlugin);
    eventChannel.setStreamHandler(geolocatorPlugin);
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    switch (call.method) {
      case "getLastKnownPosition": {
        Task task = TaskFactory.createLastKnownLocationTask(
                mRegistrar, result, call.arguments, this);
        mTasks.put(task.getTaskID(), task);
        task.startTask();
        break;
      }
      case "getCurrentPosition": {
        Task task = TaskFactory.createCurrentLocationTask(
                mRegistrar, result, call.arguments, this);
        mTasks.put(task.getTaskID(), task);
        task.startTask();
        break;
      }
      case "placemarkFromAddress": {
        Task task = TaskFactory.createForwardGeocodingTask(
                mRegistrar, result, call.arguments, this);
        mTasks.put(task.getTaskID(), task);
        task.startTask();
        break;
      }
      case "placemarkFromCoordinates": {
        Task task = TaskFactory.createReverseGeocodingTask(
                mRegistrar, result, call.arguments, this);
        mTasks.put(task.getTaskID(), task);
        task.startTask();
        break;
      }
      case "distanceBetween": {
        Task task = TaskFactory.createCalculateDistanceTask(
                mRegistrar, result, call.arguments, this);
        mTasks.put(task.getTaskID(), task);
        task.startTask();
        break;
      }
      default:
        result.notImplemented();
        break;
    }
  }

  @Override
  public void onListen(Object o, EventChannel.EventSink eventSink) {
    if (mStreamLocationTask != null) {
      eventSink.error(
              "ALREADY_LISTENING",
              "You are already listening for location changes. Create a new instance or stop listening to the current stream.",
              null);

      return;
    }

    mStreamLocationTask = TaskFactory.createStreamLocationUpdatesTask(
            mRegistrar, eventSink, o, this);
    mStreamLocationTask.startTask();
  }

  @Override
  public void onCancel(Object arguments) {
    if (mStreamLocationTask == null) return;

    mStreamLocationTask.stopTask();
    mStreamLocationTask = null;
  }

  public void onCompletion(UUID taskID) {
    mTasks.remove(taskID);
  }
}
@@ -554,16 +554,58 @@
 gistrar;
+%0Aimport io.flutter.view.FlutterNativeView;
 %0A%0A/**%0A *
@@ -666,16 +666,18 @@
 plements
+%0A 
  MethodC
@@ -687,16 +687,18 @@
 Handler,
+%0A 
  EventCh
@@ -717,16 +717,18 @@
 Handler,
+%0A 
  OnCompl
@@ -740,16 +740,54 @@
 Listener
+,%0A  PluginRegistry.ViewDestroyListener
  %7B%0A%0A  pr
@@ -1839,16 +1839,73 @@
 Plugin);
+%0A%0A    registrar.addViewDestroyListener(geolocatorPlugin);
 %0A  %7D%0A%0A  
@@ -4073,9 +4073,135 @@
 D);%0A  %7D%0A
-%7D
+%0A  @Override%0A  public boolean onViewDestroy(FlutterNativeView flutterNativeView) %7B%0A    onCancel(null);%0A    return false;%0A  %7D%0A%7D%0A

Stop location tracking on FlutterView destroy