#!/bin/bash
#
# GOSNAP: Good Old Snap
#
# Script to emulate the Aero Snap feature in Windows 7
#   Use -L or -R flags to snap left or right
#   Use -l or -r flags to snap dynamically (intermediate default position)
#   Use -M flag to maximize
#   Use -m flag to toggle maximized state
#   Use -N flag to minimize
#   Use -n flag to minimize dynamically (intermediate default position)
#   Use -d flag to reset the window state to default
#   Use -i flag to print window info to stdout
#
# wmctrl -e g,x,y,w,h (any value set to -1 won't be changed)
#   g = window gravity (just set to 0)
#   x = window x position
#   y = window y position
#   w = window width
#   h = window height
#

# CONFIGURATION
# =============

# Default window geometry to use with -d
#   Format: gravity, x_pos, y_pos, width, height)
window_default="0,10,60,826,556"

# The x position reported by xdotool when the window is snapped left/right.
#   For some reason, snapping the window to 0,0 does not actually register as 0,0.
#   Use the -i flag while the terminal window is snapped to the left or the right
#   to get the values unique to your screen.
left_origin_x=10
right_origin_x=692

# Add this to the half screen width value for snapping left/right.
#   If you see gaps on the left or right when you snap, you may need to adjust this.
half_width_adjust_left=1
half_width_adjust_right=1

# Adjust these to avoid issues with gaps
snap_left_x=0
snap_left_y=0
snap_right_x=0
snap_right_y=1

# Use wmctrl bug avoidance
#   For some reason, wmctrl intermittently snaps to the wrong position.
#   Doing "snap_default && snap_maximize" before snapping left/right seems to fix it.
#   The trade-off using this fix is that snapping left/right has a very slight delay.
wmctrl_bug_fix=true

function main
{
	check_args $@
	check_command wmctrl
	check_command xdotool
	get_window_state
	
	while getopts ":LlRrMmNndih" opt;do
		case $opt in
		L)
			snap_left
			;;
		l)
			if $window_snapped_right;then
				snap_default
			else
				snap_left
			fi
			;;
		R)
			snap_right
			;;
		r)
			if $window_snapped_left;then
				snap_default
			else
				snap_right
			fi
			;;
		M)
			snap_maximize
			;;
		m)
			if $window_maximized;then
				snap_default
			else
				snap_maximize
			fi
			;;
		N)
			snap_minimize
			;;
		n)
			if $window_maximized || $window_snapped_left || $window_snapped_right;then
				snap_default
			else
				snap_minimize
			fi		
			;;
		d)
			snap_default
			;;
		i)
			print_info
			;;
		h)
			usage
			exit
			;;
		*)
			echo "Invalid option: -$OPTARG" >&2
			usage
			exit 1
			;;
		esac
	done
}

function check_args
{
	if [[ "$@" == "" ]];then
		usage
	fi
}

function usage
{
	echo
	echo "Usage: gosnap [-L | -l | -R | -r | -M | -m | -N | -n | -d | -i]"
	echo "  -L    snap left"
	echo "  -l    snap left dynamically"
	echo "  -R    snap right"
	echo "  -r    snap right dynamically"
	echo "  -M    maximize window"
	echo "  -m    toggle maximize window"
	echo "  -N    minimize window"
	echo "  -n    minimize window dynamically"
	echo "  -d    resize to default geometry (current default: $window_default)"
	echo "  -i    print window information"
	echo
}

function check_command
{
	if [[ ! -e $(which $1) ]];then
		echo -e "\nERROR: $1 was not found on your system!\n"
		# If we're on Ubuntu, use the c-n-f functionality
		if [[ -x /usr/lib/command-not-found ]];then
			python /usr/lib/command-not-found -- $1
		elif [[ -x /usr/share/command-not-found ]];then
			python /usr/share/command-not-found -- $1
		fi
		usage
		exit 1
	fi
}

function get_window_state
{
	screen_width=$(xdpyinfo | grep 'dimensions:' | cut -f 2 -d ':' | cut -f 1 -d 'x' | xargs)
	window_id=$(xdotool getactivewindow)
	window_id_hex=$(printf 0x%x $window_id)
	window_properties=$(xprop -id $window_id)
	window_state=$(echo $window_properties | grep "_NET_WM_STATE(ATOM)")
	window_geometry=$(xdotool getwindowgeometry $window_id)
	window_pos_x=$(echo $window_geometry | awk '{print $4}' | awk -F, '{print $1}')
	window_pos_y=$(echo $window_geometry | awk '{print $4}' | awk -F, '{print $2}')
	window_width=$(echo $window_geometry | awk '{print $8}' | awk -Fx '{print $1}')
	window_height=$(echo $window_geometry | awk '{print $8}' | awk -Fx '{print $2}')
	window_max_horiz=false
	if [ $(echo $window_state | grep -o "_NET_WM_STATE_MAXIMIZED_HORZ") ];then
		window_max_horiz=true
	fi
	window_max_vert=false
	if [ $(echo $window_state | grep -o "_NET_WM_STATE_MAXIMIZED_VERT") ];then
		window_max_vert=true
	fi
	window_maximized=false
	if $window_max_horiz && $window_max_vert;then
		window_maximized=true
	fi
	window_snapped_left=false
	if $window_max_vert && [ $window_pos_x == $left_origin_x ];then
		window_snapped_left=true
	fi
	window_snapped_right=false
	if $window_max_vert && [ $window_pos_x == $right_origin_x ];then
		window_snapped_right=true
	fi
}

function snap_maximize
{
	wmctrl -r :ACTIVE: -b add,maximized_vert,maximized_horz
}

function snap_minimize
{
	xdotool getactivewindow windowminimize
}

function snap_default
{
	wmctrl -r :ACTIVE: -b remove,maximized_vert,maximized_horz
	wmctrl -r :ACTIVE: -e $window_default
}

function snap_left
{
	if $wmctrl_bug_fix; then snap_default && snap_maximize;fi
	halfw=$((($screen_width/2)+$half_width_adjust_left))
	wmctrl -r :ACTIVE: -b remove,maximized_vert,maximized_horz &&\
	wmctrl -r :ACTIVE: -b add,maximized_vert &&\
	wmctrl -r :ACTIVE: -e 0,$snap_left_x,$snap_left_y,$halfw,-1
}

function snap_right
{
	if $wmctrl_bug_fix; then snap_default && snap_maximize;fi
	halfw=$((($screen_width/2)+$half_width_adjust_right+$snap_right_x))
	wmctrl -r :ACTIVE: -b remove,maximized_vert,maximized_horz &&\
	wmctrl -r :ACTIVE: -b add,maximized_vert &&\
	wmctrl -r :ACTIVE: -e 0,$halfw,$snap_right_y,$halfw,-1
}

function print_info
{
	echo "screen_width = $screen_width (half = $(($screen_width/2)))"
	echo "Window $window_id ($window_id_hex)"
	echo "$(echo $window_geometry | tr -d '\n' | grep -o 'Position.*' | xargs)"
	echo "window_max_horiz = $window_max_horiz"
	echo "window_max_vert = $window_max_vert"
	echo "window_maximized = $window_maximized"
	echo "window_snapped_left = $window_snapped_left"
	echo "window_snapped_right = $window_snapped_right"
	exit
}

main $@

# OTHER NOTES
#
# xdotool windowmove $(xdotool getactivewindow) 0 0
# xdotool windowmove $(xdotool getactivewindow) 100% 100%
# xdotool windowsize $(xdotool getactivewindow) 50% 100%
# xdotool getwindowgeometry $(xdotool getactivewindow)
# 
# No window shadow: add this line to /etc/environment then relog
#   MUFFIN_NO_SHADOWS=1
#
