/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*-
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.gecko;

import org.mozilla.gecko.AppConstants.Versions;
import org.mozilla.gecko.permissions.Permissions;
import org.mozilla.gecko.util.ThreadUtils;

import android.Manifest;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;

public class ScreenshotObserver {
    private static final String LOGTAG = "GeckoScreenshotObserver";
    public Context context;

    /**
     * Listener for screenshot changes.
     */
    public interface OnScreenshotListener {
        /**
         * This callback is executed on the UI thread.
         */
        public void onScreenshotTaken(String data, String title);
    }

    private OnScreenshotListener listener;

    public ScreenshotObserver() {
    }

    public void setListener(Context context, OnScreenshotListener listener) {
        this.context = context;
        this.listener = listener;
    }

    private MediaObserver mediaObserver;
    private String[] mediaProjections = new String[] {
                    MediaStore.Images.ImageColumns.DATA,
                    MediaStore.Images.ImageColumns.DISPLAY_NAME,
                    MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME,
                    MediaStore.Images.ImageColumns.DATE_TAKEN,
                    MediaStore.Images.ImageColumns.TITLE
    };

    /**
     * Start ScreenshotObserver if this device is supported and all required runtime permissions
     * have been granted by the user. Calling this method will not prompt for permissions.
     */
    public void start() {
        Permissions.from(context)
                   .withPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
                   .doNotPrompt()
                   .run(startObserverRunnable());
    }

    private Runnable startObserverRunnable() {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    if (mediaObserver == null) {
                        mediaObserver = new MediaObserver();
                        context.getContentResolver().registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, false, mediaObserver);
                    }
                } catch (Exception e) {
                    Log.e(LOGTAG, "Failure to start watching media: ", e);
                }
            }
        };
    }

    public void stop() {
        if (mediaObserver == null) {
            return;
        }

        try {
            context.getContentResolver().unregisterContentObserver(mediaObserver);
            mediaObserver = null;
        } catch (Exception e) {
            Log.e(LOGTAG, "Failure to stop watching media: ", e);
        }
    }

    public void onMediaChange(final Uri uri) {
        // Make sure we are on not on the main thread.
        final ContentResolver cr = context.getContentResolver();
        ThreadUtils.postToBackgroundThread(new Runnable() {
            @Override
            public void run() {
                // Find the most recent image added to the MediaStore and see if it's a screenshot.
                final Cursor cursor = cr.query(uri, mediaProjections, null, null, MediaStore.Images.ImageColumns.DATE_ADDED + " DESC LIMIT 1");
                try {
                    if (cursor == null) {
                        return;
                    }

                    while (cursor.moveToNext()) {
                        String data = cursor.getString(0);
                        Log.i(LOGTAG, "data: " + data);
                        String display = cursor.getString(1);
                        Log.i(LOGTAG, "display: " + display);
                        String album = cursor.getString(2);
                        Log.i(LOGTAG, "album: " + album);
                        long date = cursor.getLong(3);
                        String title = cursor.getString(4);
                        Log.i(LOGTAG, "title: " + title);
                        if (album != null && album.toLowerCase().contains("screenshot")) {
                            if (listener != null) {
                                listener.onScreenshotTaken(data, title);
                                break;
                            }
                        }
                    }
                } catch (Exception e) {
                    Log.e(LOGTAG, "Failure to process media change: ", e);
                } finally {
                    if (cursor != null) {
                        cursor.close();
                    }
                }
            }
        });
    }

    private class MediaObserver extends ContentObserver {
        public MediaObserver() {
            super(null);
        }

        @Override
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            onMediaChange(MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        }
    }
}
