/***********************************************************************************************************
 * Name         : TriggerControl
 * Purpose      : Utility class to disable Trigger Executions
 **********************************************************************************************************/

public with sharing class TriggerControl {
    private static final String BYPASS_TRIGGERS_PERMISSION = 'Admin_Bypass_Triggers';

    @TestVisible
    private static Map<String, Set<TriggerOperation>> mapObjectValuesDisabled = new Map<String, Set<TriggerOperation>>();

    /**
     * Method Name  : disableTrigger
     * Description  : Disables the trigger completely for a specific SObject
     * @param String sObj, SObject type
     * @return void
     */
    public static void disableTrigger(String sObj) {
        sObj = sObj.toUpperCase();
        mapObjectValuesDisabled.put(sObj, new Set<TriggerOperation>());
        for (Integer i = 0; i < TriggerOperation.values().size(); i++) {
            mapObjectValuesDisabled.get(sObj).add(TriggerOperation.values()[i]);
        }
    }

    /**
     * Method Name  : disableTrigger
     * Description  : Disables the trigger for the specific event and SObject
     * @param String sObj, SObject type
     * @param TriggerOperation event, event to disable (for example AFTER_UPDATE)
     * @return void
     */
    public static void disableTrigger(String sObj, TriggerOperation event) {
        sObj = sObj.toUpperCase();
        if (mapObjectValuesDisabled.containsKey(sObj)) {
            mapObjectValuesDisabled.get(sObj).add(event);
        } else {
            mapObjectValuesDisabled.put(sObj, new Set<TriggerOperation>{ event });
        }
    }

    /**
     * Method Name  : enableTrigger
     * Description  : Enables the trigger completely for a specific SObject
     * @param String sObj, SObject type
     * @return void
     */
    public static void enableTrigger(String sObj) {
        mapObjectValuesDisabled.remove(sObj.toUpperCase());
    }

    /**
     * Method Name  : enableTrigger
     * Description  : Enables the trigger for the specific event and SObject
     * @param String sObj, SObject type
     * @param TriggerOperation event, event to enable (for example AFTER_UPDATE)
     * @return void
     */
    public static void enableTrigger(String sObj, TriggerOperation event) {
        sObj = sObj.toUpperCase();
        if (mapObjectValuesDisabled.containsKey(sObj)) {
            mapObjectValuesDisabled.get(sObj).remove(event);
            if (mapObjectValuesDisabled.get(sObj).isEmpty()) {
                mapObjectValuesDisabled.remove(sObj);
            }
        }
    }

    /**
     * Method Name  : isTriggerEnabled
     * Description  : Evaluates whether a Trigger is enabled for a specific event and SObject
     * @param String sObj, SObject type
     * @param TriggerOperation event, event to evaluate (for example AFTER_UPDATE)
     * @return Boolean
     */
    public static Boolean isTriggerEnabled(String sObj, TriggerOperation event) {
        if (FeatureManagement.checkPermission(BYPASS_TRIGGERS_PERMISSION)) {
            return false;
        }
        sObj = sObj.toUpperCase();
        return mapObjectValuesDisabled.containsKey(sObj) && mapObjectValuesDisabled.get(sObj).contains(event)
            ? false
            : true;
    }
}