#!/bin/sh
# this file contains functions functions that are 100% POSIX compatible
#
# Copyright (C) 2012  Björn Bidar
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#

appname=${0##*/}
libsh_ver=2.3
LIBSH_REV=2230



# base library path for import if  $SH_LIBRARY_PATH is not set
readonly IMPORT_LIBRARY_PATH=/usr/lib:/usr/lib32:/usr/local/lib:$HOME/.local/lib 
 
shload()
#################################################################
# import sh libs that are in $IMPORT_LIBRARY_PATH and $SH_LIBRARY_PATH
# vars:
# IMPORT_LIBRARY_PATH set by  import
# SH_LIBRARY_PATH     set by user use to add a library path
#################################################################    
{
    __shl_error_status=1
    case $1 in
      /*)
	    . $1
	__shl_error_status=$?
	;;
      *)
	    LIBSH_shload_old_ifs=$IFS
	    IFS=:
	    for __lib_dir in ${SH_LIBRARY_PATH} ${IMPORT_LIBRARY_PATH} }; do
		IFS=$LIBSH_shload_old_ifs
		if [ -f $__lib_dir/$1 ] ; then 
		    . ${__lib_dir}/$1
		    __shl_error_status=$?
		    break
		fi
		IFS=:
	    done
	    IFS=$LIBSH_shload_old_ifs
	    ;;
    esac
    unset  __lib __lib_dir LIBSH_shload_old_ifs
    return $__shl_error_status
}

import() 
# . file with check if already . it
{
    while [ ! $# = 0 ] ; do
	LIBSH_import_old_ifs=$IFS
	IFS=:
	for __lib in $LIBSH_IMPORTED ; do
	    IFS=$LIBSH_import_old_ifs
	    if [ "$__lib" = $1 ] ; then
		__lib_aready_imported=true
		break 
	    fi
	    IFS=:
	done 
	IFS=$LIBSH_import_old_ifs
	if [   -z $__lib_aready_imported  ] ; then
	    if shload $1 ;then
		LIBSH_IMPORTED=$LIBSH_IMPORTED:$1
	    else
		echo "error loading $1" >&2
		return 2
	    fi
	fi
	shift
	unset __lib_aready_imported LIBSH_import_old_ifs
    done  
    return 0 # return how many libs were already imported
}
#########################################################################

detectDE()
{
    # daken from xdg-open
    # see https://bugs.freedesktop.org/show_bug.cgi?id=34164
    unset GREP_OPTIONS

    if [ -n "${XDG_CURRENT_DESKTOP}" ]; then
      case "${XDG_CURRENT_DESKTOP}" in
         ENLIGHTENMENT)
           __DE=enlightenment;
           ;;
         GNOME)
           __DE=gnome;
           ;;
         KDE)
           __DE=kde;
           ;;
         LXDE)
           __DE=lxde;
           ;;
         MATE)
           __DE=mate;
           ;;
         XFCE)
           __DE=xfce
           ;;
      esac
    fi

    if [ x"$__DE" = x"" ]; then
      # classic fallbacks
      if [ x"$KDE_FULL_SESSION" != x"" ]; then __DE=kde;
      elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then __DE=gnome;
      elif [ x"$MATE_DESKTOP_SESSION_ID" != x"" ]; then __DE=mate;
      elif $(dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1) ; then __DE=gnome;
      elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then __DE=xfce;
      elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then __DE=xfce
      elif echo $DESKTOP | grep -q '^Enlightenment'; then __DE=enlightenment;
      fi
    fi

    if [ x"$DE" = x"" ]; then
      # fallback to checking $DESKTOP_SESSION
      case "$DESKTOP_SESSION" in
         gnome)
           __DE=gnome;
           ;;
         LXDE|Lubuntu)
           __DE=lxde; 
           ;;
         MATE)
           __DE=mate;
           ;;
         xfce|xfce4|'Xfce Session')
           __DE=xfce;
           ;;
      esac
    fi

    if [ x"$DE" = x"" ]; then
      # fallback to uname output for other platforms
      case "$(uname 2>/dev/null)" in 
        Darwin)
          __DE=darwin;
          ;;
      esac
    fi

    if [ x"$DE" = x"gnome" ]; then
      # gnome-default-applications-properties is only available in GNOME 2.x
      # but not in GNOME 3.x
        which gnome-default-applications-properties > /dev/null 2>&1  || __DE="gnome3"
    fi

    echo $__DE
    unset __DE
}

d_msg() # display msgs and get input 
#################################################################################################
# NOTE: needs kdialog ( or zenity ) to display graphical messages and get input in gui		#
#################################################################################################
# usage:											#	       
#  d_msg [modifer] topic msg									#
#  modifers:											#	       
#  ! msg is an error/faile message								#	
#  i msg is an msg/input ( work's not properly in cgi and with xmessage : terminal)		#
#  f msg is an yes/no msg/test									#	       
#  l msg is an list of items ( nyi in cgi: terminal)						#
#    no modifer msg is an normal msg								#
#################################################################################################
#												#
# vars:											        #
# DMSG_DE     =`detectDE` (default)  	# d_msg detects wich DE is installed and                #
#                                       # uses the coresponding dialog app                      #
# DMSG_GUI_APP=kdialog|zenity|xmessage  # tell d_msg which tool it has to use for gui output    #
#  					# either zenity, kdialog or xmessage(not recommend)     #
# 				                                                                #
#											        #
# DMSG_GUI                      	# if not zero use graphical dialog, else cfg gui        #
# DMSG_ICON				# icon that d_msg uses when is runned in gui mode       #
#                                       # if not set icon xorg is used 	                        #
#											        #
#											        #
# DMSG_APP 				# say DMSG to use $DMSG_APP in cli                      #
#                                       # ( dialog or cgi_dialog )	                        #  
#												#
# DMSG_APPNAME			        # set appname for d_msg default is $appname             #
# DMSG_ERR_STATUS = 1                   # return value that is returned when modifer is !       # 
# DMSG_XBUTTONS	= 'not:1,set:2'		# -buttons parameter for xmessage when modifer is i     #
#################################################################################################
{
    if [ ! $# -lt 2 ] ; then
	unset dmsg_return_status
	if [  "${DMSG_GUI}" = true ] || [ ! $DMSG_GUI = 0 ] ; then
	    if [  -z "$DMSG_GUI_APP" ] ; then
		DMSG_DE=$(detectDE)
	    fi
	    case $DMSG_DE in
		kde) DMSG_GUI_APP=kdialog ;; 
		gnome|xfce|mate|lxde) DMSG_GUI_APP=zenity ;;
 generic) DMSG_GUI_APP=kdialog ;;
	    esac	
	    # FIXME or remove me
	    if  ! which $DMSG_GUI_APP > /dev/null; then
		for dmsg_gdialog_app in kdialog zenity xmessage ; do
		    if  which $dmsg_gdialog_app > /dev/null; then
			DMSG_GUI_APP=$dmsg_gdialog_app
                        break
		    else
			dmsg_gdialog_app=false
		    fi
		done
		if [ $dmsg_gdialog_app = false ] ; then
		    DMSG_GUI=0 
		    d_msg ! 'Warning' "No gui dialog tool found"
		fi
	    fi 
	    case $DMSG_GUI_APP in 
		kdialog)
		    case $1 in 
			!)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}" --title "$2" --error "$3" 
			    dmsg_return_status=${DMSG_ERR_STAUS:=1}  
			    ;;
			i) kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}" -title "$2" --inputbox "$3" 
			    dmsg_return_status=$?
			;;
			l)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}"
			    --title "$2" --menu \
			    "$3" "$4" "$5" "$6" "$7" "$8" "$9" 4
			    shift ; dmsg_return_status=$? ;;
			f)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}"  --title "$2" --yesno "$3" 
			    dmsg_return_status=$? ;;
			*)  kdialog --icon ${DMSG_ICON:=xorg} --caption "${DMSG_APPNAME:=$appname}" -title "$1" --msgbox "$2" 
			    dmsg_return_status=$? ;;
		    esac
		    ;;
		zenity) 
		    case $1 in 
			!) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2 - ${DMSG_APPNAME:=$appname}" \
			    --error --text="$3"
			    dmsg_return_status=${DMSG_ERR_STAUS:=1}   
			    ;;
			i) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2 - ${DMSG_APPNAME:=$appname}" \
			    --entry --text="$3"
			    dmsg_return_status=$? 
			    ;;
			l) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2 - ${DMSG_APPNAME:=$appname}" \
			    --column='' --text="$3"\
                        --list 
			    dmsg_return_status=$? 
			    ;;
			f) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$2 - ${DMSG_APPNAME:=$appname}" \
			    --question --text="$3" 
			    dmsg_return_status=$? 
			    ;;
			*) zenity --window-icon=${DMSG_ICON:=xorg}  --title="$1 - ${DMSG_APPNAME:=$appname}" \
			    --info --text="$2" 
			    dmsg_return_status=$? ;;
		    esac
		    ;;
		xmessage)
		    case $1 in
			!) xmessage -center -title "$2 - ${DMSG_APPNAME:=$appname}" "err: "$3"" ;
			    dmsg_return_status=${DMSG_ERR_STAUS:=1} 
			    ;;
			f) xmessage -center -title "$2  -${DMSG_APPNAME:=$appname}" -buttons no:1,yes:0 "$3" 
			    dmsg_return_status=$? 
			    ;;	
			i) 
			    if [ -z $DMSG_XBUTTONS ] ; then
				DMSG_XBUTTONS='not:1,set:2'
			    fi
			    xmessage -center -title "$appname - "$2"" -print -buttons $DMSG_XBUTTONS "$3"
			    dmsg_return_status=$?
			    ;;
			l) xmessage -center -title "$2 - ${DMSG_APPNAME:=$appname}" -print \
			    -buttons "$3","$4","$5","$6","$7","$8","$9" ; dmsg_return_status=$? ;;
			*) xmessage -center -title "$1 - ${DMSG_APPNAME:=$appname}" "$2" ; dmsg_return_status=$? ;;
		    esac
		    ;;
	    esac
	else
	    case ${DMSG_APP:-native} in
		dialog)
		    case "$1" in 
			!) dialog --title "$2 -${DMSG_APPNAME:=$appname}" --infobox "error:$3" 0 0 ; dmsg_return_status=${DMSG_ERR_STAUS:=1};;
			#!) cgi_dialog ! "$3" ; dmsg_return_status=${DMG_ERR_STAUS:=1}  ;;
			f) dialog --title "$2 - ${DMSG_APPNAME:=$appname}" --yesno "$3"   0 0 
			    dmsg_return_status=$?
			    ;;
			i) dialog --title "$2 - ${DMSG_APPNAME:=$appname}" --inputbox "$3" 0 0
			    dmsg_return_status=$?		 
			    ;;
			*) dialog --title "$1 -${DMSG_APPNAME:=$appname}" --infobox "$2" 0 0  ;;
			#*) cgi_dialog "$2" ; dmsg_return_status=$? ;;
		    esac
		    ;;
		native)
		    case "$1" in
			!) echo  "$3" >&2; dmsg_return_status=${DMSG_ERR_STAUS:=1} ;;
			f)  echo ""$3" y|n"
			    read a 
			    if [ ! $a = y ] ; then
				dmsg_return_status=1;
			    fi
			    ;;
			i) 
			    echo "$3" >&2
			    read  a 
			    if [ -z "$a" ] ; then
				dmsg_return_status=1;
			    else
				echo $a
			    fi
			    ;;
			*)  echo "$2"   ; dmsg_return_status=$? ;;
		    esac
		    ;;
	    esac
	    
	fi
    fi
    return $dmsg_return_status
}

## functions for fake_arrays ########################################################################
# fake arrays are array emulated by using : as $IFS
#
#
#####################################################################################################
# NOTE:
# unlike arrays normal arrays the index of arrays starts with 1 instead of 0
# if a fake_array function gets a 0 as index parameter all entrys in the array where selected 
#
# 	for example:
#
#		var=`read_farray fu:bar 0`
#	       +var='fu bar'
#####################################################################################################	

get_farray_lenght() { # get lenght of fake array
    if [ $# -ge 1 ] ; then 
        LIBUSE_getf_old_ifs=$IFS
	IFS=:
	for var in $1 ; do
	    get_farry_lenght_count=$(( $get_farry_lenght_count + 1 ))
	done
	IFS=$LIBUSE_getf_old_ifs=$IFS
	echo  ${get_farry_lenght_count:-0}
	unset get_farry_lenght_count var LIBUSE_getf_old_ifs
    else
	echo 0
    fi
}

read_farray() { # read fake array
    if [ $# = 2 ] ; then
	#\\ifdef DEBUG_FARRAY_LESS_OUTPUT
	ifen_disable_option verbose
	ifen_disable_option xtrace
	#\\endif
	LIBUSE_readf_old_ifs=$IFS
	IFS=:
	for var in  $1 ; do
	    _read_farry_count=$(( $_read_farry_count + 1 ))
	    if [ $2 -eq  $_read_farry_count ] || [ $2 -eq 0 ] ; then
		if [ ! -z $var ] ; then
		    echo $var
		fi
	    fi
	done
	IFS=$LIBUSE_readf_old_ifs
	#\\ifdef DEBUG_FARRAY_LESS_OUTPUT
	ifde_enable_option verbose
	ifde_enable_option xtrace
	#\\endif
    fi
    unset _read_farry_count  var LIBUSE_readf_old_ifs
}

write_farray() {  # write fake array   
    if [ $# -eq 3 ] ; then
	#\\ifdef DEBUG_FARRAY_LESS_OUTPUT
	ifen_disable_option verbose
	ifen_disable_option xtrace
	#\\endif
	farry_content=$( eval echo \$$1)
	if [ ! -z "$farry_content" ] ; then 
		    if [ $( get_farray_lenght "$farry_content") = $(( $2 - 1 )) ] ; then
			eval $1=$farry_content:$3
		    else
			eval $( echo $1)=$( echo $farry_content | sed "s/$(read_farray $farry_content $2 )/$3/")
		    fi
	elif [ $2 = 1 ] ; then
	    eval $1=$3
	else
	    return 1
	fi
	#\\ifdef DEBUG_FARRAY_LESS_OUTPUT
	ifde_enable_option verbose
	ifde_enable_option xtrace
	#\\endif
    fi
}


test_input () { 
  LIBSH_test_input_N=$(( $# + 1 ))
  LIBSH_test_input_errmsg="$( read_farray "$err_input_messages" $LIBSH_test_input_N)"
  if [ -n "$LIBSH_test_input_errmsg" ] ; then
      d_msg ! 'wrong input' "$LIBSH_test_input_errmsg"
      if [   $# = 0   ]; then
	return 1
      else
	  return $LIBSH_test_input_N
      fi
  fi
}

