/*
 * Copyright 2013 Philip Schiffer
 *
 *    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 de.psdev.licensesdialog;

import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Message;
import android.view.ContextThemeWrapper;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

import java.util.List;

import de.psdev.licensesdialog.licenses.ApacheSoftwareLicense20;
import de.psdev.licensesdialog.model.Notice;
import de.psdev.licensesdialog.model.Notices;

public class LicensesDialog {
    public static final Notice LICENSES_DIALOG_NOTICE = new Notice("LicensesDialog", "http://psdev.de/LicensesDialog",
        "Copyright 2013-2016 Philip Schiffer",
        new ApacheSoftwareLicense20());

    private final Context mContext;
    private final String mTitleText;
    private final String mLicensesText;
    private final String mCloseText;
    private final int mThemeResourceId;
    private final int mDividerColor;

    private DialogInterface.OnDismissListener mOnDismissListener;

    // ==========================================================================================================================
    // Constructor
    // ==========================================================================================================================

    private LicensesDialog(final Context context, final String licensesText, final String titleText, final String closeText,
                           final int themeResourceId,
                           final int dividerColor) {
        mContext = context;
        mTitleText = titleText;
        mLicensesText = licensesText;
        mCloseText = closeText;
        mThemeResourceId = themeResourceId;
        mDividerColor = dividerColor;
    }

    // ==========================================================================================================================
    // Public API
    // ==========================================================================================================================

    public LicensesDialog setOnDismissListener(final DialogInterface.OnDismissListener onDismissListener) {
        mOnDismissListener = onDismissListener;
        return this;
    }

    public Dialog create() {
        //Get resources
        final WebView webView = createWebView(mContext);
        webView.loadDataWithBaseURL(null, mLicensesText, "text/html", "utf-8", null);
        final AlertDialog.Builder builder;
        if (mThemeResourceId != 0) {
            builder = new AlertDialog.Builder(new ContextThemeWrapper(mContext, mThemeResourceId));
        } else {
            builder = new AlertDialog.Builder(mContext);
        }
        builder.setTitle(mTitleText)
            .setView(webView)
            .setPositiveButton(mCloseText, (dialogInterface, i) -> dialogInterface.dismiss());
        final AlertDialog dialog = builder.create();
        dialog.setOnDismissListener(dialog1 -> {
            if (mOnDismissListener != null) {
                mOnDismissListener.onDismiss(dialog1);
            }
        });
        dialog.setOnShowListener(dialogInterface -> {
            if (mDividerColor != 0) {
                // Set title divider color
                final int titleDividerId = mContext.getResources().getIdentifier("titleDivider", "id", "android");
                final View titleDivider = dialog.findViewById(titleDividerId);
                if (titleDivider != null) {
                    titleDivider.setBackgroundColor(mDividerColor);
                }
            }
        });
        return dialog;
    }

    public Dialog show() {
        final Dialog dialog = create();
        dialog.show();
        return dialog;
    }

    // ==========================================================================================================================
    // Private API
    // ==========================================================================================================================

    private static WebView createWebView(final Context context) {
        final WebView webView = new WebView(context);
        webView.getSettings().setSupportMultipleWindows(true);
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onCreateWindow(final WebView view, final boolean isDialog, final boolean isUserGesture, final Message resultMsg) {
                final WebView.HitTestResult result = view.getHitTestResult();
                final String data = result.getExtra();
                if (data != null) {
                    final Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(data));
                    context.startActivity(browserIntent);
                }
                return false;
            }
        });
        return webView;
    }

    // ==========================================================================================================================
    // Inner classes
    // ==========================================================================================================================

    public static final class Builder {

        private final Context mContext;

        // Default values
        private String mTitleText;
        private String mCloseText;
        @Nullable
        private Integer mRawNoticesId;
        @Nullable
        private Notices mNotices;
        @Nullable
        private String mNoticesText;
        private String mNoticesStyle;
        private boolean mShowFullLicenseText;
        private boolean mIncludeOwnLicense;
        private int mThemeResourceId;
        private int mDividerColor;

        public Builder(final Context context) {
            mContext = context;
            mTitleText = context.getString(R.string.notices_title);
            mCloseText = context.getString(R.string.notices_close);
            mNoticesStyle = context.getString(R.string.notices_default_style);
            mShowFullLicenseText = false;
            mIncludeOwnLicense = false;
            mThemeResourceId = 0;
            mDividerColor = 0;
        }

        public Builder setTitle(final int titleId) {
            mTitleText = mContext.getString(titleId);
            return this;
        }

        public Builder setTitle(final String title) {
            mTitleText = title;
            return this;
        }

        public Builder setCloseText(final int closeId) {
            mCloseText = mContext.getString(closeId);
            return this;
        }

        public Builder setCloseText(final String closeText) {
            mCloseText = closeText;
            return this;
        }

        public Builder setNotices(final int rawNoticesId) {
            mRawNoticesId = rawNoticesId;
            mNotices = null;
            return this;
        }

        public Builder setNotices(final Notices notices) {
            mNotices = notices;
            mRawNoticesId = null;
            return this;
        }

        public Builder setNotices(final Notice notice) {
            return setNotices(getSingleNoticeNotices(notice));
        }

        Builder setNotices(final String notices) {
            mNotices = null;
            mRawNoticesId = null;
            mNoticesText = notices;
            return this;
        }

        public Builder setNoticesCssStyle(final int cssStyleTextId) {
            mNoticesStyle = mContext.getString(cssStyleTextId);
            return this;
        }

        public Builder setNoticesCssStyle(final String cssStyleText) {
            mNoticesStyle = cssStyleText;
            return this;
        }

        public Builder setShowFullLicenseText(final boolean showFullLicenseText) {
            mShowFullLicenseText = showFullLicenseText;
            return this;
        }

        public Builder setIncludeOwnLicense(final boolean includeOwnLicense) {
            mIncludeOwnLicense = includeOwnLicense;
            return this;
        }

        public Builder setThemeResourceId(final int themeResourceId) {
            mThemeResourceId = themeResourceId;
            return this;
        }

        public Builder setDividerColor(final int dividerColor) {
            mDividerColor = dividerColor;
            return this;
        }

        public Builder setDividerColorId(final int dividerColorId) {
            mDividerColor = mContext.getResources().getColor(dividerColorId);
            return this;
        }

        public LicensesDialog build() {
            final String licensesText;
            if (mNotices != null) {
                licensesText = getLicensesText(mContext, mNotices, mShowFullLicenseText, mIncludeOwnLicense, mNoticesStyle);
            } else if (mRawNoticesId != null) {
                licensesText = getLicensesText(mContext, getNotices(mContext, mRawNoticesId), mShowFullLicenseText, mIncludeOwnLicense,
                    mNoticesStyle);
            } else if (mNoticesText != null) {
                licensesText = mNoticesText;
            } else {
                throw new IllegalStateException("Notices have to be provided, see setNotices");
            }

            return new LicensesDialog(mContext, licensesText, mTitleText, mCloseText, mThemeResourceId, mDividerColor);
        }

        private static Notices getNotices(final Context context, final int rawNoticesResourceId) {
            try {
                final Resources resources = context.getResources();
                if ("raw".equals(resources.getResourceTypeName(rawNoticesResourceId))) {
                    return NoticesXmlParser.parse(resources.openRawResource(rawNoticesResourceId));
                } else {
                    throw new IllegalStateException("not a raw resource");
                }
            } catch (final Exception e) {
                throw new IllegalStateException(e);
            }
        }

        private static String getLicensesText(final Context context, final Notices notices, final boolean showFullLicenseText,
                                              final boolean includeOwnLicense, final String style) {
            try {
                if (includeOwnLicense) {
                    final List<Notice> noticeList = notices.getNotices();
                    noticeList.add(LICENSES_DIALOG_NOTICE);
                }
                return NoticesHtmlBuilder.create(context).setShowFullLicenseText(showFullLicenseText).setNotices(notices).setStyle(style).build();
            } catch (final Exception e) {
                throw new IllegalStateException(e);
            }
        }

        private static Notices getSingleNoticeNotices(final Notice notice) {
            final Notices notices = new Notices();
            notices.addNotice(notice);
            return notices;
        }

    }
}