/*
 * Copyright (C) 2018 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 android.telephony;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.service.carrier.CarrierIdentifier;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Contains the list of carrier restrictions.
 * Allowed list: it indicates the list of carriers that are allowed.
 * Excluded list: it indicates the list of carriers that are excluded.
 * Default carrier restriction: it indicates the default behavior and the priority between the two
 * lists:
 *  - not allowed: the device only allows usage of carriers that are present in the allowed list
 *    and not present in the excluded list. This implies that if a carrier is not present in either
 *    list, it is not allowed.
 *  - allowed: the device allows all carriers, except those present in the excluded list and not
 *    present in the allowed list. This implies that if a carrier is not present in either list,
 *    it is allowed.
 * MultiSim policy: it indicates the behavior in case of devices with two or more SIM cards.
 *  - MULTISIM_POLICY_NONE: the same configuration is applied to all SIM slots independently. This
 *    is the default value if none is set.
 *  - MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT: it indicates that any SIM card can be used
 *    as far as one SIM card matching the configuration is present in the device.
 *
 * Both lists support the character '?' as wild character. For example, an entry indicating
 * MCC=310 and MNC=??? will match all networks with MCC=310.
 *
 * Example 1: Allowed list contains MCC and MNC of operator A. Excluded list contains operator B,
 *            which has same MCC and MNC, but also GID1 value. The priority allowed list is set
 *            to true. Only SIM cards of operator A are allowed, but not those of B or any other
 *            operator.
 * Example 2: Allowed list contains MCC and MNC of operator A. Excluded list contains an entry
 *            with same MCC, and '???' as MNC. The priority allowed list is set to false.
 *            SIM cards of operator A and all SIM cards with a different MCC value are allowed.
 *            SIM cards of operators with same MCC value and different MNC are not allowed.
 * @hide
 */
@SystemApi
public final class CarrierRestrictionRules implements Parcelable {
    /**
     * The device only allows usage of carriers that are present in the allowed list and not
     * present in the excluded list. This implies that if a carrier is not present in either list,
     * it is not allowed.
     */
    public static final int CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED = 0;

    /**
     * The device allows all carriers, except those present in the excluded list and not present
     * in the allowed list. This implies that if a carrier is not present in either list, it is
     * allowed.
     */
    public static final int CARRIER_RESTRICTION_DEFAULT_ALLOWED = 1;

    /** The same configuration is applied to all SIM slots independently. */
    public static final int MULTISIM_POLICY_NONE = 0;

    /** Any SIM card can be used as far as one SIM card matching the configuration is present. */
    public static final int MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT = 1;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "MULTISIM_POLICY_",
            value = {MULTISIM_POLICY_NONE, MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT})
    public @interface MultiSimPolicy {}

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = "CARRIER_RESTRICTION_DEFAULT_",
            value = {CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED, CARRIER_RESTRICTION_DEFAULT_ALLOWED})
    public @interface CarrierRestrictionDefault {}

    /* Wild character for comparison */
    private static final char WILD_CHARACTER = '?';

    private List<CarrierIdentifier> mAllowedCarriers;
    private List<CarrierIdentifier> mExcludedCarriers;
    @CarrierRestrictionDefault
    private int mCarrierRestrictionDefault;
    @MultiSimPolicy
    private int mMultiSimPolicy;

    private CarrierRestrictionRules() {
        mAllowedCarriers = new ArrayList<CarrierIdentifier>();
        mExcludedCarriers = new ArrayList<CarrierIdentifier>();
        mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED;
        mMultiSimPolicy = MULTISIM_POLICY_NONE;
    }

    private CarrierRestrictionRules(Parcel in) {
        mAllowedCarriers = new ArrayList<CarrierIdentifier>();
        mExcludedCarriers = new ArrayList<CarrierIdentifier>();

        in.readTypedList(mAllowedCarriers, CarrierIdentifier.CREATOR);
        in.readTypedList(mExcludedCarriers, CarrierIdentifier.CREATOR);
        mCarrierRestrictionDefault = in.readInt();
        mMultiSimPolicy = in.readInt();
    }

    /**
     * Creates a new builder for this class
     * @hide
     */
    public static Builder newBuilder() {
        return new Builder();
    }

    /**
     * Indicates if all carriers are allowed
     */
    public boolean isAllCarriersAllowed() {
        return (mAllowedCarriers.isEmpty() && mExcludedCarriers.isEmpty()
                && mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_ALLOWED);
    }

    /**
     * Retrieves list of allowed carriers
     *
     * @return the list of allowed carriers
     */
    public @NonNull List<CarrierIdentifier> getAllowedCarriers() {
        return mAllowedCarriers;
    }

    /**
     * Retrieves list of excluded carriers
     *
     * @return the list of excluded carriers
     */
    public @NonNull List<CarrierIdentifier> getExcludedCarriers() {
        return mExcludedCarriers;
    }

    /**
     * Retrieves the default behavior of carrier restrictions
     */
    public @CarrierRestrictionDefault int getDefaultCarrierRestriction() {
        return mCarrierRestrictionDefault;
    }

    /**
     * @return The policy used for multi-SIM devices
     */
    public @MultiSimPolicy int getMultiSimPolicy() {
        return mMultiSimPolicy;
    }

    /**
     * Tests an array of carriers with the carrier restriction configuration. The list of carrier
     * ids passed as argument does not need to be the same as currently present in the device.
     *
     * @param carrierIds list of {@link CarrierIdentifier}, one for each SIM slot on the device
     * @return a list of boolean with the same size as input, indicating if each
     * {@link CarrierIdentifier} is allowed or not.
     */
    public @NonNull List<Boolean> areCarrierIdentifiersAllowed(
            @NonNull List<CarrierIdentifier> carrierIds) {
        ArrayList<Boolean> result = new ArrayList<>(carrierIds.size());

        // First calculate the result for each slot independently
        for (int i = 0; i < carrierIds.size(); i++) {
            boolean inAllowedList = isCarrierIdInList(carrierIds.get(i), mAllowedCarriers);
            boolean inExcludedList = isCarrierIdInList(carrierIds.get(i), mExcludedCarriers);
            if (mCarrierRestrictionDefault == CARRIER_RESTRICTION_DEFAULT_NOT_ALLOWED) {
                result.add((inAllowedList && !inExcludedList) ? true : false);
            } else {
                result.add((inExcludedList && !inAllowedList) ? false : true);
            }
        }
        // Apply the multi-slot policy, if needed.
        if (mMultiSimPolicy == MULTISIM_POLICY_ONE_VALID_SIM_MUST_BE_PRESENT) {
            for (boolean b : result) {
                if (b) {
                    result.replaceAll(x -> true);
                    break;
                }
            }
        }
        return result;
    }

    /**
     * Indicates if a certain carrier {@code id} is present inside a {@code list}
     *
     * @return true if the carrier {@code id} is present, false otherwise
     */
    private static boolean isCarrierIdInList(CarrierIdentifier id, List<CarrierIdentifier> list) {
        for (CarrierIdentifier listItem : list) {
            // Compare MCC and MNC
            if (!patternMatch(id.getMcc(), listItem.getMcc())
                    || !patternMatch(id.getMnc(), listItem.getMnc())) {
                continue;
            }

            // Compare SPN. Comparison is on the complete strings, case insensitive and with wild
            // characters.
            String listItemValue = convertNullToEmpty(listItem.getSpn());
            String idValue = convertNullToEmpty(id.getSpn());
            if (!listItemValue.isEmpty()) {
                if (!patternMatch(idValue, listItemValue)) {
                    continue;
                }
            }

            // The IMSI of the configuration can be shorter than actual IMSI in the SIM card.
            listItemValue = convertNullToEmpty(listItem.getImsi());
            idValue = convertNullToEmpty(id.getImsi());
            if (!patternMatch(
                    idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
                    listItemValue)) {
                continue;
            }

            // The GID1 of the configuration can be shorter than actual GID1 in the SIM card.
            listItemValue = convertNullToEmpty(listItem.getGid1());
            idValue = convertNullToEmpty(id.getGid1());
            if (!patternMatch(
                    idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
                    listItemValue)) {
                continue;
            }

            // The GID2 of the configuration can be shorter than actual GID2 in the SIM card.
            listItemValue = convertNullToEmpty(listItem.getGid2());
            idValue = convertNullToEmpty(id.getGid2());
            if (!patternMatch(
                    idValue.substring(0, Math.min(idValue.length(), listItemValue.length())),
                    listItemValue)) {
                continue;
            }

            // Valid match was found in the list
            return true;
        }
        return false;
    }

    private static String convertNullToEmpty(String value) {
        return Objects.toString(value, "");
    }

    /**
     * Performs a case insensitive string comparison against a given pattern. The character '?'
     * is used in the pattern as wild character in the comparison. The string must have the same
     * length as the pattern.
     *
     * @param str string to match
     * @param pattern string containing the pattern
     * @return true in case of match, false otherwise
     */
    private static boolean patternMatch(String str, String pattern) {
        if (str.length() != pattern.length()) {
            return false;
        }
        String lowerCaseStr = str.toLowerCase();
        String lowerCasePattern = pattern.toLowerCase();

        for (int i = 0; i < lowerCasePattern.length(); i++) {
            if (lowerCasePattern.charAt(i) != lowerCaseStr.charAt(i)
                    && lowerCasePattern.charAt(i) != WILD_CHARACTER) {
                return false;
            }
        }
        return true;
    }

    /**
     * {@link Parcelable#writeToParcel}
     */
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeTypedList(mAllowedCarriers);
        out.writeTypedList(mExcludedCarriers);
        out.writeInt(mCarrierRestrictionDefault);
        out.writeInt(mMultiSimPolicy);
    }

    /**
     * {@link Parcelable#describeContents}
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * {@link Parcelable.Creator}
     */
    public static final @android.annotation.NonNull Creator<CarrierRestrictionRules> CREATOR =
            new Creator<CarrierRestrictionRules>() {
        @Override
        public CarrierRestrictionRules createFromParcel(Parcel in) {
            return new CarrierRestrictionRules(in);
        }

        @Override
        public CarrierRestrictionRules[] newArray(int size) {
            return new CarrierRestrictionRules[size];
        }
    };

    @Override
    public String toString() {
        return "CarrierRestrictionRules(allowed:" + mAllowedCarriers + ", excluded:"
                + mExcludedCarriers + ", default:" + mCarrierRestrictionDefault
                + ", multisim policy:" + mMultiSimPolicy + ")";
    }

    /**
     * Builder for a {@link CarrierRestrictionRules}.
     */
    public static final class Builder {
        private final CarrierRestrictionRules mRules;

        public Builder() {
            mRules = new CarrierRestrictionRules();
        }

        /** build command */
        public @NonNull CarrierRestrictionRules build() {
            return mRules;
        }

        /**
         * Indicate that all carriers are allowed.
         */
        public @NonNull Builder setAllCarriersAllowed() {
            mRules.mAllowedCarriers.clear();
            mRules.mExcludedCarriers.clear();
            mRules.mCarrierRestrictionDefault = CARRIER_RESTRICTION_DEFAULT_ALLOWED;
            return this;
        }

        /**
         * Set list of allowed carriers.
         *
         * @param allowedCarriers list of allowed carriers
         */
        public @NonNull Builder setAllowedCarriers(
                @NonNull List<CarrierIdentifier> allowedCarriers) {
            mRules.mAllowedCarriers = new ArrayList<CarrierIdentifier>(allowedCarriers);
            return this;
        }

        /**
         * Set list of excluded carriers.
         *
         * @param excludedCarriers list of excluded carriers
         */
        public @NonNull Builder setExcludedCarriers(
                @NonNull List<CarrierIdentifier> excludedCarriers) {
            mRules.mExcludedCarriers = new ArrayList<CarrierIdentifier>(excludedCarriers);
            return this;
        }

        /**
         * Set the default behavior of the carrier restrictions
         *
         * @param carrierRestrictionDefault prioritized carrier list
         */
        public @NonNull Builder setDefaultCarrierRestriction(
                @CarrierRestrictionDefault int carrierRestrictionDefault) {
            mRules.mCarrierRestrictionDefault = carrierRestrictionDefault;
            return this;
        }

        /**
         * Set the policy to be used for multi-SIM devices
         *
         * @param multiSimPolicy multi SIM policy
         */
        public @NonNull Builder setMultiSimPolicy(@MultiSimPolicy int multiSimPolicy) {
            mRules.mMultiSimPolicy = multiSimPolicy;
            return this;
        }
    }
}
