#!/usr/bin/env zsh

# terminal to launch when splitting 
# undefined window class.
# first choice urxvt fallback xterm.
terminal="${commands[urxvt]:-xterm}"

typeset -a allowed_actions=(
	xbindkeys
	start
	end
)
if [ ${allowed_actions[(I)$1]} -le 0 ]; then
	cat <<-EOF
	i3winsplit.zsh
	==============
	Your scientists were so preoccupied with whether or not they could,
	they didn’t stop to think if they should.          - Jurassic Park

	Updates:
	========
	https://gist.github.com/DerBunman/2fe23d26d4a79bb4fe4cab1e243062ee/

	About:
	======
	A tool which enables you to cut thru your i3 windows to split them.
	Whatever the reason you feel like you need to do it. I feel you.
	When I first had this idea it was a gamechanger for migrating back
	from keyboard centric user input to a more mouse oriented approach.
	While I soon realized that none of this made sense, I somehow wanted
	to see and feel how this would work.
	So well. Behold its glory: https://streamable.com/016h2

	Known problems:
	===============
	* Sometimes i3 will reply with this message and split the window in the middle:
	  "ERROR: Failed to find appropriate tiling containers for resize operation"
	* Some applications don't want to be resized. vim-gtk3 for example just resizes
	  never like it should, but sometimes it resizes some more windows while itd at it.
	* However, I don't plan to use this script, so I didn't investigate any of these
	  issues.

	Dependencies:
	=============
	The following binaries have to be in your path:
	 - xbindkeys
	 - xdotool
	 - i3-msg
	 - zsh (tested with 5.5.1, but should work with >=5.4.2)
	 - tee
	 - urxvt or xterm
	 - notify-send (optional. else output will only appear on stdout)
	And, i3 has to be running with a few windows to tear down.

	Allowed actions:
	================
	 - xbindkeys:
	    Starts the xbindkeys service which binds control + mouse button 3 (rmc)
	    to the start and end trigger. This is the only action you should call.
	    The other actions are said start and end trigger which will be called on
	    control+mouse button 3 (rmc) trgger (start) and release (end).
	
	So, this is the command you should run:
	=======================================
	${0} xbindkeys
	EOF
	exit 1

elif [ "$1" = "xbindkeys" ]; then
	xbindkeys --verbose --nodaemon --file <(<<-EOF
	"$0 start"
	  control + b:3

	"$0 end"
	  release+control + b:3
	EOF
	)
	exit
elif [ "$1" = "start" ]; then
	xdotool getmouselocation >~/.i3winsplit.tmp
	exit

fi

# use notify-send when in path`
NOTIFY_SEND="${commands[notify-send]:-cat}"

# $1 = end
setopt SH_WORD_SPLIT
typeset -A after=( ${$(xdotool getmouselocation)//:/ } )
typeset -A before=( ${$(<~/.i3winsplit.tmp)//:/ } )

# which command to send i3
# depending on cut direction.
typeset -A splitcmd=(
	x "split v"
	y "split h"
)

# everything not defined here will spawn
# a new $TERM instance instead
typeset -A class_cmds=(
	# gvim doesn't like to be split
	# gvim    "gvim"
	urxvt   "urxvtcd"
	firefox "xdotool key --window ${before[window]} control+n"
)

{ # The following block will be sent to stdout and when in path notify-send

	# abort when the mouse motion crossed more than one window
	[ $after[window] -ne $before[window] ] && {
		echo "[ $after[window] -ne $before[window] ]"
		echo "ERROR: window ids are different."
		exit
	}

	zmodload zsh/mathfunc
	typeset -A diff
	diff[x]=$(( $before[x] - $after[x] ))
	diff[x_abs]=$(( sqrt($diff[x] * $diff[x]) ))
	diff[y]=$(( $before[y] - $after[y] ))
	diff[y_abs]=$(( sqrt($diff[y] * $diff[y]) ))

	(( $diff[x_abs] > $diff[y_abs] )) \
		&& direction="x" \
		|| direction="y"

	class=${(@)${$(xprop -id ${before[window]} WM_CLASS)}[4]//'"'/}
	echo direction $splitcmd[$direction]

	[ $direction = x ] \
		&& { axis=y; size=XWSHEIGHT } \
		|| { axis=x; size=XWSWIDTH }

	offset_screen=$(( ( $before[$axis] + $after[$axis] ) /2 ))
	eval $(xdotool getwindowgeometry --prefix XWS --shell $before[window])

	offset=$(( $offset_screen - ${(P)$(echo "XWS${axis:u}")} ))

	# remaining percent of the window
	# echo "PERC $(( $offset.0 / ${(P)size} *100 ))"

	xdotool windowactivate $before[window]
	i3-msg "${splitcmd[$direction]}"; sleep .5
	eval "${class_cmds[$class:l]:-$terminal}" &|

	xdotool search --onlyvisible --pid $!
	[ "${class:l}" = "firefox" ] && sleep .5

	xdotool windowactivate $before[window]

	[ $direction = x ] \
		&& i3-msg "resize set height $offset px" \
		|| i3-msg "resize set width $offset px"

} 2>&1 | tee >("$NOTIFY_SEND" "$(cat -)")