#!/bin/bash

###########################################################
## Copyright (c) 2002-2024 Alexey Kuryakin daqgroup@mail.ru
###########################################################

###########################################################
## Find window by title [ and maybe class, pid, exe, host].
## Then move found window to given (x,y) screen position.
## Also new size (width,height) can be assigned.
###########################################################

###########################################################
source $(crwkit which crwlib_base.sh); # Use base library #
source $(crwkit which crwlib_file.sh); # Use file library #
###########################################################

let fatal_notify_uses=0;

function do_help(){
 local name="$(basename ${BASH_SOURCE[0]})";
 echo "$name version 1.0";
 if [ $1 -eq 0 ]; then return 0; fi;
 echo "Copyright (c) 2002-2024 Alexey Kuryakin daqgroup@mail.ru";
 echo "$name - find window by title [ class, pid, exe, host ].";
 echo "Then move found window to given (x,y) screen position.";
 echo "Also new size (width,height) can be assigned.";
 echo "Usage:";
 echo " $name [-options] [parameters]";
 echo "Options:";
 echo " --help           - print help.";
 echo " --version        - print version.";
 echo " -i,--ignore-case - ignore char case";
 echo " -c,--class c     - also match window class (c)";
 echo " -p,--pid p       - also match process PID  (p)";
 echo " -e,--exe e       - also match executable   (e)";
 echo " -h,--host h      - also match host name    (h)";
 echo " --               - end of options, followed params";
 echo "Parameters:";
 echo " title - target window title (mandatory)";
 echo " X     - new window X position or -1 (mandatory)";
 echo " Y     - new window Y position or -1 (mandatory)";
 echo " W     - new window Width      or -1 (optional)";
 echo " H     - new window Height     or -1 (optional)";
 echo "Notes:";
 echo " 1) -opt and --opt options are equivalent.";
 echo "    for example: -pid and --pid are synonyms.";
 echo " 2) title,class,host may be a regexp like '.*'";
 echo " 3) exe must be a basename of executable";
 echo " 4) pid must be a number = process PID";
 echo "Examples:";
 echo " unix $name --help";
 echo " unix $name --version";
 echo " unix $name 'KCalc' 200 100";
 echo " unix $name 'KCalc' -1 -1 800 600";
 echo " unix $name 'KCalc' 200 100 800 600";
 echo " unix $name -p 9812 'KCalc' 200 100";
 echo " unix $name -e kcalc 'KCalc' 200 100";
 echo " unix $name -i -c 'kcalc.Kcalc' 'kcalc' 200 100";
 echo " unix $name -i -e kcalc -c 'kcalc.kcalc' 'KCalc' 200 100";
 echo " unix $name -i -e kcalc -c 'kcalc.kcalc' -h $(hostname) 'KCalc' 200 100";
};

declare opt_i="";
declare host=".*";
declare pids=".*";
declare class=".*";

function call(){
 if [ $# -gt 0 ]; then
  echo "$@";
  eval "$@";
 fi;
};

function val_def(){
 if is_number "$1"; then echo "$1" | xargs; else echo "$2" | xargs; fi;
};

function movewindow(){
 local title="$1";
 local x="$(val_def "$2" "-1")";
 local y="$(val_def "$3" "-1")";
 local w="$(val_def "$4" "-1")";
 local h="$(val_def "$5" "-1")";
 if [ -n "$title" ] && [ -n "$2" ] && [ -n "$3" ]; then
  local win="$(findwindow "$1" 2>/dev/null | awk '{print $1}' | xargs)";
  if [ -n "$win" ]; then
   local num="$(echo "$win" | wc -w)";
   case $num in
    1) call wmctrl -i -r $win -e 0,$x,$y,$w,$h; ;;
    *) fatal 1 "Error: found $num windows. Please specify target window more precisely." ;;
   esac;
  else
   fatal 1 "Error: not found window: \"$title\".";
  fi;
 else
  fatal 1 "Error: invalid arguments: $@.";
 fi;
};

function findwindow(){
 local title="$1"; 
 if [ -n "$title" ]; then
  local win="$(wmctrl -lpx | grep $opt_i " $title" | grep $opt_i " $class " | grep $opt_i " $host " | grep -P " $pids " | grep '0x')";
  if [ -n "$win" ]; then
   echo "$win";
  else
   fatal 1 "Error: not found window: \"$title\".";
  fi;
 else
  fatal 1 "Error: invalid arguments: $@.";
 fi;
};

function exe_pids(){
 if [ -n "$1" ]; then
  pgrep -lf $opt_i "$1" | awk '{print $1}' | xargs;
 fi;
};

function do_opt_i(){
 opt_i="-i";
};

function do_opt_c(){
 if [ -n "$1" ]; then
  class="$1";
 fi;
};

function do_opt_p(){
 local p="$1";
 if [ -n "$p" ]; then
  p="${p//,/ }"; p="${p//:/ }";
  p="$(echo "$p" | xargs)";
  pids="(${p// /|})";
 fi;
};

function do_opt_e(){
 if [ -n "$1" ]; then
  do_opt_p "$(exe_pids "$1")";
 fi;
};

function do_opt_h(){
 if [ -n "$1" ]; then
  host="$1";
 fi;
};

function handle_arguments(){
 movewindow "$@";
};

function fail_on_empty(){
 if [ -z "$1" ]; then
  fatal 1 "Error: missed arguments.\nType unix $(basename ${BASH_SOURCE[0]}) --help for help.";
 fi;
};

function fail_on_missed(){
 while [ -n "$1" ]; do
  if which $1 >/dev/null 2>&1; then
   true;
  else
   fatal 1 "Error: $1 not found.\nPlease install it first.";
  fi;
  shift;
 done;
};

function main(){
 fail_on_empty "$@";
 fail_on_missed wmctrl grep pgrep xargs awk wc;
 while [ -n "$1" ]; do
  case $1 in
   -version|--version)              do_help 0; exit 0; ;;
   -help|--help)                    do_help 1; exit 0; ;;
   -i|-ignore-case|--ignore-case)   do_opt_i; ;;
   -c|-class|--class)               shift; do_opt_c "$1"; ;;
   -p|-pid|--pid)                   shift; do_opt_p "$1"; ;;
   -e|-exe|--exe)                   shift; do_opt_e "$1"; ;;
   -h|-host|--host)                 shift; do_opt_h "$1"; ;;
   --)                              shift; handle_arguments "$@"; break; ;;
   -*)                              fatal 1 "Error: unknown option $1."; ;;
   *)                               handle_arguments "$@"; break; ;;
  esac;
  shift;
  fail_on_empty "$@";
 done;
};

main "$@";

##############
## END OF FILE
##############
