"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimelineSequence = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = __importStar(require("react"));
const remotion_1 = require("remotion");
const client_id_1 = require("../../helpers/client-id");
const colors_1 = require("../../helpers/colors");
const format_file_location_1 = require("../../helpers/format-file-location");
const get_timeline_sequence_layout_1 = require("../../helpers/get-timeline-sequence-layout");
const interactivity_enabled_1 = require("../../helpers/interactivity-enabled");
const open_in_editor_1 = require("../../helpers/open-in-editor");
const timeline_layout_1 = require("../../helpers/timeline-layout");
const use_max_media_duration_1 = require("../../helpers/use-max-media-duration");
const AudioWaveform_1 = require("../AudioWaveform");
const call_api_1 = require("../call-api");
const ConfirmationDialog_1 = require("../ConfirmationDialog");
const ContextMenu_1 = require("../ContextMenu");
const NotificationCenter_1 = require("../Notifications/NotificationCenter");
const use_select_asset_1 = require("../use-select-asset");
const disable_sequence_interactivity_1 = require("./disable-sequence-interactivity");
const duplicate_selected_timeline_item_1 = require("./duplicate-selected-timeline-item");
const get_sequence_context_menu_items_1 = require("./get-sequence-context-menu-items");
const LoopedTimelineIndicators_1 = require("./LoopedTimelineIndicators");
const timeline_asset_link_1 = require("./timeline-asset-link");
const TimelineImageInfo_1 = require("./TimelineImageInfo");
const TimelineSelection_1 = require("./TimelineSelection");
const TimelineSequenceFrame_1 = require("./TimelineSequenceFrame");
const TimelineSequenceRightEdgeDragHandle_1 = require("./TimelineSequenceRightEdgeDragHandle");
const TimelineVideoInfo_1 = require("./TimelineVideoInfo");
const TimelineWidthProvider_1 = require("./TimelineWidthProvider");
const use_resolved_stack_react_to_change_1 = require("./use-resolved-stack-react-to-change");
const use_sequence_freeze_frame_menu_item_1 = require("./use-sequence-freeze-frame-menu-item");
const TimelineSequenceFn = ({ s, nodePathInfo, sequenceFrameOffset }) => {
    const windowWidth = (0, react_1.useContext)(TimelineWidthProvider_1.TimelineWidthContext);
    if (windowWidth === null) {
        return null;
    }
    return (jsx_runtime_1.jsx(TimelineSequenceInner, { windowWidth: windowWidth, s: s, nodePathInfo: nodePathInfo, sequenceFrameOffset: sequenceFrameOffset }));
};
const TimelineSequenceCurrentFrame = ({ s, displayDurationInFrames, premountWidth, postmountWidth, style, children, nodePathInfo, sequenceFrameOffset, fromCanUpdate, frozenFrame, onMoveDragPointerDown, }) => {
    var _a, _b;
    const ref = (0, react_1.useRef)(null);
    const { onSelect, selectable, selected, selectionItem } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
    (0, TimelineSelection_1.useTimelineMarqueeSelectableItem)(selectionItem, ref);
    const onPointerDown = (0, react_1.useCallback)((e) => {
        if (e.button === 0) {
            e.stopPropagation();
            if ((0, TimelineSelection_1.shouldSelectTimelineRowOnPointerDown)({
                selected,
                shiftKey: e.shiftKey,
                metaKey: e.metaKey,
                ctrlKey: e.ctrlKey,
            })) {
                onSelect({
                    shiftKey: e.shiftKey,
                    toggleKey: e.metaKey || e.ctrlKey,
                });
            }
            if (fromCanUpdate) {
                onMoveDragPointerDown(e);
            }
        }
    }, [fromCanUpdate, onMoveDragPointerDown, onSelect, selected]);
    const frame = (0, remotion_1.useCurrentFrame)();
    const relativeFrame = frame - s.from;
    const sequenceFrame = relativeFrame + sequenceFrameOffset;
    const relativeFrameWithPremount = relativeFrame + ((_a = s.premountDisplay) !== null && _a !== void 0 ? _a : 0);
    const relativeFrameWithPostmount = relativeFrame - displayDurationInFrames;
    const roundedFrame = Math.round(sequenceFrame * 100) / 100;
    const isInRange = relativeFrame >= 0 && relativeFrame < displayDurationInFrames;
    const isPremounting = relativeFrameWithPremount >= 0 &&
        relativeFrameWithPremount < displayDurationInFrames &&
        !isInRange;
    const isPostmounting = relativeFrameWithPostmount >= 0 &&
        relativeFrameWithPostmount < ((_b = s.postmountDisplay) !== null && _b !== void 0 ? _b : 0) &&
        !isInRange;
    const actualStyle = (0, react_1.useMemo)(() => {
        return {
            ...style,
            opacity: isInRange ? 1 : 0.5,
        };
    }, [isInRange, style]);
    return (jsx_runtime_1.jsxs("div", { ref: ref, [TimelineSelection_1.TIMELINE_MARQUEE_ITEM_ATTR]: true, style: actualStyle, title: s.displayName, onPointerDown: selectable ? onPointerDown : undefined, children: [premountWidth ? (jsx_runtime_1.jsx("div", { style: {
                    width: premountWidth,
                    height: '100%',
                    background: `repeating-linear-gradient(
								-45deg,
								${colors_1.TRANSPARENT},
								${colors_1.TRANSPARENT} 2px,
								${isPremounting ? colors_1.WHITE_ALPHA_50 : colors_1.WHITE_ALPHA_20} 2px,
								${isPremounting ? colors_1.WHITE_ALPHA_50 : colors_1.WHITE_ALPHA_20} 4px
							)`,
                    position: 'absolute',
                } })) : null, postmountWidth ? (jsx_runtime_1.jsx("div", { style: {
                    width: postmountWidth,
                    height: '100%',
                    background: `repeating-linear-gradient(
								-45deg,
								${colors_1.TRANSPARENT},
								${colors_1.TRANSPARENT} 2px,
								${isPostmounting ? colors_1.WHITE_ALPHA_50 : colors_1.WHITE_ALPHA_20} 2px,
								${isPostmounting ? colors_1.WHITE_ALPHA_50 : colors_1.WHITE_ALPHA_20} 4px
							)`,
                    position: 'absolute',
                    right: 0,
                } })) : null, children, s.type !== 'audio' &&
                s.type !== 'video' &&
                s.type !== 'image' &&
                s.loopDisplay === undefined &&
                (isInRange || isPremounting || isPostmounting) ? (jsx_runtime_1.jsx("div", { style: {
                    paddingLeft: 5 + (premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0),
                    height: '100%',
                    display: 'flex',
                    alignItems: 'center',
                }, children: jsx_runtime_1.jsx(TimelineSequenceFrame_1.TimelineSequenceFrame, { premounted: isPremounting, postmounted: isPostmounting ? s.duration - 1 : null, roundedFrame: roundedFrame, frozenFrame: frozenFrame }) })) : null] }));
};
const TimelineSequenceInner = ({ s, windowWidth, nodePathInfo, sequenceFrameOffset }) => {
    // If a duration is 1, it is essentially a still and it should have width 0
    // Some compositions may not be longer than their media duration,
    // if that is the case, it needs to be asynchronously determined
    var _a, _b, _c;
    var _d, _e, _f, _g, _h, _j;
    const video = remotion_1.Internals.useVideo();
    const maxMediaDuration = (0, use_max_media_duration_1.useMaxMediaDuration)(s, (_d = video === null || video === void 0 ? void 0 : video.fps) !== null && _d !== void 0 ? _d : 30);
    const effectiveMaxMediaDuration = s.loopDisplay ? null : maxMediaDuration;
    const originalLocation = (0, use_resolved_stack_react_to_change_1.useResolveStackAndReactToChange)(s.getStack);
    const validatedLocation = (0, react_1.useMemo)(() => {
        var _a;
        if (!originalLocation ||
            !originalLocation.source ||
            !originalLocation.line) {
            return null;
        }
        return {
            source: originalLocation.source,
            line: originalLocation.line,
            column: (_a = originalLocation.column) !== null && _a !== void 0 ? _a : 0,
        };
    }, [originalLocation]);
    const { propStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModePropStatusesContext);
    const nodePath = (_e = nodePathInfo === null || nodePathInfo === void 0 ? void 0 : nodePathInfo.sequenceSubscriptionKey) !== null && _e !== void 0 ? _e : null;
    const propStatusesForOverride = (0, react_1.useMemo)(() => {
        return nodePath
            ? remotion_1.Internals.getPropStatusesCtx(propStatuses, nodePath)
            : undefined;
    }, [propStatuses, nodePath]);
    const durationCanUpdate = Boolean(interactivity_enabled_1.studioInteractivityEnabled &&
        ((_a = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.durationInFrames) === null || _a === void 0 ? void 0 : _a.status) === 'static');
    const fromCanUpdate = Boolean(interactivity_enabled_1.studioInteractivityEnabled &&
        ((_b = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.from) === null || _b === void 0 ? void 0 : _b.status) === 'static');
    const trimBeforeCanUpdate = Boolean(interactivity_enabled_1.studioInteractivityEnabled &&
        ((_c = propStatusesForOverride === null || propStatusesForOverride === void 0 ? void 0 : propStatusesForOverride.trimBefore) === null || _c === void 0 ? void 0 : _c.status) === 'static');
    const { previewServerState } = (0, react_1.useContext)(client_id_1.StudioServerConnectionCtx);
    const previewConnected = previewServerState.type === 'connected';
    const previewInteractive = previewConnected && interactivity_enabled_1.studioInteractivityEnabled;
    const { setPropStatuses } = (0, react_1.useContext)(remotion_1.Internals.VisualModeSettersContext);
    const timelinePosition = remotion_1.Internals.Timeline.useTimelinePosition();
    const selectAsset = (0, use_select_asset_1.useSelectAsset)();
    const confirm = (0, ConfirmationDialog_1.useConfirmationDialog)();
    const { onSelect, selectable } = (0, TimelineSelection_1.useTimelineRowSelection)(nodePathInfo);
    const fileLocation = (0, react_1.useMemo)(() => (0, format_file_location_1.formatFileLocation)({
        location: originalLocation,
        root: window.remotion_cwd,
    }), [originalLocation]);
    const canOpenInEditor = Boolean(window.remotion_editorName && previewConnected && originalLocation);
    const openInEditor = (0, react_1.useCallback)(() => {
        if (!canOpenInEditor || !originalLocation) {
            return;
        }
        (0, open_in_editor_1.openOriginalPositionInEditor)(originalLocation).catch((err) => {
            (0, NotificationCenter_1.showNotification)(err.message, 2000);
        });
    }, [canOpenInEditor, originalLocation]);
    const canDeleteFromSource = Boolean(nodePath && (validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source));
    const deleteDisabled = !previewInteractive || !s.controls || !canDeleteFromSource;
    const duplicateDisabled = deleteDisabled;
    const disableInteractivityDisabled = !previewInteractive ||
        !s.showInTimeline ||
        !nodePath ||
        !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source);
    const mediaSrc = s.type === 'audio' || s.type === 'video' || s.type === 'image'
        ? s.src
        : null;
    const assetLinkInfo = (0, react_1.useMemo)(() => (mediaSrc ? (0, timeline_asset_link_1.getTimelineAssetLinkInfo)(mediaSrc) : null), [mediaSrc]);
    const onDuplicateSequenceFromSource = (0, react_1.useCallback)(() => {
        if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePathInfo || duplicateDisabled) {
            return;
        }
        (0, duplicate_selected_timeline_item_1.duplicateSequencesFromSource)([nodePathInfo], confirm).catch(() => undefined);
    }, [confirm, duplicateDisabled, nodePathInfo, validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source]);
    const onDeleteSequenceFromSource = (0, react_1.useCallback)(async () => {
        if (!(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) || !nodePath || deleteDisabled) {
            return;
        }
        if (nodePathInfo && nodePathInfo.numberOfSequencesWithThisNodePath > 1) {
            const shouldDelete = await confirm({
                title: 'Delete sequence?',
                message: 'This sequence is programmatically duplicated ' +
                    nodePathInfo.numberOfSequencesWithThisNodePath +
                    ' times in the code. Deleting removes all instances. Continue?',
                confirmLabel: 'Delete',
            });
            if (!shouldDelete) {
                return;
            }
        }
        try {
            const result = await (0, call_api_1.callApi)('/api/delete-jsx-node', {
                nodes: [
                    {
                        fileName: validatedLocation.source,
                        nodePath: nodePath.nodePath,
                    },
                ],
            });
            if (result.success) {
                (0, NotificationCenter_1.showNotification)('Removed sequence from source file', 2000);
            }
            else {
                (0, NotificationCenter_1.showNotification)(result.reason, 4000);
            }
        }
        catch (err) {
            (0, NotificationCenter_1.showNotification)(err.message, 4000);
        }
    }, [
        confirm,
        deleteDisabled,
        nodePath,
        nodePathInfo,
        validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
    ]);
    const onDisableSequenceInteractivity = (0, react_1.useCallback)(() => {
        if (disableInteractivityDisabled ||
            !nodePath ||
            !(validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) ||
            previewServerState.type !== 'connected') {
            return;
        }
        (0, disable_sequence_interactivity_1.disableSequenceInteractivity)({
            fileName: validatedLocation.source,
            nodePath,
            setPropStatuses,
            clientId: previewServerState.clientId,
        });
    }, [
        disableInteractivityDisabled,
        nodePath,
        previewServerState,
        setPropStatuses,
        validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source,
    ]);
    const freezeFrameMenuItem = (0, use_sequence_freeze_frame_menu_item_1.useSequenceFreezeFrameMenuItem)({
        clientId: previewInteractive && previewServerState.type === 'connected'
            ? previewServerState.clientId
            : null,
        nodePath,
        propStatusesForOverride,
        sequence: s,
        sequenceFrameOffset,
        setPropStatuses,
        timelinePosition,
        validatedSource: (_f = validatedLocation === null || validatedLocation === void 0 ? void 0 : validatedLocation.source) !== null && _f !== void 0 ? _f : null,
    });
    const contextMenuValues = (0, react_1.useMemo)(() => {
        if (!previewConnected) {
            return [];
        }
        return (0, get_sequence_context_menu_items_1.getSequenceContextMenuItems)({
            assetLinkInfo,
            canOpenInEditor,
            deleteDisabled,
            disableInteractivityDisabled,
            duplicateDisabled,
            fileLocation,
            includeSourceEditItems: interactivity_enabled_1.studioInteractivityEnabled,
            onDeleteSequenceFromSource,
            onDisableSequenceInteractivity,
            onDuplicateSequenceFromSource,
            openInEditor,
            originalLocation,
            selectAsset,
            sequence: s,
            sourceActions: interactivity_enabled_1.studioInteractivityEnabled && freezeFrameMenuItem
                ? [freezeFrameMenuItem]
                : [],
        });
    }, [
        assetLinkInfo,
        canOpenInEditor,
        deleteDisabled,
        disableInteractivityDisabled,
        duplicateDisabled,
        fileLocation,
        freezeFrameMenuItem,
        onDeleteSequenceFromSource,
        onDisableSequenceInteractivity,
        onDuplicateSequenceFromSource,
        openInEditor,
        originalLocation,
        previewConnected,
        s,
        selectAsset,
    ]);
    const onContextMenuOpen = (0, react_1.useCallback)(() => {
        if (selectable) {
            onSelect({ shiftKey: false, toggleKey: false });
        }
    }, [onSelect, selectable]);
    const { frozenFrame } = s;
    const { onPointerDown: onMoveDragPointerDown } = (0, TimelineSequenceRightEdgeDragHandle_1.useTimelineSequenceFromDrag)({
        nodePathInfo,
        windowWidth,
        timelineDurationInFrames: (_g = video === null || video === void 0 ? void 0 : video.durationInFrames) !== null && _g !== void 0 ? _g : 1,
    });
    if (!video) {
        throw new TypeError('Expected video config');
    }
    const displayDurationInFrames = s.loopDisplay
        ? s.loopDisplay.durationInFrames * s.loopDisplay.numberOfTimes
        : s.duration;
    const { marginLeft, width, naturalWidth, premountWidth, postmountWidth } = (0, react_1.useMemo)(() => {
        return (0, get_timeline_sequence_layout_1.getTimelineSequenceLayout)({
            durationInFrames: displayDurationInFrames,
            startFrom: s.loopDisplay ? s.from + s.loopDisplay.startOffset : s.from,
            startFromMedia: s.type === 'sequence' || s.type === 'image' ? 0 : s.startMediaFrom,
            maxMediaDuration: effectiveMaxMediaDuration,
            video,
            windowWidth,
            premountDisplay: s.premountDisplay,
            postmountDisplay: s.postmountDisplay,
        });
    }, [
        displayDurationInFrames,
        effectiveMaxMediaDuration,
        s,
        video,
        windowWidth,
    ]);
    const style = (0, react_1.useMemo)(() => {
        return {
            background: s.type === 'audio'
                ? colors_1.TIMELINE_AUDIO_GRADIENT
                : s.type === 'video'
                    ? colors_1.TIMELINE_VIDEO_GRADIENT
                    : s.type === 'image'
                        ? colors_1.TIMELINE_IMAGE_GRADIENT
                        : colors_1.BLUE,
            border: `${get_timeline_sequence_layout_1.SEQUENCE_BORDER_WIDTH}px solid ${colors_1.WHITE_ALPHA_20}`,
            borderRadius: 2,
            position: 'absolute',
            height: (0, timeline_layout_1.getTimelineLayerHeight)(s.type),
            marginLeft,
            width,
            color: colors_1.WHITE,
            overflow: 'hidden',
        };
    }, [marginLeft, s.type, width]);
    const showRightEdgeDragHandle = (0, TimelineSequenceRightEdgeDragHandle_1.isTimelineSequenceDurationDraggable)(s) &&
        nodePath !== null &&
        validatedLocation !== null &&
        durationCanUpdate;
    const showLeftEdgeDragHandle = (s.type === 'sequence' ||
        s.type === 'image' ||
        s.type === 'audio' ||
        s.type === 'video') &&
        !s.isInsideSeries &&
        nodePath !== null &&
        validatedLocation !== null &&
        Boolean(s.controls) &&
        fromCanUpdate &&
        durationCanUpdate &&
        trimBeforeCanUpdate;
    if (maxMediaDuration === null && !s.loopDisplay) {
        return null;
    }
    const sequence = (jsx_runtime_1.jsxs(TimelineSequenceCurrentFrame, { s: s, displayDurationInFrames: displayDurationInFrames, premountWidth: premountWidth, postmountWidth: postmountWidth, style: style, nodePathInfo: nodePathInfo, sequenceFrameOffset: sequenceFrameOffset, fromCanUpdate: fromCanUpdate, frozenFrame: frozenFrame, onMoveDragPointerDown: onMoveDragPointerDown, children: [s.type === 'audio' ? (jsx_runtime_1.jsx(AudioWaveform_1.AudioWaveform, { src: s.src, height: timeline_layout_1.TIMELINE_LAYER_HEIGHT_AUDIO, doesVolumeChange: s.doesVolumeChange, visualizationWidth: width, startFrom: s.startMediaFrom, durationInFrames: s.duration, volume: s.volume, playbackRate: s.playbackRate, loopDisplay: s.loopDisplay })) : null, s.type === 'video' ? (jsx_runtime_1.jsx(TimelineVideoInfo_1.TimelineVideoInfo, { src: s.src, visualizationWidth: width, naturalWidth: naturalWidth, startMediaFrom: s.startMediaFrom, mediaFrameAtSequenceZero: s.mediaFrameAtSequenceZero, sequenceFrameOffset: sequenceFrameOffset, durationInFrames: s.duration, playbackRate: s.playbackRate, volume: s.volume, doesVolumeChange: s.doesVolumeChange, premountWidth: premountWidth !== null && premountWidth !== void 0 ? premountWidth : 0, postmountWidth: postmountWidth !== null && postmountWidth !== void 0 ? postmountWidth : 0, loopDisplay: s.loopDisplay, frozenMediaFrame: s.frozenMediaFrame })) : null, s.type === 'image' ? (jsx_runtime_1.jsx(TimelineImageInfo_1.TimelineImageInfo, { src: s.src, visualizationWidth: width })) : null, s.loopDisplay === undefined ? null : (jsx_runtime_1.jsx(LoopedTimelineIndicators_1.LoopedTimelineIndicator, { loops: s.loopDisplay.numberOfTimes })), showLeftEdgeDragHandle && nodePathInfo && validatedLocation ? (jsx_runtime_1.jsx(TimelineSequenceRightEdgeDragHandle_1.TimelineSequenceLeftEdgeDragHandle, { nodePathInfo: nodePathInfo, windowWidth: windowWidth, timelineDurationInFrames: (_h = video.durationInFrames) !== null && _h !== void 0 ? _h : 1 })) : null, showRightEdgeDragHandle && nodePathInfo && validatedLocation ? (jsx_runtime_1.jsx(TimelineSequenceRightEdgeDragHandle_1.TimelineSequenceRightEdgeDragHandle, { nodePathInfo: nodePathInfo, windowWidth: windowWidth, timelineDurationInFrames: (_j = video.durationInFrames) !== null && _j !== void 0 ? _j : 1 })) : null] }));
    return previewConnected ? (jsx_runtime_1.jsx(ContextMenu_1.ContextMenu, { values: contextMenuValues, onOpen: onContextMenuOpen, children: sequence })) : (sequence);
};
exports.TimelineSequence = react_1.default.memo(TimelineSequenceFn);
