/*
 * Copyright (C) 2017 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.android.settings.notification;

import android.app.ActivityManager;
import android.app.AutomaticZenRule;
import android.app.NotificationManager;
import android.content.Context;
import android.net.Uri;
import android.provider.Settings;
import android.service.notification.ZenModeConfig;
import android.support.annotation.VisibleForTesting;
import android.util.Log;

import com.android.settings.R;

public class ZenModeBackend {
    @VisibleForTesting
    protected static final String ZEN_MODE_FROM_ANYONE = "zen_mode_from_anyone";
    @VisibleForTesting
    protected static final String ZEN_MODE_FROM_CONTACTS = "zen_mode_from_contacts";
    @VisibleForTesting
    protected static final String ZEN_MODE_FROM_STARRED = "zen_mode_from_starred";
    @VisibleForTesting
    protected static final String ZEN_MODE_FROM_NONE = "zen_mode_from_none";
    protected static final int SOURCE_NONE = -1;

    private static ZenModeBackend sInstance;

    protected int mZenMode;
    /** gets policy last set by updatePolicy **/
    protected NotificationManager.Policy mPolicy;
    private final NotificationManager mNotificationManager;

    private String TAG = "ZenModeSettingsBackend";
    private final Context mContext;

    public static ZenModeBackend getInstance(Context context) {
        if (sInstance == null) {
            sInstance = new ZenModeBackend(context);
        }
        return sInstance;
    }

    public ZenModeBackend(Context context) {
        mContext = context;
        mNotificationManager = (NotificationManager) context.getSystemService(
                Context.NOTIFICATION_SERVICE);
        updateZenMode();
        updatePolicy();
    }

    protected void updatePolicy() {
        if (mNotificationManager != null) {
            mPolicy = mNotificationManager.getNotificationPolicy();
        }
    }

    protected void updateZenMode() {
        mZenMode = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.ZEN_MODE, mZenMode);
    }

    protected boolean setZenRule(String id, AutomaticZenRule rule) {
        return NotificationManager.from(mContext).updateAutomaticZenRule(id, rule);
    }

    protected void setZenMode(int zenMode) {
        NotificationManager.from(mContext).setZenMode(zenMode, null, TAG);
        mZenMode = getZenMode();
    }

    protected void setZenModeForDuration(int minutes) {
        Uri conditionId = ZenModeConfig.toTimeCondition(mContext, minutes,
                ActivityManager.getCurrentUser(), true).id;
        mNotificationManager.setZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS,
                conditionId, TAG);
        mZenMode = getZenMode();
    }

    protected int getZenMode() {
        mZenMode = Settings.Global.getInt(mContext.getContentResolver(),
                Settings.Global.ZEN_MODE, mZenMode);
        return mZenMode;
    }

    protected boolean isVisualEffectSuppressed(int visualEffect) {
        return (mPolicy.suppressedVisualEffects & visualEffect) != 0;
    }

    protected boolean isPriorityCategoryEnabled(int categoryType) {
        return (mPolicy.priorityCategories & categoryType) != 0;
    }

    protected int getNewPriorityCategories(boolean allow, int categoryType) {
        int priorityCategories = mPolicy.priorityCategories;
        if (allow) {
            priorityCategories |= categoryType;
        } else {
            priorityCategories &= ~categoryType;
        }
        return priorityCategories;
    }

    protected int getPriorityCallSenders() {
        if (isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_CALLS)) {
            return mPolicy.priorityCallSenders;
        }

        return SOURCE_NONE;
    }

    protected int getPriorityMessageSenders() {
        if (isPriorityCategoryEnabled(NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES)) {
            return mPolicy.priorityMessageSenders;
        }
        return SOURCE_NONE;
    }

    protected void saveVisualEffectsPolicy(int category, boolean suppress) {
        int suppressedEffects = getNewSuppressedEffects(suppress, category);
        savePolicy(mPolicy.priorityCategories, mPolicy.priorityCallSenders,
                mPolicy.priorityMessageSenders, suppressedEffects);
    }

    protected void saveSoundPolicy(int category, boolean allow) {
        int priorityCategories = getNewPriorityCategories(allow, category);
        savePolicy(priorityCategories, mPolicy.priorityCallSenders,
                mPolicy.priorityMessageSenders, mPolicy.suppressedVisualEffects);
    }

    protected void savePolicy(int priorityCategories, int priorityCallSenders,
            int priorityMessageSenders, int suppressedVisualEffects) {
        mPolicy = new NotificationManager.Policy(priorityCategories, priorityCallSenders,
                priorityMessageSenders,
                suppressedVisualEffects);
        mNotificationManager.setNotificationPolicy(mPolicy);
    }

    protected int getNewSuppressedEffects(boolean suppress, int effectType) {
        int effects = mPolicy.suppressedVisualEffects;
        if (suppress) {
            effects |= effectType;
        } else {
            effects &= ~effectType;
        }
        return effects;
    }

    protected boolean isEffectAllowed(int effect) {
        return (mPolicy.suppressedVisualEffects & effect) == 0;
    }

    protected void saveSenders(int category, int val) {
        int priorityCallSenders = getPriorityCallSenders();
        int priorityMessagesSenders = getPriorityMessageSenders();
        int categorySenders = getPrioritySenders(category);

        final boolean allowSenders = val != SOURCE_NONE;
        final int allowSendersFrom = val == SOURCE_NONE ? categorySenders : val;

        String stringCategory = "";
        if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS) {
            stringCategory = "Calls";
            priorityCallSenders = allowSendersFrom;
        }

        if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
            stringCategory = "Messages";
            priorityMessagesSenders = allowSendersFrom;
        }

        savePolicy(getNewPriorityCategories(allowSenders, category),
            priorityCallSenders, priorityMessagesSenders, mPolicy.suppressedVisualEffects);

        if (ZenModeSettingsBase.DEBUG) Log.d(TAG, "onPrefChange allow" +
                stringCategory + "=" + allowSenders + " allow" + stringCategory + "From="
                + ZenModeConfig.sourceToString(allowSendersFrom));
    }

    protected String getSendersKey(int category) {
        switch (getZenMode()) {
            case Settings.Global.ZEN_MODE_NO_INTERRUPTIONS:
            case Settings.Global.ZEN_MODE_ALARMS:
                return getKeyFromSetting(SOURCE_NONE);
            default:
                int prioritySenders = getPrioritySenders(category);
                return getKeyFromSetting(isPriorityCategoryEnabled(category)
                        ? prioritySenders : SOURCE_NONE);
            }
    }

    private int getPrioritySenders(int category) {
        int categorySenders = -1;

        if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS) {
            return getPriorityCallSenders();
        }

        if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
            return getPriorityMessageSenders();
        }

        return categorySenders;
    }

    protected static String getKeyFromSetting(int contactType) {
        switch (contactType) {
            case NotificationManager.Policy.PRIORITY_SENDERS_ANY:
                return ZEN_MODE_FROM_ANYONE;
            case NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS:
                return ZEN_MODE_FROM_CONTACTS;
            case NotificationManager.Policy.PRIORITY_SENDERS_STARRED:
                return ZEN_MODE_FROM_STARRED;
            case SOURCE_NONE:
            default:
                return ZEN_MODE_FROM_NONE;
        }
    }

    protected int getContactsSummary(int category) {
        int contactType = -1;

        // SOURCE_NONE can be used when in total silence or alarms only
        // (policy is based on user's preferences but the UI displayed is based on zenMode)
        if (category == SOURCE_NONE) {
            return R.string.zen_mode_from_none;
        }

        if (category == NotificationManager.Policy.PRIORITY_CATEGORY_MESSAGES) {
            if (isPriorityCategoryEnabled(category)) {
                contactType = getPriorityMessageSenders();
            }
        } else if (category == NotificationManager.Policy.PRIORITY_CATEGORY_CALLS) {
            if (isPriorityCategoryEnabled(category)) {
                contactType = getPriorityCallSenders();
            }
        }

        switch (contactType) {
            case NotificationManager.Policy.PRIORITY_SENDERS_ANY:
                return R.string.zen_mode_from_anyone;
            case NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS:
                return  R.string.zen_mode_from_contacts;
            case NotificationManager.Policy.PRIORITY_SENDERS_STARRED:
                return  R.string.zen_mode_from_starred;
            case SOURCE_NONE:
            default:
                return R.string.zen_mode_from_none;
        }
    }

    protected static int getSettingFromPrefKey(String key) {
        switch (key) {
            case ZEN_MODE_FROM_ANYONE:
                return NotificationManager.Policy.PRIORITY_SENDERS_ANY;
            case ZEN_MODE_FROM_CONTACTS:
                return NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS;
            case ZEN_MODE_FROM_STARRED:
                return NotificationManager.Policy.PRIORITY_SENDERS_STARRED;
            case ZEN_MODE_FROM_NONE:
            default:
                return SOURCE_NONE;
        }
    }

    public boolean removeZenRule(String ruleId) {
        return NotificationManager.from(mContext).removeAutomaticZenRule(ruleId);
    }

    protected String addZenRule(AutomaticZenRule rule) {
        try {
            String id = NotificationManager.from(mContext).addAutomaticZenRule(rule);
            NotificationManager.from(mContext).getAutomaticZenRule(id);
            return id;
        } catch (Exception e) {
            return null;
        }
    }
}
