/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * 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.wearable.agendadata;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.text.TextUtils;
import android.text.format.DateFormat;
import android.util.Log;

import static com.example.android.wearable.agendadata.Constants.ALL_DAY;
import static com.example.android.wearable.agendadata.Constants.BEGIN;
import static com.example.android.wearable.agendadata.Constants.DESCRIPTION;
import static com.example.android.wearable.agendadata.Constants.EXTRA_SILENT;
import static com.example.android.wearable.agendadata.Constants.END;
import static com.example.android.wearable.agendadata.Constants.PROFILE_PIC;
import static com.example.android.wearable.agendadata.Constants.TAG;
import static com.example.android.wearable.agendadata.Constants.TITLE;

import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.Asset;
import com.google.android.gms.wearable.DataApi;
import com.google.android.gms.wearable.DataEvent;
import com.google.android.gms.wearable.DataEventBuffer;
import com.google.android.gms.wearable.DataItem;
import com.google.android.gms.wearable.DataMap;
import com.google.android.gms.wearable.DataMapItem;
import com.google.android.gms.wearable.Wearable;
import com.google.android.gms.wearable.WearableListenerService;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Listens to DataItem events on the home device.
 */
public class HomeListenerService extends WearableListenerService {

    private static final Map<Uri, Integer> sNotificationIdByDataItemUri =
            new HashMap<Uri, Integer>();
    private static int sNotificationId = 1;
    private GoogleApiClient mGoogleApiClient;

    @Override
    public void onCreate() {
        super.onCreate();
        mGoogleApiClient = new GoogleApiClient.Builder(this.getApplicationContext())
                .addApi(Wearable.API)
                .build();
        mGoogleApiClient.connect();
    }

    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
            Log.d(TAG, "onDataChanged: " + dataEvents + " for " + getPackageName());
        }
        for (DataEvent event : dataEvents) {

            if (event.getType() == DataEvent.TYPE_DELETED) {
                deleteDataItem(event.getDataItem());
            } else if (event.getType() == DataEvent.TYPE_CHANGED) {
                updateNotificationForDataItem(event.getDataItem());
            }
        }
    }

    /**
     * Deletes the calendar card associated with the data item.
     */
    private void deleteDataItem(DataItem dataItem) {
        if (Log.isLoggable(TAG, Log.VERBOSE)) {
            Log.v(TAG, "onDataItemDeleted:DataItem=" + dataItem.getUri());
        }
        Integer notificationId = sNotificationIdByDataItemUri.remove(dataItem.getUri());
        if (notificationId != null) {
            ((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(notificationId);
        }
    }

    /**
     * Posts a local notification to show calendar card.
     */
    private void updateNotificationForDataItem(DataItem dataItem) {
        DataMapItem mapDataItem = DataMapItem.fromDataItem(dataItem);
        DataMap data = mapDataItem.getDataMap();

        String description = data.getString(DESCRIPTION);
        if (TextUtils.isEmpty(description)) {
            description = "";
        } else {
            // Add a space between the description and the time of the event.
            description += " ";
        }
        String contentText;
        if (data.getBoolean(ALL_DAY)) {
            contentText = getString(R.string.desc_all_day, description);
        } else {
            String startTime = DateFormat.getTimeFormat(this).format(new Date(data.getLong(BEGIN)));
            String endTime = DateFormat.getTimeFormat(this).format(new Date(data.getLong(END)));
            contentText = getString(R.string.desc_time_period, description, startTime, endTime);
        }

        Intent deleteOperation = new Intent(this, DeleteService.class);
        // Use a unique identifier for the delete action.
        String deleteAction = "action_delete" + dataItem.getUri().toString() + sNotificationId;
        deleteOperation.setAction(deleteAction);
        deleteOperation.setData(dataItem.getUri());
        PendingIntent deleteIntent = PendingIntent.getService(this, 0, deleteOperation,
                PendingIntent.FLAG_ONE_SHOT);
        PendingIntent silentDeleteIntent = PendingIntent.getService(this, 1,
                deleteOperation.putExtra(EXTRA_SILENT, true), PendingIntent.FLAG_ONE_SHOT);

        Notification.Builder notificationBuilder = new Notification.Builder(this)
                .setContentTitle(data.getString(TITLE))
                .setContentText(contentText)
                .setSmallIcon(R.drawable.ic_launcher)
                .addAction(R.drawable.ic_menu_delete, getText(R.string.delete), deleteIntent)
                .setDeleteIntent(silentDeleteIntent)  // Delete DataItem if notification dismissed.
                .setLocalOnly(true)
                .setPriority(Notification.PRIORITY_MIN);

        // Set the event owner's profile picture as the notification background.
        Asset asset = data.getAsset(PROFILE_PIC);
        if (null != asset) {
            if (mGoogleApiClient.isConnected()) {
                DataApi.GetFdForAssetResult assetFdResult =
                        Wearable.DataApi.getFdForAsset(mGoogleApiClient, asset).await();
                if (assetFdResult.getStatus().isSuccess()) {
                    Bitmap profilePic = BitmapFactory.decodeStream(assetFdResult.getInputStream());
                    notificationBuilder.extend(new Notification.WearableExtender()
                            .setBackground(profilePic));
                } else if (Log.isLoggable(TAG, Log.DEBUG)) {
                    Log.d(TAG, "asset fetch failed with statusCode: "
                            + assetFdResult.getStatus().getStatusCode());
                }
            } else {
                Log.e(TAG, "Failed to set notification background"
                         + " - Client disconnected from Google Play Services");
            }
        }
        Notification card = notificationBuilder.build();

        ((NotificationManager) getSystemService(NOTIFICATION_SERVICE))
                .notify(sNotificationId, card);

        sNotificationIdByDataItemUri.put(dataItem.getUri(), sNotificationId++);
    }
}
