dir() {
    curlArchive=false
    templateArchive=""
    repoUrl=""
    nixShell=""
    findNix=false
    dir=""
    forceShell=false
    wormhole=false
    gitWorktree=""
    # notmuchMsg=""
    quickserve=false
    modifyPDF=""

    while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do
        case $arg in
            "t") ;;
            "a")
                if [[ ${OPTARG} =~ "://" ]]; then
                    templateArchive=${OPTARG}
                    curlArchive=true
                else
                    templateArchive=${OPTARG:a}
                fi
                ;;
            "s") nixShell=${OPTARG:a} ;;
            "S") findNix=true ;;
            "d") dir=${OPTARG} ;;
            "i") forceShell=true ;;
            "r") repoUrl=${OPTARG} ;;
            "w") wormhole=true ;;
            "g") gitWorktree=${OPTARG} ;;
            # "n") notmuchMsg=${OPTARG} ;;
	    "q") quickserve=true ;;
	    "p") modifyPDF=${OPTARG:a} ;;
            *) printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
        esac
    done

    shift $((OPTIND - 1))

    if [[ -z ${dir} && ${#@} -ge 1 ]]; then
        dir=${1}
        shift
    fi

    [[ -n ${dir} ]] || return 2;

    if [[ ! -e ${dir} ]]; then
        if [[ -z "${gitWorktree}" ]]; then
            mkdir -vp ${dir}
        else
            git -C ${gitWorktree} worktree add ${dir}
        fi
    else
        gitWorktree=""
    fi

    cleanup()
    {
	cd ${modifyPDF:h}
	[[ -n ${modifyPDF} ]] && nix shell nixos#imagemagick -c convert -verbose ${dir}/${modifyPDF:t:r}_*.png(on) ${modifyPDF}
    }

    (
        trap cleanup EXIT

        cd ${dir}
        export dir;

        ${findNix} && { nixShell=$(findNix) || return $? }

        [[ -n ${repoUrl} ]] && git clone -- ${repoUrl} .

	[[ -n ${modifyPDF} ]] && templateArchive=${modifyPDF}

        if [[ -n ${templateArchive} ]]; then
            (
                archiveFile=""
                cleanup() {
                    [[ -n "${archiveFile}" ]] && rm -fv ${archiveFile}
                }
                trap cleanup EXIT

                if ${curlArchive}; then
                    archiveFile=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t}")

                    curl -L -o ${archiveFile} ${templateArchive}

                    templateArchive=${archiveFile}
                fi

		unpack=true
		while ${unpack}; do
		    case $(file --brief --mime-type --dereference ${templateArchive}) in
			application/zip)
			    unzip ${templateArchive}
			    unpack=false
			;;
			application/vnd.debian.binary-package)
			    nix shell nixos#binutils --command ar x ${templateArchive}
			    mkdir control data
			    tar -C control -xvaf control.*
			    tar -C data -xvaf data.*
			    unpack=false
			;;
			application/x-rpm)
			    cpioArchive=$(mktemp -t "archive.XXXXXXXXXX.${templateArchive:t:r}.cpio")
			    nix shell nixos#busybox --command rpm2cpio ${templateArchive} > ${cpioArchive}
			    templateArchive=${cpioArchive}
			    unpack=true
			;;
			application/x-cpio)
			    cpio --extract --make-directories --no-absolute-filenames -F ${templateArchive}
			    unpack=false
			;;
			application/pdf)
			    nix shell nixos#ghostscript nixos#imagemagick -c convert -verbose -density 400 ${templateArchive} ${modifyPDF:t:r}_%0d.png
			    unpack=false
			;;
			application/octet-stream)
			    if [[ $(file --brief --dereferenc ${templateArchive}) =~ Squashfs ]]; then
			       nix shell nixos#squashfsTools -c unsquashfs -d . ${templateArchive}
			       unpack=false
			    fi
			;;
			*)
			    tar -xvaf ${templateArchive}
			    unpack=false
			;;
		    esac
		done
            )
        fi


        ${wormhole} && wormhole receive --accept-file


	if ${quickserve}; then
	  quickserve --root . --upload . --show-hidden --tar gz
	fi


        if [[ ${#@} -eq 0 ]] || ${forceShell}; then
            if [[ ${#@} -gt 0 ]]; then
                if [[ -z ${nixShell} ]]; then
                    ${@}
                else
                    nix-shell ${nixShell} --run "${@}"
                fi
            fi

            cd $(pwd) # Needed for mounting to work

            isSingleDir() {
                typeset -a contents
                contents=(*(N) .*(N))

                if [[ ${#contents} -eq 1 && -d ${contents[1]} ]]; then
                    print ${contents[1]}
                    return 0
                else
                    return 1
                fi
            }
            while d=$(isSingleDir); do cd ${d}; done


            if [[ -z ${nixShell} ]]; then
                zsh
            else
                nix-shell ${nixShell} --run zsh
            fi
        else
            if [[ -z ${nixShell} ]]; then
                ${@}
            else
                nix-shell ${nixShell} --run "${@}"
            fi
        fi
    )
}

tmpdir() {
    cleanup()
    {
      cd /
        unmount() {
            printf "Unmounting %s\n" ${1} >&2
            fusermount -u ${1} || umount ${1} || sudo umount ${1}
        }

        if mountpoint -q -- ${dir}; then
            unmount ${dir} || return $?
        else
            while read -d $'\0' subDir; do
                mountpoint -q -- ${subDir} || continue
                unmount ${subDir} || return $?
            done <<<$(find ${dir} -xdev -type d -print0 | sort -zr)
        fi

        rm -rfv --one-file-system -- ${dir}
    }

    local tmpdir=""

    while getopts ':t:a:s:Sd:ir:wqg:p:' arg; do
        case $arg in
            "t") tmpdir="=${OPTARG}" ;;
            "?"|":") printf "Invalid option: %s\n" $arg >&2; exit 2 ;;
        esac
    done

    (
        trap cleanup EXIT


        local dir=$(mktemp -ud --tmpdir${tmpdir} ${0}.XXXXXXXXXX || return $?)

        ( dir -d ${dir} ${@} )
    )
}

qr() {
    qrencode -l M -o - -t ANSIUTF8 $@
}

clock() {
    tty-clock -sSbc -C 7 -d 0 -a 100000000
}

public-ip() {
    curl -s -H 'Accept: application/json' $@ ifconfig.co | jq -r '.ip'
}

nix-ghci() {
    pkgExpr=""
    if [[ ${#@} -gt 0 ]]; then
        pkgExpr="${1}"
        shift
    fi

    nix-shell -p "with (import <nixpkgs> {}); pkgs.haskellPackages.ghcWithPackages (p: with p; [${pkgExpr}])" --run "ghci ${@}"
}

swap() {
    f1=${1}
    f2=${2}

    if [[ -z "${f1}" || ! -e "${f1}" ]]; then
        printf "ā€˜%sā€™ does not exist\n" "${f1}" >&2
        return 2
    fi
    if [[ -z "${f2}" || ! -e "${f2}" ]]; then
        printf "ā€˜%sā€™ does not exist\n" "${f2}" >&2
        return 2
    fi

    tmpfile=$(mktemp --dry-run --tmpdir=${f1:h} .swap.XXXXXXXXXX)
    mv -v ${f1} ${tmpfile}
    mv -v ${f2} ${f1}
    mv -v ${tmpfile} ${f2}
}

ls() {
  eza --all --group-directories-first --colour=always --sort=modified --smart-group $@ | less --mouse -FR
}

l() {
  ls --long --binary --git --time-style=iso --header $@
}

re() {
  systemctl --restart $@
}

ure() {
  systemctl --user --restart $@
}

ssh-installer() {
  ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o IdentityFile=~/.ssh/gkleen@sif.midgard.yggdrasil $@
}

dichotomic_search() {
  min=$1; shift
  max=$1; shift

  while [[ $min -lt $max ]]; do
    # Compute the mean between min and max, rounded up to the superior unit
    current=$(( (min + max + 1 ) / 2 ))
    if $@ $current; then
      min=$current
    else
      max=$((current - 1))
    fi
  done

  echo $min
}

while read -r -d $'\0' d _ s; do
  hash -d ${s}=${d}
done < <(find ~/projects ~/uni -regextype posix-extended -maxdepth 2 -type d -regex '\S+/[0-9]{2}[ws]/\S+' -print0 2>/dev/null | \
       sed -zr 's|(.*/([0-9]{2}[ws])/(.+))|\1 \2 \3|' | \
       sort -z -r -k2 | sort -z -s -k3 | uniq -z -f 2)

alias '..'='cd ..'
alias rzadm=$'tmpdir -i sh -c \'mkdir adm; sshfs gkleen@mgmt01:/adm adm\''
alias mathcloud=$'tmpdir -i rclone mount --daemon mathcloud:// .'
alias -g L='| less'
alias -g S='&> /dev/null'
alias -g G='| grep'
alias -g B='&> /dev/null &'
alias -g BB='&> /dev/null &!'

export DEFAULT_USER=gkleen

bindkey -e
bindkey ';5C' emacs-forward-word
bindkey ';5D' emacs-backward-word
bindkey '^[[1;5C' emacs-forward-word
bindkey '^[[1;5D' emacs-backward-word
bindkey '^H' backward-kill-word