package com.fsck.k9.view;


import java.io.InputStream;

import android.annotation.TargetApi;
import android.content.ActivityNotFoundException;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Build.VERSION_CODES;
import android.provider.Browser;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import timber.log.Timber;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.fsck.k9.K9;
import com.fsck.k9.mailstore.AttachmentResolver;
import com.fsck.k9.view.MessageWebView.OnPageFinishedListener;


/**
 * {@link WebViewClient} that intercepts requests for {@code cid:} URIs to load the respective body part.
 */
abstract class K9WebViewClient extends WebViewClient {
    private static final String CID_SCHEME = "cid";
    private static final WebResourceResponse RESULT_DO_NOT_INTERCEPT = null;
    private static final WebResourceResponse RESULT_DUMMY_RESPONSE = new WebResourceResponse(null, null, null);
    private OnPageFinishedListener onPageFinishedListener;


    @Nullable
    private final AttachmentResolver attachmentResolver;


    public static K9WebViewClient newInstance(@Nullable AttachmentResolver attachmentResolver) {
        if (Build.VERSION.SDK_INT < 21) {
            return new PreLollipopWebViewClient(attachmentResolver);
        }

        return new LollipopWebViewClient(attachmentResolver);
    }


    private K9WebViewClient(@Nullable AttachmentResolver attachmentResolver) {
        this.attachmentResolver = attachmentResolver;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView webView, String url) {
        Uri uri = Uri.parse(url);
        if (CID_SCHEME.equals(uri.getScheme())) {
            return false;
        }

        Context context = webView.getContext();
        Intent intent = createBrowserViewIntent(uri, context);
        addActivityFlags(intent);

        boolean overridingUrlLoading = false;
        try {
            context.startActivity(intent);
            overridingUrlLoading = true;
        } catch (ActivityNotFoundException ex) {
            // If no application can handle the URL, assume that the WebView can handle it.
        }

        return overridingUrlLoading;
    }

    private Intent createBrowserViewIntent(Uri uri, Context context) {
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
        intent.addCategory(Intent.CATEGORY_BROWSABLE);
        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
        intent.putExtra(Browser.EXTRA_CREATE_NEW_TAB, true);
        return intent;
    }

    protected abstract void addActivityFlags(Intent intent);

    protected WebResourceResponse shouldInterceptRequest(WebView webView, Uri uri) {
        if (!CID_SCHEME.equals(uri.getScheme())) {
            return RESULT_DO_NOT_INTERCEPT;
        }

        if (attachmentResolver == null) {
            return RESULT_DUMMY_RESPONSE;
        }

        String cid = uri.getSchemeSpecificPart();
        if (TextUtils.isEmpty(cid)) {
            return RESULT_DUMMY_RESPONSE;
        }

        Uri attachmentUri = attachmentResolver.getAttachmentUriForContentId(cid);
        if (attachmentUri == null) {
            return RESULT_DUMMY_RESPONSE;
        }

        Context context = webView.getContext();
        ContentResolver contentResolver = context.getContentResolver();
        try {
            String mimeType = contentResolver.getType(attachmentUri);
            InputStream inputStream = contentResolver.openInputStream(attachmentUri);

            return new WebResourceResponse(mimeType, null, inputStream);
        } catch (Exception e) {
            Timber.e(e, "Error while intercepting URI: %s", uri);
            return RESULT_DUMMY_RESPONSE;
        }
    }

    public void setOnPageFinishedListener(OnPageFinishedListener onPageFinishedListener) {
        this.onPageFinishedListener = onPageFinishedListener;
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        if (onPageFinishedListener != null) {
            onPageFinishedListener.onPageFinished();
        }
    }

    @SuppressWarnings("deprecation")
    private static class PreLollipopWebViewClient extends K9WebViewClient {
        protected PreLollipopWebViewClient(AttachmentResolver attachmentResolver) {
            super(attachmentResolver);
        }

        @Override
        public WebResourceResponse shouldInterceptRequest(WebView webView, String url) {
            return shouldInterceptRequest(webView, Uri.parse(url));
        }

        @Override
        protected void addActivityFlags(Intent intent) {
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
        }
    }

    @TargetApi(VERSION_CODES.LOLLIPOP)
    private static class LollipopWebViewClient extends K9WebViewClient {
        protected LollipopWebViewClient(AttachmentResolver attachmentResolver) {
            super(attachmentResolver);
        }

        @Override
        public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest request) {
            return shouldInterceptRequest(webView, request.getUrl());
        }

        @Override
        protected void addActivityFlags(Intent intent) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
        }
    }
}

@@ -48,16 +48,68 @@
 tStream;
+%0Aimport java.util.Collections;%0Aimport java.util.Map;
 %0A%0Aimport
@@ -672,31 +672,8 @@
 t;%0A%0A
-import com.fsck.k9.K9;%0A
 impo
@@ -2868,24 +2868,106 @@
 t intent);%0A%0A
+    protected abstract void addCacheControlHeader(WebResourceResponse response);%0A%0A
     protecte
@@ -3852,30 +3852,65 @@
             
-return
+WebResourceResponse webResourceResponse =
  new WebReso
@@ -3952,16 +3952,112 @@
 tream);%0A
+            addCacheControlHeader(webResourceResponse);%0A            return webResourceResponse;%0A
         
@@ -5177,32 +5177,210 @@
 ESET);%0A        %7D
+%0A%0A        @Override%0A        protected void addCacheControlHeader(WebResourceResponse response) %7B%0A            // Sadly, adding headers is not supported prior to Lollipop%0A        %7D
 %0A    %7D%0A%0A    @Tar
@@ -5885,32 +5885,32 @@
 ntent intent) %7B%0A
-
             inte
@@ -5962,21 +5962,274 @@
 );%0A        %7D
+%0A%0A        @Override%0A        protected void addCacheControlHeader(WebResourceResponse response) %7B%0A            Map%3CString, String%3E headers = Collections.singletonMap(%22Cache-Control%22, %22no-store%22);%0A            response.setResponseHeaders(headers);%0A        %7D
 %0A    %7D%0A%7D%0A

Disable WebView caching of inline images on API 21+