package com.regula.documentreader;

import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMapKeySetIterator;
import com.regula.documentreader.api.DocumentReader;
import com.regula.documentreader.api.params.Functionality;
import com.regula.documentreader.api.params.ParamsCustomization;
import com.regula.documentreader.api.params.ProcessParam;
import com.regula.documentreader.api.enums.BarcodeType;
import com.regula.documentreader.api.params.rfid.dg.DataGroups;

import android.widget.ImageView.ScaleType;
import android.graphics.Typeface;
import android.graphics.Matrix;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.Objects;

// You can read more about each these settings at 
// https://github.com/regulaforensics/DocumentReader-Android/wiki/Custom-settings

class RegulaConfig {

    private static float[] extractFloatArray(ReadableArray readableArray) {
        float[] result = new float[readableArray.size()];
        for (int i = 0; i < readableArray.size(); i++)
            result[i] = (float) readableArray.getDouble(i);
        return result;
    }

    static void setConfig(DocumentReader reader, ReadableMap opts) {
        if (opts.hasKey("customization"))
            setCustomization(reader.customization(), Objects.requireNonNull(opts.getMap("customization")));
        if (opts.hasKey("functionality"))
            setFunctionality(reader.functionality(), Objects.requireNonNull(opts.getMap("functionality")));
        if (opts.hasKey("processParams")) {
            JSONObject params = convertMapToJson(Objects.requireNonNull(opts.getMap("processParams")));
            if (params.has("logs")) {
                try {
                    params.put("log", params.optBoolean("logs"));
                    params.remove("logs");
                } catch (JSONException ignored) {
                }
            }
            if (params.has("barcodeTypes")) {
                try {
                    JSONArray arr = params.optJSONArray("barcodeTypes");
                    JSONArray newArr = new JSONArray();
                    for (int i = 0; i < arr.length(); i++) {
                        newArr.put(BarcodeType.valueOf(arr.getInt(i)));
                    }
                    params.put("doBarcodes", newArr);
                    params.remove("barcodeTypes");
                } catch (JSONException ignored) {
                }
            }
            if (params.has("documentIDList")) {
                try {
                    params.put("documentIdList", params.optJSONArray("documentIDList"));
                    params.remove("documentIDList");
                } catch (JSONException ignored) {
                }
            }
            reader.processParams().fromJson(params.toString());
        }
    }

    static JSONObject getConfig(DocumentReader reader) {
        JSONObject object = new JSONObject();
        try {
            object.put("customization", getCustomization(reader.customization()));
            object.put("functionality", getFunctionality(reader.functionality()));
            object.put("processParams", getProcessParams(reader.processParams()));
        } catch (JSONException ignored) {
        }

        return object;
    }

    private static void setFunctionality(Functionality functionality, ReadableMap opts) {
        if (opts.hasKey("pictureOnBoundsReady"))
            functionality.setPictureOnBoundsReady(opts.getBoolean("pictureOnBoundsReady"));
        if (opts.hasKey("showTorchButton"))
            functionality.setShowTorchButton(opts.getBoolean("showTorchButton"));
        if (opts.hasKey("showCloseButton"))
            functionality.setShowCloseButton(opts.getBoolean("showCloseButton"));
        if (opts.hasKey("videoCaptureMotionControl"))
            functionality.setVideoCaptureMotionControl(opts.getBoolean("videoCaptureMotionControl"));
        if (opts.hasKey("showCaptureButton"))
            functionality.setShowCaptureButton(opts.getBoolean("showCaptureButton"));
        if (opts.hasKey("showChangeFrameButton"))
            functionality.setShowChangeFrameButton(opts.getBoolean("showChangeFrameButton"));
        if (opts.hasKey("showCaptureButtonDelayFromDetect"))
            functionality.setShowCaptureButtonDelayFromDetect(opts.getInt("showCaptureButtonDelayFromDetect"));
        if (opts.hasKey("showCaptureButtonDelayFromStart"))
            functionality.setShowCaptureButtonDelayFromStart(opts.getInt("showCaptureButtonDelayFromStart"));
        if (opts.hasKey("isOnlineMode"))
            functionality.setOnlineMode(opts.getBoolean("isOnlineMode"));
        if (opts.hasKey("databaseAutoupdate"))
            functionality.setDatabaseAutoupdate(opts.getBoolean("databaseAutoupdate"));
        if (opts.hasKey("showSkipNextPageButton"))
            functionality.setShowSkipNextPageButton(opts.getBoolean("showSkipNextPageButton"));
        if (opts.hasKey("useAuthenticator"))
            functionality.setUseAuthenticator(opts.getBoolean("useAuthenticator"));
        if (opts.hasKey("skipFocusingFrames"))
            functionality.setSkipFocusingFrames(opts.getBoolean("skipFocusingFrames"));
        if (opts.hasKey("showCameraSwitchButton"))
            functionality.setShowCameraSwitchButton(opts.getBoolean("showCameraSwitchButton"));
        if (opts.hasKey("cameraFrame"))
            functionality.setCameraFrame(opts.getString("cameraFrame"));
        if (opts.hasKey("serviceURL"))
            functionality.setServiceURL(opts.getString("serviceURL"));
        if (opts.hasKey("databaseIdentifier"))
            functionality.setDatabaseIdentifier(opts.getString("databaseIdentifier"));
        if (opts.hasKey("btDeviceName"))
            functionality.setBtDeviceName(opts.getString("btDeviceName"));
        if (opts.hasKey("orientation"))
            functionality.setOrientation(opts.getInt("orientation"));
    }

    private static void setCustomization(ParamsCustomization customization, ReadableMap opts) {
        ParamsCustomization.CustomizationEditor editor = customization.edit();
        if (opts.hasKey("status"))
            editor.setStatus(opts.getString("status"));
        if (opts.hasKey("resultStatus"))
            editor.setResultStatus(opts.getString("resultStatus"));
        if (opts.hasKey("cameraFrameDefaultColor"))
            editor.setCameraFrameDefaultColor(opts.getString("cameraFrameDefaultColor"));
        if (opts.hasKey("cameraFrameActiveColor"))
            editor.setCameraFrameActiveColor(opts.getString("cameraFrameActiveColor"));
        if (opts.hasKey("statusTextColor"))
            editor.setStatusTextColor(opts.getString("statusTextColor"));
        if (opts.hasKey("resultStatusTextColor"))
            editor.setResultStatusTextColor(opts.getString("resultStatusTextColor"));
        if (opts.hasKey("resultStatusBackgroundColor"))
            editor.setResultStatusBackgroundColor(opts.getString("resultStatusBackgroundColor"));
        if (opts.hasKey("multipageButtonBackgroundColor"))
            editor.setMultipageButtonBackgroundColor(opts.getString("multipageButtonBackgroundColor"));
        if (opts.hasKey("tintColor"))
            editor.setTintColor(opts.getString("tintColor"));
        if (opts.hasKey("activityIndicatorColor"))
            editor.setActivityIndicatorColor(opts.getString("activityIndicatorColor"));
        if (opts.hasKey("showStatusMessages"))
            editor.setShowStatusMessages(opts.getBoolean("showStatusMessages"));
        if (opts.hasKey("showResultStatusMessages"))
            editor.setShowResultStatusMessages(opts.getBoolean("showResultStatusMessages"));
        if (opts.hasKey("showHelpAnimation"))
            editor.setShowHelpAnimation(opts.getBoolean("showHelpAnimation"));
        if (opts.hasKey("showNextPageAnimation"))
            editor.setShowNextPageAnimation(opts.getBoolean("showNextPageAnimation"));
        if (opts.hasKey("showBackgroundMask"))
            editor.setShowBackgroundMask(opts.getBoolean("showBackgroundMask"));
        if (opts.hasKey("cameraFrameBorderWidth"))
            editor.setCameraFrameBorderWidth(opts.getInt("cameraFrameBorderWidth"));
        if (opts.hasKey("statusTextSize"))
            editor.setStatusTextSize(opts.getInt("statusTextSize"));
        if (opts.hasKey("cameraFrameLineLength"))
            editor.setCameraFrameLineLength(opts.getInt("cameraFrameLineLength"));
        if (opts.hasKey("cameraFrameShapeType"))
            editor.setCameraFrameShapeType(opts.getInt("cameraFrameShapeType"));
        if (opts.hasKey("resultStatusTextSize"))
            editor.setResultStatusTextSize(opts.getInt("resultStatusTextSize"));
        if (opts.hasKey("helpAnimationImageID"))
            editor.setHelpAnimationImageID(opts.getInt("helpAnimationImageID"));
        if (opts.hasKey("multipageAnimationFrontImage"))
            editor.setMultipageAnimationFrontImage(opts.getInt("multipageAnimationFrontImage"));
        if (opts.hasKey("multipageAnimationBackImage"))
            editor.setMultipageAnimationBackImage(opts.getInt("multipageAnimationBackImage"));
        if (opts.hasKey("borderBackgroundImage"))
            editor.setBorderBackgroundImage(opts.getInt("borderBackgroundImage"));
        if (opts.hasKey("statusPositionMultiplier"))
            editor.setStatusPositionMultiplier(opts.getDouble("statusPositionMultiplier"));
        if (opts.hasKey("resultStatusPositionMultiplier"))
            editor.setResultStatusPositionMultiplier(opts.getDouble("resultStatusPositionMultiplier"));
        if (opts.hasKey("backgroundMaskAlpha"))
            editor.setBackgroundMaskAlpha((float) opts.getDouble("backgroundMaskAlpha"));
        if (opts.hasKey("statusTextFont"))
            if (opts.hasKey("statusTextFontStyle"))
                editor.setStatusTextFont(Typeface.create(opts.getString("statusTextFont"), opts.getInt("statusTextFontStyle")));
            else
                editor.setStatusTextFont(Typeface.create(opts.getString("statusTextFont"), Typeface.NORMAL));
        if (opts.hasKey("resultStatusTextFont"))
            if (opts.hasKey("resultStatusTextFontStyle"))
                editor.setResultStatusTextFont(Typeface.create(opts.getString("resultStatusTextFont"), opts.getInt("resultStatusTextFontStyle")));
            else
                editor.setResultStatusTextFont(Typeface.create(opts.getString("resultStatusTextFont"), Typeface.NORMAL));
        if (opts.hasKey("helpAnimationImageScaleType"))
            editor.setHelpAnimationImageScaleType(ScaleType.valueOf(opts.getString("helpAnimationImageScaleType")));
        if (opts.hasKey("multipageAnimationFrontImageScaleType"))
            editor.setMultipageAnimationFrontImageScaleType(
                    ScaleType.valueOf(opts.getString("multipageAnimationFrontImageScaleType")));
        if (opts.hasKey("multipageAnimationBackImageScaleType"))
            editor.setMultipageAnimationBackImageScaleType(
                    ScaleType.valueOf(opts.getString("multipageAnimationBackImageScaleType")));
        if (opts.hasKey("helpAnimationImageMatrix")) {
            Matrix matrix = new Matrix();
            matrix.setValues(extractFloatArray(Objects.requireNonNull(opts.getArray("helpAnimationImageMatrix"))));
            editor.setHelpAnimationImageMatrix(matrix);
        }
        if (opts.hasKey("multipageAnimationFrontImageMatrix")) {
            Matrix matrix = new Matrix();
            matrix.setValues(extractFloatArray(Objects.requireNonNull(opts.getArray("multipageAnimationFrontImageMatrix"))));
            editor.setMultipageAnimationFrontImageMatrix(matrix);
        }
        if (opts.hasKey("multipageAnimationBackImageMatrix")) {
            Matrix matrix = new Matrix();
            matrix.setValues(extractFloatArray(Objects.requireNonNull(opts.getArray("multipageAnimationBackImageMatrix"))));
            editor.setMultipageAnimationBackImageMatrix(matrix);
        }
        editor.apply();
    }

    private static JSONObject getFunctionality(Functionality functionality) {
        JSONObject object = new JSONObject();
        try {
            object.put("pictureOnBoundsReady", functionality.isPictureOnBoundsReady());
            object.put("showTorchButton", functionality.isShowTorchButton());
            object.put("showCloseButton", functionality.isShowCloseButton());
            object.put("videoCaptureMotionControl", functionality.isVideoCaptureMotionControl());
            object.put("showCaptureButton", functionality.isShowCaptureButton());
            object.put("showChangeFrameButton", functionality.isShowChangeFrameButton());
            object.put("showCaptureButtonDelayFromDetect", functionality.getShowCaptureButtonDelayFromDetect());
            object.put("showCaptureButtonDelayFromStart", functionality.getShowCaptureButtonDelayFromStart());
            object.put("isOnlineMode", functionality.isOnlineMode());
            object.put("databaseAutoupdate", functionality.isDatabaseAutoupdate());
            object.put("showSkipNextPageButton", functionality.isShowSkipNextPageButton());
            object.put("useAuthenticator", functionality.isUseAuthenticator());
            object.put("skipFocusingFrames", functionality.isSkipFocusingFrames());
            object.put("showCameraSwitchButton", functionality.isShowCameraSwitchButton());
            object.put("cameraFrame", functionality.getCameraFrame());
            object.put("serviceURL", functionality.getServiceURL());
            object.put("databaseIdentifier", functionality.getDatabaseIdentifier());
            object.put("btDeviceName", functionality.getBtDeviceName());
            object.put("orientation", functionality.getOrientation());
        } catch (JSONException ignored) {
        }

        return object;
    }

    private static JSONObject getCustomization(ParamsCustomization customization) {
        JSONObject object = new JSONObject();
        try {
            object.put("status", customization.getStatus());
            object.put("resultStatus", customization.getResultStatus());
            object.put("cameraFrameDefaultColor", customization.getCameraFrameDefaultColor());
            object.put("cameraFrameActiveColor", customization.getCameraFrameActiveColor());
            object.put("statusTextColor", customization.getStatusTextColor());
            object.put("resultStatusTextColor", customization.getResultStatusTextColor());
            object.put("resultStatusBackgroundColor", customization.getResultStatusBackgroundColor());
            object.put("multipageButtonBackgroundColor", customization.getMultipageButtonBackgroundColor());
            object.put("tintColor", customization.getTintColor());
            object.put("activityIndicatorColor", customization.getActivityIndicatorColor());
            object.put("showStatusMessages", customization.isShowStatusMessages());
            object.put("showResultStatusMessages", customization.isShowResultStatusMessages());
            object.put("showHelpAnimation", customization.isShowHelpAnimation());
            object.put("showNextPageAnimation", customization.isShowNextPageAnimation());
            object.put("showBackgroundMask", customization.isShowBackgroundMask());
            object.put("cameraFrameBorderWidth", customization.getCameraFrameBorderWidth());
            object.put("statusTextSize", customization.getStatusTextSize());
            object.put("cameraFrameLineLength", customization.getCameraFrameLineLength());
            object.put("cameraFrameShapeType", customization.getCameraFrameShapeType());
            object.put("resultStatusTextSize", customization.getResultStatusTextSize());
            object.put("helpAnimationImageID", customization.getHelpAnimationImageID());
            object.put("multipageAnimationFrontImage", customization.getMultipageAnimationFrontImage());
            object.put("multipageAnimationBackImage", customization.getMultipageAnimationBackImage());
            object.put("borderBackgroundImage", customization.getBorderBackgroundImage());
            object.put("helpAnimationImageScaleType", customization.getHelpAnimationImageScaleType());
            object.put("multipageAnimationFrontImageScaleType", customization.getMultipageAnimationFrontImageScaleType());
            object.put("multipageAnimationBackImageScaleType", customization.getMultipageAnimationBackImageScaleType());
            object.put("helpAnimationImageMatrix", customization.getHelpAnimationImageMatrix());
            object.put("multipageAnimationFrontImageMatrix", customization.getMultipageAnimationFrontImageMatrix());
            object.put("multipageAnimationBackImageMatrix", customization.getMultipageAnimationBackImageMatrix());
            object.put("statusTextFont", customization.getStatusTextFont());
            object.put("resultStatusTextFont", customization.getResultStatusTextFont());
            object.put("statusPositionMultiplier", customization.getStatusPositionMultiplier());
            object.put("resultStatusPositionMultiplier", customization.getResultStatusPositionMultiplier());
            object.put("backgroundMaskAlpha", customization.getBackgroundMaskAlpha());
        } catch (JSONException ignored) {
        }

        return object;
    }

    private static JSONObject getProcessParams(ProcessParam processParams) {
        JSONObject object = new JSONObject();
        try {
            object.put("scenario", processParams.scenario);
            object.put("measureSystem", processParams.measureSystem);
            object.put("uvTorchEnabled", processParams.uvTorchEnabled);
            object.put("debugSaveImages", true);
            object.put("debugSaveLogs", processParams.debugSaveLogs);
            object.put("multipageProcessing", processParams.multipageProcessing);
            object.put("dateFormat", processParams.dateFormat);
            object.put("debugSaveCroppedImages", processParams.debugSaveCroppedImages);
            object.put("sessionLogFolder", processParams.sessionLogFolder);
            object.put("disableFocusingCheck", processParams.disableFocusingCheck);
            object.put("captureButtonScenario", processParams.captureButtonScenario);
            object.put("returnUncroppedImage", processParams.returnUncroppedImage);
            if (processParams.customParams != null)
                object.put("customParams", processParams.customParams.toString());
            else
                object.put("customParams", new JSONArray());

            JSONArray jdocumentIDList = new JSONArray();
            if (processParams.documentIDList != null && processParams.documentIDList.length > 0) {
                int index = 0;
                for (int item : processParams.documentIDList) {
                    jdocumentIDList.put(index, item);
                    index++;
                }
            }
            object.put("documentIDList", jdocumentIDList);

            JSONArray jdoBarcodes = new JSONArray();
            if (processParams.doBarcodes != null && processParams.doBarcodes.length > 0) {
                int index = 0;
                for (String item : processParams.doBarcodes) {
                    jdoBarcodes.put(index, item);
                    index++;
                }
            }
            object.put("barcodeTypes", jdoBarcodes);

            JSONArray jfieldTypesFilter = new JSONArray();
            if (processParams.fieldTypesFilter != null && processParams.fieldTypesFilter.length > 0) {
                int index = 0;
                for (int item : processParams.fieldTypesFilter) {
                    jfieldTypesFilter.put(index, item);
                    index++;
                }
            }
            object.put("fieldTypesFilter", jfieldTypesFilter);
        } catch (Exception ignored) {
        }
        return object;
    }

    static void setRfidScenario(ReadableMap opts) {
        if (opts.hasKey("paceStaticBinding"))
            DocumentReader.Instance().rfidScenario().setPaceStaticBinding(opts.getBoolean("PACE_StaticBinding"));
        if (opts.hasKey("signManagementAction"))
            DocumentReader.Instance().rfidScenario().setSignManagementAction(opts.getInt("signManagementAction"));
        if (opts.hasKey("readingBuffer"))
            DocumentReader.Instance().rfidScenario().setReadingBuffer(opts.getInt("readingBuffer"));
        if (opts.hasKey("onlineTAToSignDataType"))
            DocumentReader.Instance().rfidScenario().setOnlineTAToSignDataType(opts.getInt("onlineTAToSignDataType"));
        if (opts.hasKey("onlineTA"))
            DocumentReader.Instance().rfidScenario().setOnlineTA(opts.getBoolean("onlineTA"));
        if (opts.hasKey("writeEid"))
            DocumentReader.Instance().rfidScenario().setWriteEid(opts.getBoolean("writeEid"));
        if (opts.hasKey("profilerType"))
            DocumentReader.Instance().rfidScenario().setProfilerType(opts.getInt("profilerType"));
        if (opts.hasKey("authProcType"))
            DocumentReader.Instance().rfidScenario().setAuthProcType(opts.getInt("authProcType"));
        if (opts.hasKey("baseSMProcedure"))
            DocumentReader.Instance().rfidScenario().setBaseSMProcedure(opts.getInt("baseSMProcedure"));
        if (opts.hasKey("pacePasswordType"))
            DocumentReader.Instance().rfidScenario().setPacePasswordType(opts.getInt("pacePasswordType"));
        if (opts.hasKey("terminalType"))
            DocumentReader.Instance().rfidScenario().setTerminalType(opts.getInt("terminalType"));
        if (opts.hasKey("universalAccessRights"))
            DocumentReader.Instance().rfidScenario().setUniversalAccessRights(opts.getBoolean("universalAccessRights"));
        if (opts.hasKey("authorizedRestrictedIdentification"))
            DocumentReader.Instance().rfidScenario().setAuthorizedRestrictedIdentification(opts.getBoolean("authorizedRestrictedIdentification"));
        if (opts.hasKey("auxVerificationCommunityID"))
            DocumentReader.Instance().rfidScenario().setAuxVerificationCommunityID(opts.getBoolean("auxVerificationCommunityID"));
        if (opts.hasKey("auxVerificationDateOfBirth"))
            DocumentReader.Instance().rfidScenario().setAuxVerificationDateOfBirth(opts.getBoolean("auxVerificationDateOfBirth"));
        if (opts.hasKey("skipAA"))
            DocumentReader.Instance().rfidScenario().setSkipAA(opts.getBoolean("skipAA"));
        if (opts.hasKey("strictProcessing"))
            DocumentReader.Instance().rfidScenario().setStrictProcessing(opts.getBoolean("strictProcessing"));
        if (opts.hasKey("pkdDSCertPriority"))
            DocumentReader.Instance().rfidScenario().setPkdDSCertPriority(opts.getBoolean("pkdDSCertPriority"));
        if (opts.hasKey("pkdUseExternalCSCA"))
            DocumentReader.Instance().rfidScenario().setPkdUseExternalCSCA(opts.getBoolean("pkdUseExternalCSCA"));
        if (opts.hasKey("trustedPKD"))
            DocumentReader.Instance().rfidScenario().setTrustedPKD(opts.getBoolean("trustedPKD"));
        if (opts.hasKey("passiveAuth"))
            DocumentReader.Instance().rfidScenario().setPassiveAuth(opts.getBoolean("passiveAuth"));
        if (opts.hasKey("password"))
            DocumentReader.Instance().rfidScenario().setPassword(opts.getString("password"));
        if (opts.hasKey("useSFI"))
            DocumentReader.Instance().rfidScenario().setUseSFI(opts.getBoolean("useSFI"));
        if (opts.hasKey("pkdPA"))
            DocumentReader.Instance().rfidScenario().setPkdPA(opts.getString("pkdPA"));
        if (opts.hasKey("pkdEAC"))
            DocumentReader.Instance().rfidScenario().setPkdEAC(opts.getString("pkdEAC"));
        if (opts.hasKey("readEPassport"))
            DocumentReader.Instance().rfidScenario().setReadEPassport(opts.getBoolean("readEPassport"));
        if (opts.hasKey("readEID"))
            DocumentReader.Instance().rfidScenario().setReadEID(opts.getBoolean("readEID"));
        if (opts.hasKey("readEDL"))
            DocumentReader.Instance().rfidScenario().setReadEDL(opts.getBoolean("readEDL"));
        if (opts.hasKey("mrz"))
            DocumentReader.Instance().rfidScenario().setMrz(opts.getString("mrz"));
        if (opts.hasKey("eSignPINDefault"))
            DocumentReader.Instance().rfidScenario().seteSignPINDefault(opts.getString("eSignPINDefault"));
        if (opts.hasKey("eSignPINNewValue"))
            DocumentReader.Instance().rfidScenario().seteSignPINNewValue(opts.getString("eSignPINNewValue"));
        if (opts.hasKey("authorizedSTSignature"))
            DocumentReader.Instance().rfidScenario().setAuthorizedSTSignature(opts.getBoolean("authorizedSTSignature"));
        if (opts.hasKey("authorizedSTQSignature"))
            DocumentReader.Instance().rfidScenario().setAuthorizedSTQSignature(opts.getBoolean("authorizedSTQSignature"));
        if (opts.hasKey("authorizedWriteDG17"))
            DocumentReader.Instance().rfidScenario().setAuthorizedWriteDG17(opts.getBoolean("authorizedWriteDG17"));
        if (opts.hasKey("authorizedWriteDG18"))
            DocumentReader.Instance().rfidScenario().setAuthorizedWriteDG18(opts.getBoolean("authorizedWriteDG18"));
        if (opts.hasKey("authorizedWriteDG19"))
            DocumentReader.Instance().rfidScenario().setAuthorizedWriteDG19(opts.getBoolean("authorizedWriteDG19"));
        if (opts.hasKey("authorizedWriteDG20"))
            DocumentReader.Instance().rfidScenario().setAuthorizedWriteDG20(opts.getBoolean("authorizedWriteDG20"));
        if (opts.hasKey("authorizedWriteDG21"))
            DocumentReader.Instance().rfidScenario().setAuthorizedWriteDG21(opts.getBoolean("authorizedWriteDG21"));
        if (opts.hasKey("authorizedVerifyAge"))
            DocumentReader.Instance().rfidScenario().setAuthorizedVerifyAge(opts.getBoolean("authorizedVerifyAge"));
        if (opts.hasKey("authorizedVerifyCommunityID"))
            DocumentReader.Instance().rfidScenario().setAuthorizedVerifyCommunityID(opts.getBoolean("authorizedVerifyCommunityID"));
        if (opts.hasKey("authorizedPrivilegedTerminal"))
            DocumentReader.Instance().rfidScenario().setAuthorizedPrivilegedTerminal(opts.getBoolean("authorizedPrivilegedTerminal"));
        if (opts.hasKey("authorizedCANAllowed"))
            DocumentReader.Instance().rfidScenario().setAuthorizedCANAllowed(opts.getBoolean("authorizedCANAllowed"));
        if (opts.hasKey("authorizedPINManagement"))
            DocumentReader.Instance().rfidScenario().setAuthorizedPINManagment(opts.getBoolean("authorizedPINManagement"));
        if (opts.hasKey("authorizedInstallCert"))
            DocumentReader.Instance().rfidScenario().setAuthorizedInstallCert(opts.getBoolean("authorizedInstallCert"));
        if (opts.hasKey("authorizedInstallQCert"))
            DocumentReader.Instance().rfidScenario().setAuthorizedInstallQCert(opts.getBoolean("authorizedInstallQCert"));
        if (opts.hasKey("ePassportDataGroups"))
            setDataGroups(DocumentReader.Instance().rfidScenario().ePassportDataGroups(), Objects.requireNonNull(opts.getMap("ePassportDataGroups")));
        if (opts.hasKey("eIDDataGroups"))
            setDataGroups(DocumentReader.Instance().rfidScenario().eIDDataGroups(), Objects.requireNonNull(opts.getMap("eIDDataGroups")));
        if (opts.hasKey("eDLDataGroups"))
            setDataGroups(DocumentReader.Instance().rfidScenario().eDLDataGroups(), Objects.requireNonNull(opts.getMap("eDLDataGroups")));
    }

    private static void setDataGroups(DataGroups dataGroup, ReadableMap opts) {
        if (opts.hasKey("DG1"))
            dataGroup.setDG1(opts.getBoolean("DG1"));
        if (opts.hasKey("DG2"))
            dataGroup.setDG2(opts.getBoolean("DG2"));
        if (opts.hasKey("DG3"))
            dataGroup.setDG3(opts.getBoolean("DG3"));
        if (opts.hasKey("DG4"))
            dataGroup.setDG4(opts.getBoolean("DG4"));
        if (opts.hasKey("DG5"))
            dataGroup.setDG5(opts.getBoolean("DG5"));
        if (opts.hasKey("DG6"))
            dataGroup.setDG6(opts.getBoolean("DG6"));
        if (opts.hasKey("DG7"))
            dataGroup.setDG7(opts.getBoolean("DG7"));
        if (opts.hasKey("DG8"))
            dataGroup.setDG8(opts.getBoolean("DG8"));
        if (opts.hasKey("DG9"))
            dataGroup.setDG9(opts.getBoolean("DG9"));
        if (opts.hasKey("DG10"))
            dataGroup.setDG10(opts.getBoolean("DG10"));
        if (opts.hasKey("DG11"))
            dataGroup.setDG11(opts.getBoolean("DG11"));
        if (opts.hasKey("DG12"))
            dataGroup.setDG12(opts.getBoolean("DG12"));
        if (opts.hasKey("DG13"))
            dataGroup.setDG13(opts.getBoolean("DG13"));
        if (opts.hasKey("DG14"))
            dataGroup.setDG14(opts.getBoolean("DG14"));
    }

    private static JSONObject convertMapToJson(ReadableMap readableMap) {
        JSONObject object = new JSONObject();
        try {
            ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
            while (iterator.hasNextKey()) {
                String key = iterator.nextKey();
                switch (readableMap.getType(key)) {
                    case Null:
                        object.put(key, JSONObject.NULL);
                        break;
                    case Boolean:
                        object.put(key, readableMap.getBoolean(key));
                        break;
                    case Number:
                        object.put(key, readableMap.getDouble(key));
                        break;
                    case String:
                        object.put(key, readableMap.getString(key));
                        break;
                    case Map:
                        object.put(key, convertMapToJson(Objects.requireNonNull(readableMap.getMap(key))));
                        break;
                    case Array:
                        object.put(key, convertArrayToJson(Objects.requireNonNull(readableMap.getArray(key))));
                        break;
                }
            }
        } catch (JSONException ignored) {
        }

        return object;
    }

    private static JSONArray convertArrayToJson(ReadableArray readableArray) {
        JSONArray array = new JSONArray();
        try {
            for (int i = 0; i < readableArray.size(); i++) {
                switch (readableArray.getType(i)) {
                    case Null:
                        break;
                    case Boolean:
                        array.put(readableArray.getBoolean(i));
                        break;
                    case Number:
                        array.put(readableArray.getDouble(i));
                        break;
                    case String:
                        array.put(readableArray.getString(i));
                        break;
                    case Map:
                        array.put(convertMapToJson(Objects.requireNonNull(readableArray.getMap(i))));
                        break;
                    case Array:
                        array.put(convertArrayToJson(Objects.requireNonNull(readableArray.getArray(i))));
                        break;
                }
            }
        } catch (JSONException ignored) {
        }

        return array;
    }
}