// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { MessageBarType } from '@fluentui/react';
import { _formatString } from "../../../acs-ui-common/src";
/**
 * @private
 *
 * @param fileName
 * @param length
 * @returns string
 */
export const truncatedFileName = (fileName, length) => {
    return fileName.substring(0, length).trimEnd() + (fileName.length > length ? '... ' : '');
};
/**
 * @private
 *
 * @param fileName
 * @returns string
 */
export const extension = (fileName) => fileName.split('.').pop() || '';
/**
 * @private
 * @param dismissedErrors
 * @param toDismiss
 * @returns DismissedError[]
 * Always returns a new Array so that the state variable is updated, trigerring a render.
 */
export const dismissError = (dismissedErrors, toDismiss) => {
    var _a;
    const now = new Date(Date.now());
    for (const error of dismissedErrors) {
        if (error.type === toDismiss.type) {
            // Bump the timestamp for latest dismissal of this error to now.
            error.dismissedAt = now;
            error.activeSince = toDismiss.timestamp;
            return Array.from(dismissedErrors);
        }
    }
    const toDismissTimestamp = (_a = toDismiss.timestamp) !== null && _a !== void 0 ? _a : now;
    // Record that this error was dismissed for the first time right now.
    return [...dismissedErrors, {
            type: toDismiss.type,
            // the error time could be sometimes later than the button click time, which cause the dismiss not working
            // so we set the dismiss time to the later one
            dismissedAt: now > toDismissTimestamp ? now : toDismissTimestamp,
            activeSince: toDismiss.timestamp
        }];
};
/**
 * @private
 * @param activeErrorMessages
 * @param dismissedErrors
 * @returns DismissedError[]
 *  Returns a new Array if and only if contents change, to avoid re-rendering when nothing was dropped.
 */
export const dropDismissalsForInactiveErrors = (activeErrorMessages, dismissedErrors) => {
    const active = new Map();
    for (const message of activeErrorMessages) {
        active.set(message.type, message);
    }
    // For an error such that:
    // * It was previously active, and dismissed.
    // * It did not have a timestamp associated with it.
    // * It is no longer active.
    //
    // We remove it from dismissals. When it becomes active again next time, it will be shown again on the UI.
    const shouldDeleteDismissal = (dismissed) => dismissed.activeSince === undefined && active.get(dismissed.type) === undefined;
    if (dismissedErrors.some(dismissed => shouldDeleteDismissal(dismissed))) {
        return dismissedErrors.filter(dismissed => !shouldDeleteDismissal(dismissed));
    }
    return dismissedErrors;
};
/**
 * @private
 * @param dismissedNotifications
 * @param toDismiss
 * @returns DismissedNotification[]
 * Always returns a new Array so that the state variable is updated, trigerring a render.
 */
export const dismissNotification = (dismissedNotifications, toDismiss) => {
    var _a;
    const now = new Date(Date.now());
    for (const notification of dismissedNotifications) {
        if (notification.type === toDismiss.type) {
            // Bump the timestamp for latest dismissal of this error to now.
            notification.dismissedAt = now;
            notification.activeSince = toDismiss.timestamp;
            return Array.from(dismissedNotifications);
        }
    }
    const toDismissTimestamp = (_a = toDismiss.timestamp) !== null && _a !== void 0 ? _a : now;
    // Record that this error was dismissed for the first time right now.
    return [...dismissedNotifications, {
            type: toDismiss.type,
            // the error time could be sometimes later than the button click time, which cause the dismiss not working
            // so we set the dismiss time to the later one
            dismissedAt: now > toDismissTimestamp ? now : toDismissTimestamp,
            activeSince: toDismiss.timestamp
        }];
};
/**
 * @private
 * @param activeNotifications
 * @param dismissedNotifications
 * @returns DismissedError[]
 *  Returns a new Array if and only if contents change, to avoid re-rendering when nothing was dropped.
 */
export const dropDismissalsForInactiveNotifications = (activeNotifications, dismissedNotifications) => {
    const active = new Map();
    for (const message of activeNotifications) {
        active.set(message.type, message);
    }
    // For an error such that:
    // * It was previously active, and dismissed.
    // * It did not have a timestamp associated with it.
    // * It is no longer active.
    //
    // We remove it from dismissals. When it becomes active again next time, it will be shown again on the UI.
    const shouldDeleteDismissal = (dismissed) => dismissed.activeSince === undefined && active.get(dismissed.type) === undefined;
    if (dismissedNotifications.some(dismissed => shouldDeleteDismissal(dismissed))) {
        return dismissedNotifications.filter(dismissed => !shouldDeleteDismissal(dismissed));
    }
    return dismissedNotifications;
};
/**
 * @private
 * @param activeErrorMessages
 * @param dismissedErrors
 * @returns ActiveErrorMessage[]
 */
export const errorsToShow = (activeErrorMessages, dismissedErrors, mountTimestamp) => {
    const dismissed = new Map();
    for (const error of dismissedErrors) {
        dismissed.set(error.type, error);
    }
    return activeErrorMessages.filter(error => {
        if (mountTimestamp && error.timestamp && mountTimestamp > error.timestamp) {
            // Error has a timestamp and it is older than when the component was mounted.
            return false;
        }
        const dismissal = dismissed.get(error.type);
        if (!dismissal) {
            // This error was never dismissed.
            return true;
        }
        if (!error.timestamp) {
            // No timestamp associated with the error. In this case, the existence of a dismissal is enough to suppress the error.
            return false;
        }
        // Error has an associated timestamp, so compare with last dismissal.
        return error.timestamp > dismissal.dismissedAt;
    });
};
/**
 * @private
 * @param activeNotifications
 * @param dismissedNotifications
 * @returns ActiveNotification[]
 */
export const notificationsToShow = (activeNotifications, dismissedNotifications, mountTimestamp) => {
    const dismissed = new Map();
    for (const notification of dismissedNotifications) {
        dismissed.set(notification.type, notification);
    }
    return activeNotifications.filter(notification => {
        if (mountTimestamp && notification.timestamp && mountTimestamp > notification.timestamp) {
            // Notification has a timestamp and it is older than when the component was mounted.
            return false;
        }
        const dismissal = dismissed.get(notification.type);
        if (!dismissal) {
            // This error was never dismissed.
            return true;
        }
        if (!notification.timestamp) {
            // No timestamp associated with the error. In this case, the existence of a dismissal is enough to suppress the error.
            return false;
        }
        // Error has an associated timestamp, so compare with last dismissal.
        return notification.timestamp > dismissal.dismissedAt;
    });
};
/**
 * @private
 * @param errorType
 * @returns MessageBarType
 */
export const messageBarType = (errorType) => {
    switch (errorType) {
        case 'callNetworkQualityLow':
        case 'callNoSpeakerFound':
        case 'callNoMicrophoneFound':
        case 'callMicrophoneAccessDenied':
        case 'callMicrophoneAccessDeniedSafari':
        case 'callMicrophoneMutedBySystem':
        case 'callMicrophoneUnmutedBySystem':
        case 'callMacOsMicrophoneAccessDenied':
        case 'callLocalVideoFreeze':
        case 'callCameraAccessDenied':
        case 'callCameraAccessDeniedSafari':
        case 'callCameraAlreadyInUse':
        case 'callVideoStoppedBySystem':
        case 'callVideoRecoveredBySystem':
        case 'callMacOsCameraAccessDenied':
        case 'callMacOsScreenShareAccessDenied':
        case 'startScreenShareGeneric':
        case 'cameraFrozenForRemoteParticipants':
            return MessageBarType.warning;
        default:
            return MessageBarType.error;
    }
};
/**
 * @private
 * @param errorType
 * @returns IIconProps | undefined
 */
export const messageBarIconProps = (errorType) => {
    const iconName = customIconName[errorType];
    return iconName ? {
        iconName
    } : undefined;
};
/**
 * @private
 */
export const customIconName = {
    callNetworkQualityLow: 'ErrorBarCallNetworkQualityLow',
    callNoSpeakerFound: 'ErrorBarCallNoSpeakerFound',
    callNoMicrophoneFound: 'ErrorBarCallNoMicrophoneFound',
    callMicrophoneAccessDenied: 'ErrorBarCallMicrophoneAccessDenied',
    callMicrophoneAccessDeniedSafari: 'ErrorBarCallMicrophoneAccessDenied',
    callMicrophoneMutedBySystem: 'ErrorBarCallMicrophoneMutedBySystem',
    callMicrophoneUnmutedBySystem: 'ErrorBarCallMicrophoneUnmutedBySystem',
    callMacOsMicrophoneAccessDenied: 'ErrorBarCallMacOsMicrophoneAccessDenied',
    callLocalVideoFreeze: 'ErrorBarCallLocalVideoFreeze',
    callCameraAccessDenied: 'ErrorBarCallCameraAccessDenied',
    callCameraAccessDeniedSafari: 'ErrorBarCallCameraAccessDenied',
    callCameraAlreadyInUse: 'ErrorBarCallCameraAlreadyInUse',
    callVideoStoppedBySystem: 'ErrorBarCallVideoStoppedBySystem',
    callVideoRecoveredBySystem: 'ErrorBarCallVideoRecoveredBySystem',
    callMacOsCameraAccessDenied: 'ErrorBarCallMacOsCameraAccessDenied'
};
/**
 * @private
 * @param NotificationType
 * @returns IIconProps | undefined
 */
export const NotificationIconProps = (notificationType) => {
    const iconName = customNotificationIconName[notificationType];
    return iconName ? {
        iconName
    } : undefined;
};
/**
 * @private
 */
export const customNotificationIconName = {
    callNetworkQualityLow: 'ErrorBarCallNetworkQualityLow',
    teamsMeetingCallNetworkQualityLow: 'ErrorBarCallNetworkQualityLow',
    callNoSpeakerFound: 'ErrorBarCallNoSpeakerFound',
    callNoMicrophoneFound: 'ErrorBarCallNoMicrophoneFound',
    callMicrophoneAccessDenied: 'ErrorBarCallMicrophoneAccessDenied',
    callMicrophoneAccessDeniedSafari: 'ErrorBarCallMicrophoneAccessDenied',
    callMicrophoneMutedBySystem: 'ErrorBarCallMicrophoneMutedBySystem',
    callMicrophoneUnmutedBySystem: 'ErrorBarCallMicrophoneUnmutedBySystem',
    callMacOsMicrophoneAccessDenied: 'ErrorBarCallMacOsMicrophoneAccessDenied',
    callLocalVideoFreeze: 'ErrorBarCallLocalVideoFreeze',
    callCameraAccessDenied: 'ErrorBarCallCameraAccessDenied',
    callCameraAccessDeniedSafari: 'ErrorBarCallCameraAccessDenied',
    callCameraAlreadyInUse: 'ErrorBarCallCameraAlreadyInUse',
    callVideoStoppedBySystem: 'ErrorBarCallVideoStoppedBySystem',
    callVideoRecoveredBySystem: 'ErrorBarCallVideoRecoveredBySystem',
    callMacOsCameraAccessDenied: 'ErrorBarCallMacOsCameraAccessDenied',
    mutedByRemoteParticipant: 'ErrorBarMutedByRemoteParticipant',
    speakingWhileMuted: 'ErrorBarCallMicrophoneMutedBySystem',
    recordingStarted: 'NotificationBarRecording',
    transcriptionStarted: 'NotificationBarRecording',
    recordingStopped: 'NotificationBarRecording',
    transcriptionStopped: 'NotificationBarRecording',
    recordingAndTranscriptionStarted: 'NotificationBarRecording',
    recordingAndTranscriptionStopped: 'NotificationBarRecording',
    recordingStoppedStillTranscribing: 'NotificationBarRecording',
    transcriptionStoppedStillRecording: 'NotificationBarRecording',
    assignedBreakoutRoomOpened: 'NotificationBarBreakoutRoomOpened',
    assignedBreakoutRoomOpenedPromptJoin: 'NotificationBarBreakoutRoomPromptJoin',
    assignedBreakoutRoomChanged: 'NotificationBarBreakoutRoomChanged',
    assignedBreakoutRoomClosed: 'NotificationBarBreakoutRoomClosed',
    breakoutRoomJoined: 'NotificationBarBreakoutRoomJoined',
    breakoutRoomClosingSoon: 'NotificationBarBreakoutRoomClosingSoon',
    capabilityTurnVideoOnPresent: 'ControlButtonCameraOff',
    capabilityTurnVideoOnAbsent: 'ControlButtonCameraProhibited',
    capabilityUnmuteMicPresent: 'ControlButtonMicOff',
    capabilityUnmuteMicAbsent: 'ControlButtonMicProhibited',
    togetherModeStarted: 'NotificationBarTogetherModeIcon',
    togetherModeEnded: 'NotificationBarTogetherModeIcon',
    transcriptionError: 'NotificationBarTranscriptionError',
    transcriptionStartedByYou: 'NotificationBarTranscriptionStartedByYou'
};
/**
 * @private
 */
export const isValidString = (string) => {
    return !!string && string.length > 0;
};
/**
 * Chunk an array into rows of a given size.
 * @private
 */
export function chunk(options, itemsPerRow) {
    const rows = [];
    let currentRow = [];
    for (const option of options) {
        currentRow.push(option);
        if (currentRow.length === itemsPerRow) {
            rows.push(currentRow);
            currentRow = [];
        }
    }
    if (currentRow.length > 0) {
        rows.push(currentRow);
    }
    return rows;
}
/**
 * @private
 */
export const defaultSpokenLanguage = 'en-us';
/**
 * @private
 */
const SAFARI_COMPOSITION_KEYCODE = 229;
/**
 * Determine if the press of the enter key is from a composition session or not (Safari only)
 *
 * @private
 */
export const isEnterKeyEventFromCompositionSession = (e) => {
    // Uses KeyCode 229 and which code 229 to determine if the press of the enter key is from a composition session or not (the code check is needed for Safari only, for everything else e.isComposing check is enough)
    const isComposing = e.isComposing || e.keyCode === SAFARI_COMPOSITION_KEYCODE || e.which === SAFARI_COMPOSITION_KEYCODE;
    return isComposing && e.key === 'Enter';
};
/**
 * @private
 */
export const nullToUndefined = (value) => value === null ? undefined : value;
/**
 * @private
 */
export const formatMoreButtonAriaDescription = (displayName, isMuted, isHandRaised, state, isSpeaking, strings, isMicDisabled, isCameraDisabled) => {
    const mutedState = isMuted ? strings === null || strings === void 0 ? void 0 : strings.moreOptionsParticipantMutedStateMutedAriaLabel : strings === null || strings === void 0 ? void 0 : strings.moreOptionsParticipantMutedStateUnmutedAriaLabel;
    const handRaisedState = isHandRaised ? strings === null || strings === void 0 ? void 0 : strings.moreOptionsParticipantHandRaisedAriaLabel : undefined;
    const isSpeakingState = isSpeaking ? strings === null || strings === void 0 ? void 0 : strings.moreOptionsParticipantIsSpeakingAriaLabel : undefined;
    const micDisabledState = isMicDisabled ? strings === null || strings === void 0 ? void 0 : strings.moreOptionsParticipantMicDisabledAriaLabel : undefined;
    const cameraDisabledState = isCameraDisabled ? strings === null || strings === void 0 ? void 0 : strings.moreOptionsParticipantCameraDisabledAriaLabel : undefined;
    const description = (strings === null || strings === void 0 ? void 0 : strings.moreOptionsButtonAriaLabel) ? _formatString(strings === null || strings === void 0 ? void 0 : strings.moreOptionsButtonAriaLabel, {
        displayName: displayName !== null && displayName !== void 0 ? displayName : ' ',
        isMuted: mutedState !== null && mutedState !== void 0 ? mutedState : ' ',
        isHandRaised: handRaisedState !== null && handRaisedState !== void 0 ? handRaisedState : ' ',
        state: state !== null && state !== void 0 ? state : ' ',
        isSpeaking: isSpeakingState !== null && isSpeakingState !== void 0 ? isSpeakingState : ' ',
        micDisabledState: micDisabledState !== null && micDisabledState !== void 0 ? micDisabledState : ' ',
        cameraDisabledState: cameraDisabledState !== null && cameraDisabledState !== void 0 ? cameraDisabledState : ' '
    }) : '';
    return description;
};
//# sourceMappingURL=utils.js.map