_print() {
    local total_lines=$(awk 'END {print NR}' $CURRENT_FILE)
    echo "[File: $(realpath --relative-to=$ROOT $CURRENT_FILE) ($total_lines lines total)]"
    lines_above=$(jq -n "$CURRENT_LINE - $WINDOW/2" | jq '[0, .] | max | floor')
    lines_below=$(jq -n "$total_lines - $CURRENT_LINE - $WINDOW/2" | jq '[0, .] | max | round')
    if [ $lines_above -gt 0 ]; then
        echo "($lines_above more lines above)"
    fi
    cat $CURRENT_FILE | grep -n $ | head -n $(jq -n "[$CURRENT_LINE + $WINDOW/2, $WINDOW/2] | max | floor") | tail -n $(jq -n "$WINDOW")
    if [ $lines_below -gt 0 ]; then
        echo "($lines_below more lines below)"
    fi
}

_constrain_line() {
    if [ -z "$CURRENT_FILE" ]
    then
        echo "No file open. Use the open command first."
        return
    fi
    local max_line=$(awk 'END {print NR}' $CURRENT_FILE)
    export CURRENT_LINE=$(jq -n "[$CURRENT_LINE, $max_line - $WINDOW/2] | min") _print
    export CURRENT_LINE=$(jq -n "[$CURRENT_LINE, $WINDOW/2] | max") _print
}

# submits your current solution and closes the shell
submit() {
    cd $ROOT
    echo "<<SUBMISSION||"
    cat $CURRENT_FILE
    echo "||SUBMISSION>>"
}

# lists the files in the current directory
list() {
    ls
}

# @yaml
# signature: open <path>
# docstring: opens the file at the given path in the editor
open() {
    if [ -z "$1" ]
    then
        echo "Usage: open <file>"
        return
    fi

    if [ -f "$1" ]
    then
        if [ "$(realpath $1)" = "$CURRENT_FILE" ]
        then
            echo "$1"' is already open. Use `scroll_down`, `scroll_up`, `goto` and `search` to navigate file.'
            return
        fi
        export CURRENT_FILE=$(realpath $1)
        export CURRENT_LINE=$(jq -n "$WINDOW/2")
        _constrain_line
        _print
    else
        echo "File $1 not found"
    fi
}

# moves the window up {WINDOW} lines
scroll_down() {
    if [ -z "$CURRENT_FILE" ]
    then
        echo "No file open. Use the open command first."
        return
    fi
    export CURRENT_LINE=$(jq -n "$CURRENT_LINE + $WINDOW - $OVERLAP")
    _constrain_line
    _print
}

# moves the window down {WINDOW} lines
scroll_up() {
    if [ -z "$CURRENT_FILE" ]
    then
        echo "No file open. Use the open command first."
        return
    fi
    export CURRENT_LINE=$(jq -n "$CURRENT_LINE - $WINDOW + $OVERLAP")
    _constrain_line
    _print
}

# @yaml
# signature: goto <n>
# docstring: moves the window to be centered on line n
goto() {
    if [ $# -gt 1 ]; then
        echo "goto allows only one line number at a time."
        return
    fi
    if [ -z "$CURRENT_FILE" ]
    then
        echo "No file open. Use the open command first."
        return
    fi
    if [ -z "$1" ]
    then
        echo "Usage: goto <line>"
        return
    fi
    if ! [[ $1 =~ ^[0-9]+$ ]]
    then
        echo "Usage: goto <line>"
        echo "Error: <line> must be a number"
        return
    fi
    local max_line=$(awk 'END {print NR}' $CURRENT_FILE)
    if [ $1 -gt $max_line ]
    then
        echo "Error: <line> must be less than or equal to $max_line"
        return
    fi
    export CURRENT_LINE=$1
    _constrain_line
    _print
}
