/*
 * Copyright 2020 The Kubernetes Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import { v4 as uuid } from 'uuid';
import { hideReplayOutput, isCommentaryResponse, isError, Util } from '@kui-shell/core';
// this used to be defined here
export { isError };
/** Capture the current working directory */
function cwd() {
    const dir = Util.cwd();
    return dir ? dir.replace(process.env.HOME, '~') : undefined;
}
export function isProcessing(block) {
    return block.state === "processing" /* BlockState.Processing */;
}
export function isActive(block) {
    return block.state === "repl-active" /* BlockState.Active */;
}
/** @return true if the given `block` is `Active` and differs from the other `oblock` */
export function isActiveAndDifferent(block, oblock) {
    return isActive(block) && (!isActive(oblock) || block.cwd !== oblock.cwd || block.value !== oblock.value);
}
export function isCancelled(block) {
    return block.state === "cancelled" /* BlockState.Cancelled */;
}
export function isEmpty(block) {
    return block.state === "empty" /* BlockState.Empty */;
}
export function isOk(block) {
    return block.state === "valid-response" /* BlockState.ValidResponse */;
}
export function isOops(block) {
    return block.state === "error" /* BlockState.Error */;
}
export function isFinished(block) {
    return isOops(block) || isCancelled(block) || isOk(block) || isEmpty(block);
}
export function hasCommand(block) {
    return !isActive(block) && (!isEmpty(block) || block.command !== undefined);
}
export function isAnnouncement(block) {
    const blockModel = block;
    return blockModel.state === "valid-response" /* BlockState.ValidResponse */ && blockModel.isAnnouncement === true;
}
export function hasUUID(block) {
    return block && /* && !isActive(block) && */ !isEmpty(block) && !isAnnouncement(block);
}
export function hasValue(block) {
    return typeof block.value === 'string';
}
/** Transform to Active */
export function Active(initialValue) {
    return {
        cwd: cwd(),
        execUUID: uuid(),
        state: "repl-active" /* BlockState.Active */,
        value: initialValue || ''
    };
}
/** Transform to AnnouncementBlock */
export function Announcement(response, execUUID = uuid(), maximized) {
    return {
        response,
        execUUID,
        maximized,
        outputOnly: true,
        isAnnouncement: true,
        startTime: Date.now(),
        cwd: cwd(),
        state: "valid-response" /* BlockState.ValidResponse */
    };
}
export function isRerunable(block) {
    return isOk(block) || isOops(block);
}
export function isBeingRerun(block) {
    return block.isRerun === true;
}
export function isProcessingOrBeingRerun(block) {
    return isProcessing(block) || isBeingRerun(block);
}
export function hasOriginalUUID(block) {
    return typeof block.originalExecUUID === 'string';
}
/** Useful e.g. when reloading a snapshot, to clear out any prior "has been rerun" state */
export function clearOriginalUUID(block) {
    block.originalExecUUID = undefined;
}
/** @return whether the block has a completeEvent trait */
export function isWithCompleteEvent(block) {
    return (isOk(block) || isOops(block) || isEmpty(block)) && block.completeEvent !== undefined;
}
export function hasBeenRerun(block) {
    return (hasOriginalUUID(block) && hasUUID(block) && block.originalExecUUID !== block.execUUID && isWithCompleteEvent(block));
}
/** @return whether the block is from replay */
export function isReplay(block) {
    return (isProcessing(block) || isWithCompleteEvent(block)) && block.isReplay;
}
/** Transform to Processing */
export function Processing(block, startEvent, isExperimental = false, _isReplay = isReplay(block)) {
    return {
        command: startEvent.command,
        isExperimental,
        cwd: block.cwd,
        execUUID: startEvent.execUUID,
        originalExecUUID: (hasOriginalUUID(block) && block.originalExecUUID) || startEvent.execUUID,
        isReplay: _isReplay,
        startEvent,
        startTime: startEvent.startTime,
        state: "processing" /* BlockState.Processing */
    };
}
/** Transform to Empty */
export function Empty(block, typedSoFar, completeEvent) {
    return {
        cwd: block.cwd,
        command: typedSoFar,
        completeEvent,
        state: "empty" /* BlockState.Empty */
    };
}
/** Transform to Cancelled */
export function Cancelled(block, typedSoFar, completeEvent) {
    if (isProcessing(block)) {
        return {
            cwd: block.cwd,
            command: block.command,
            execUUID: block.execUUID,
            startTime: block.startTime,
            state: "cancelled" /* BlockState.Cancelled */
        };
    }
    else {
        return Empty(block, typedSoFar, completeEvent);
    }
}
/** Transform to Finished */
export function Finished(block, event, outputOnly = false, _isReplay = isReplay(block)) {
    const response = event.response; // event.responseType === 'ScalarResponse' ? (event.response as ScalarResponse) : true
    const { historyIdx } = event;
    const { startEvent } = block;
    // see Rerun() below; when re-executing a block (which means we
    // re-evaluate a potentially changed command, and want to splice the
    // updated response into an existing block --- in this scenario, we
    // still need a new execUUID so that the view components can know
    // whether or not a re-render is needed; Rerun() which is called
    // onExecStart allocates the execUUID, and then when we get here,
    // onExecEnd, we can swap that new execUUID into place
    if (isBeingRerun(block)) {
        block.execUUID = block.newExecUUID;
    }
    if (event.cancelled) {
        if (!event.command) {
            return Empty(block);
        }
        else {
            return Cancelled(block, event.command);
        }
    }
    else if (isError(response)) {
        return {
            response,
            historyIdx,
            cwd: block.cwd,
            command: block.command,
            startEvent,
            completeEvent: event,
            isExperimental: block.isExperimental,
            isReplay: _isReplay,
            state: "error" /* BlockState.Error */,
            execUUID: block.execUUID,
            originalExecUUID: (hasOriginalUUID(block) && block.originalExecUUID) || block.execUUID,
            startTime: block.startTime
        };
    }
    else {
        return {
            response,
            historyIdx,
            cwd: block.cwd,
            command: block.command,
            startEvent,
            completeEvent: event,
            isExperimental: block.isExperimental,
            isReplay: _isReplay,
            execUUID: block.execUUID,
            originalExecUUID: (hasOriginalUUID(block) && block.originalExecUUID) || block.execUUID,
            startTime: block.startTime,
            outputOnly,
            state: "valid-response" /* BlockState.ValidResponse */
        };
    }
}
export function isOutputOnly(block) {
    if (isProcessing(block)) {
        return block.startEvent.echo === false;
    }
    else if (isOk(block)) {
        return ((block.completeEvent && block.completeEvent.echo === false) ||
            (block.startEvent && block.startEvent.echo === false) ||
            block.outputOnly);
    }
}
/** @return whether the block as a startEvent trait */
export function hasStartEvent(block) {
    return !isAnnouncement(block) && (isProcessing(block) || isOk(block) || isOops(block));
}
/** @return whether the output of this command execution be redirected to a file */
export function isOutputRedirected(block) {
    return hasStartEvent(block) && block.startEvent.redirectDesired;
}
/** Transform a RerunableBlock to one in the BlockBeingRerun state */
export function Rerun(block, newStartEvent = block.startEvent, newCommand = newStartEvent.command, newStartTime = newStartEvent.startTime) {
    return Object.assign({}, block, {
        isRerun: true,
        startEvent: newStartEvent,
        command: newCommand,
        newExecUUID: uuid(),
        originalExecUUID: (hasOriginalUUID(block) && block.originalExecUUID) || block.execUUID,
        startTime: newStartTime
    });
}
/** this implements support for not showing the Output blocks when replaying a notebook */
export function hideOutput(model) {
    return (hideReplayOutput() && // client asked us not to show replay output in notebooks
        isReplay(model) && // we are showing a notebook
        !hasBeenRerun(model) && // user has yet to re-execute the block in this notebook
        isFinished(model) &&
        !isCancelled(model) &&
        !isEmpty(model) &&
        !isCommentaryResponse(model.response));
}
export function isMaximized(model) {
    return isAnnouncement(model) && model.maximized;
}
//# sourceMappingURL=BlockModel.js.map