class MraidBridge {

    @VisibleForTesting
    void runCommand(@NonNull final MraidJavascriptCommand command,
            @NonNull Map<String, String> params)
            throws MraidCommandException {
        if (command.requiresClick(mPlacementType) && !mIsClicked) {
            throw new MraidCommandException("Cannot execute this command unless the user clicks");
        }

        if (mMraidBridgeListener == null) {
            throw new MraidCommandException("Invalid state to execute this command");
        }

        if (mMraidWebView == null) {
            throw new MraidCommandException("The current WebView is being destroyed");
        }

        switch (command) {
            case CLOSE:
                mMraidBridgeListener.onClose();
                break;
            case RESIZE:
                // All these params are required
                int width = checkRange(parseSize(params.get("width")), 0, 100000);
                int height = checkRange(parseSize(params.get("height")), 0, 100000);
                int offsetX = checkRange(parseSize(params.get("offsetX")), -100000, 100000);
                int offsetY = checkRange(parseSize(params.get("offsetY")), -100000, 100000);
                ClosePosition closePosition = parseClosePosition(
                        params.get("customClosePosition"), ClosePosition.TOP_RIGHT);
                boolean allowOffscreen = parseBoolean(params.get("allowOffscreen"), true);
                mMraidBridgeListener.onResize(
                        width, height, offsetX, offsetY, closePosition, allowOffscreen);
                break;
            case EXPAND:
                URI uri = parseURI(params.get("url"), null);
                boolean shouldUseCustomClose = parseBoolean(params.get("shouldUseCustomClose"),
                        false);
                mMraidBridgeListener.onExpand(uri, shouldUseCustomClose);
                break;
            case USE_CUSTOM_CLOSE:
                shouldUseCustomClose = parseBoolean(params.get("shouldUseCustomClose"), false);
                mMraidBridgeListener.onUseCustomClose(shouldUseCustomClose);
                break;
            case OPEN:
                uri = parseURI(params.get("url"));
                mMraidBridgeListener.onOpen(uri);
                break;
            case SET_ORIENTATION_PROPERTIES:
                boolean allowOrientationChange = parseBoolean(params.get("allowOrientationChange"));
                MraidOrientation forceOrientation = parseOrientation(params.get("forceOrientation"));

                mMraidBridgeListener.onSetOrientationProperties(allowOrientationChange,
                        forceOrientation);
                break;
            case PLAY_VIDEO:
                uri = parseURI(params.get("uri"));
                mMraidBridgeListener.onPlayVideo(uri);
                break;
            case STORE_PICTURE:
                uri = parseURI(params.get("uri"));
                mMraidNativeCommandHandler.storePicture(mMraidWebView.getContext(), uri.toString(),
                        new MraidCommandFailureListener() {
                            @Override
                            public void onFailure(final MraidCommandException exception) {
                                fireErrorEvent(command, exception.getMessage());
                            }
                        });
                break;

            case CREATE_CALENDAR_EVENT:
                mMraidNativeCommandHandler.createCalendarEvent(mMraidWebView.getContext(), params);
                break;
            case UNSPECIFIED:
                throw new MraidCommandException("Unspecified MRAID Javascript command");
        }
    }

      MraidBridge(@NonNull AdConfiguration adConfiguration,
            @NonNull PlacementType placementType);
    @VisibleForTesting  MraidBridge(@NonNull AdConfiguration adConfiguration,
            @NonNull PlacementType placementType,
            @NonNull MraidNativeCommandHandler mraidNativeCommandHandler);

}