/*
 * Copyright 2015 Google Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.xyztouristattractions.service;

import android.app.IntentService;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

import com.example.android.xyztouristattractions.R;
import com.example.android.xyztouristattractions.common.Constants;
import com.example.android.xyztouristattractions.common.Utils;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.CapabilityApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.Wearable;

import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * A utility IntentService, used for a variety of asynchronous background
 * operations that do not necessarily need to be tied to a UI.
 */
public class UtilityService extends IntentService {

    private static final String TAG = UtilityService.class.getSimpleName();

    private static final String ACTION_CLEAR_NOTIFICATION = "clear_notification";
    private static final String ACTION_CLEAR_REMOTE_NOTIFICATIONS = "clear_remote_notifications";
    private static final String ACTION_START_DEVICE_ACTIVITY = "start_device_activity";
    private static final String EXTRA_START_PATH = "start_path";
    private static final String EXTRA_START_ACTIVITY_INFO = "start_activity_info";
    private static final long GET_CAPABILITY_TIMEOUT_S = 10;

    public static void clearNotification(Context context) {
        Intent intent = new Intent(context, UtilityService.class);
        intent.setAction(UtilityService.ACTION_CLEAR_NOTIFICATION);
        context.startService(intent);
    }

    public static void clearRemoteNotifications(Context context) {
        context.startService(getClearRemoteNotificationsIntent(context));
    }

    public static Intent getClearRemoteNotificationsIntent(Context context) {
        Intent intent = new Intent(context, UtilityService.class);
        intent.setAction(UtilityService.ACTION_CLEAR_REMOTE_NOTIFICATIONS);
        return intent;
    }

    /**
     * Trigger a message that asks the master device to start an activity.
     *
     * @param context the context
     * @param path the path that will be sent via the wearable message API
     * @param name the tourist attraction name
     * @param city the tourist attraction city
     */
    public static void startDeviceActivity(Context context, String path, String name, String city) {
        Intent intent = new Intent(context, UtilityService.class);
        intent.setAction(UtilityService.ACTION_START_DEVICE_ACTIVITY);
        String extraInfo;
        if (Constants.START_ATTRACTION_PATH.equals(path)) {
            extraInfo = name;
        } else {
            extraInfo = name + ", " + city;
        }
        intent.putExtra(EXTRA_START_ACTIVITY_INFO, extraInfo);
        intent.putExtra(EXTRA_START_PATH, path);
        context.startService(intent);
    }

    public UtilityService() {
        super(TAG);
    }

    @Override
    protected void onHandleIntent(Intent intent) {
        String action = intent != null ? intent.getAction() : null;
        if (ACTION_CLEAR_NOTIFICATION.equals(action)) {
            clearNotificationInternal();
        } else if (ACTION_CLEAR_REMOTE_NOTIFICATIONS.equals(action)) {
            clearRemoteNotificationsInternal();
        } else if (ACTION_START_DEVICE_ACTIVITY.equals(action)) {
            startDeviceActivityInternal(intent.getStringExtra(EXTRA_START_PATH),
                    intent.getStringExtra(EXTRA_START_ACTIVITY_INFO));
        }
    }

    /**
     * Clear the local notifications
     */
    private void clearNotificationInternal() {
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        notificationManager.cancel(Constants.WEAR_NOTIFICATION_ID);
    }

    /**
     * Trigger a message to ask other devices to clear their notifications
     */
    private void clearRemoteNotificationsInternal() {
        GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .build();

        ConnectionResult connectionResult = googleApiClient.blockingConnect(
                Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS);

        if (connectionResult.isSuccess() && googleApiClient.isConnected()) {
            Iterator<String> itr = Utils.getNodes(googleApiClient).iterator();
            while (itr.hasNext()) {
                // Loop through all connected nodes
                Wearable.MessageApi.sendMessage(
                        googleApiClient, itr.next(), Constants.CLEAR_NOTIFICATIONS_PATH, null);
            }
        }

        googleApiClient.disconnect();
    }

    /**
     * Sends the actual message to ask other devices that are capable of showing "details" to start
     * the appropriate activity
     *
     * @param path the path to pass to the wearable message API
     * @param extraInfo extra info that varies based on the path being sent
     */
    private void startDeviceActivityInternal(String path, String extraInfo) {
        GoogleApiClient googleApiClient = new GoogleApiClient.Builder(this)
                .addApi(Wearable.API)
                .build();

        ConnectionResult connectionResult = googleApiClient.blockingConnect(
                Constants.GOOGLE_API_CLIENT_TIMEOUT_S, TimeUnit.SECONDS);

        if (connectionResult.isSuccess() && googleApiClient.isConnected()) {
            CapabilityApi.GetCapabilityResult result = Wearable.CapabilityApi.getCapability(
                    googleApiClient,
                    getApplicationContext().getString(R.string.show_detail_capability_name),
                    CapabilityApi.FILTER_REACHABLE)
                    .await(GET_CAPABILITY_TIMEOUT_S, TimeUnit.SECONDS);
            if (result.getStatus().isSuccess()) {
                Set<Node> nodes = result.getCapability().getNodes();
                for (Node node : nodes) {
                    Wearable.MessageApi.sendMessage(
                            googleApiClient, node.getId(), path, extraInfo.getBytes());
                }
            } else {
                Log.e(TAG, "startDeviceActivityInternal() Failed to get capabilities, status: "
                        + result.getStatus().getStatusMessage());
            }

            googleApiClient.disconnect();
        }
    }

}
