#!/usr/bin/env bash

#
# # Array Module
#
:
#
# ## array\_is\_nonempty()
#
# Checks to see if an array with the name given as the first parameter
# is nonempty.
#
# ### Input Parameters
#
# The first parameter is the name of the array variable.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 if the array is non-empty.
# 1 if the array is empty.
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     the_array=(1 2 3 4 5)
#     if array_is_nonempty the_array
#     then
#       log "the array is not empty"
#     else
#       log "the array is empty"
#     fi
#
#     the_array=()
#     if array_is_nonempty the_array
#     then
#       log "the array is not empty"
#     else
#       log "the array is empty"
#     fi
#
#     user$ $HOME/test
#     the array is not empty
#     the array is empty
#
# ### Code Walkthrough
array_is_nonempty()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # if the array name variable is not empty then and if the length of the named
  # array is greater than 0 then then return true (0) otherwise return false (1)
  # otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging
  if variable_is_nonempty _array_name
  then
    if eval "(( \${#${_array_name}[@]} > 0 ))"
    then
      return 0
    else
      return 1
    fi
  else
    fail "Cannot determine if an array is nonempty"\
      "as an array name was not given."
  fi
}

#
# ## array\_is\_empty()
#
# Checks to see if an array with the name given as the first parameter is empty.
#
# ### Input Parameters
#
# The first parameter is the name of the array variable.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 if the array is empty.
# 1 if the array is non-empty.
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     user$ the_array=()
#     user$ array_is_empty the_array
#     user$ echo $?
#     0
#
#     user$ the_array=(1 2 3 4 5)
#     user$ array_is_empty the_array
#     user$ echo $?
#     1
#
# ### Code Walkthrough
array_is_empty()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # If the array name variable is not empty and if the length of the named array
  # is zero then return true, 0 otherwise return false, 1
  # otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging
  if variable_is_nonempty _array_name
  then
    if eval "(( \${#${_array_name}[@]} == 0 ))"
    then
      return 0
    else
      return 1
    fi
  else
    fail "Cannot push onto array as an array name was not given."
  fi
}

#
# ## array\_length()
#
# Return the length of the given array.
#
# ### Input Parameters
#
# First parameter is the name of the array variable.
#
# ### Stream Outputs
#
# Prints the length of the named array to the STDOUT stream of the calling
# environment.
#
# ### Return Codes
#
# returns 0
#
# ### Failure Scenarios
#
# Fails if the array name, first parameter, is not given.
#
# ### Usage Examples
#
#     user$ the_array=(1 2 3 4 5)
#     user$ array_length the_array
#     5
#
# ### Code Walkthrough
array_length()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" _length

  # If the array name variable is not empty then record the lenght of the array
  # to the length variable. print out the length of the array and return true, 0
  # Otherwise the array name variable was not passed in. This is a programming
  # error and as such we call the fail function which yields a message and
  # a backtrace thus enabling the developer to pinpoint and fix the issue
  # quickly.
  if variable_is_nonempty _array_name
  then
    eval "_length=\${#${_array_name}[@]}"
    printf ${_length}
    return 0
  else
    fail "Cannot push onto array as an array name was not given."
  fi
}

#
# ## array\_last\_element()
#
# Print the last element of the given array.
#
# ### Input Parameters
#
# First parameter is the name of the array variable.
#
# ### Stream Outputs
#
# Prints the last element of the named array to the STDOUT stream of the
# calling environment.
#
# ### Failure Scenarios
#
# Fails if the array name, first parameter, is not given.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Usage Examples
#
#     $ the_array=(one two three four five)
#     $ array_last_element the_array
#     five
#
# ### Code Walkthrough
array_last_element()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" _length _element

  # If the array name variable is not empty, set the length variable's value to
  # the length of the named array.  Set the element variable to the largest
  # element. Print the element at the index of the length of the named array to
  # the calling environments STDOUT stream.
  # Otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging.
  if variable_is_nonempty _array_name
  then
    eval "_length=\${#${_array_name}[@]}"

    eval "_element=\"\${${_array_name}[${_length}]}\""

    printf "%{_element}"
  else
    fail "Cannot push onto array as an array name was not given."
  fi
}

#
# ## array\_first\_element()
#
# Print the first element of the given array.
#
# ### Input Parameters
#
# First parameter is the name of the array variable.
#
# ### Stream Outputs
#
# Prints the first element of the named array to the STDOUT stream of the
# calling environment.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     $ the_array=(one two three four five)
#     $ array_first_element the_array
#     one
#
# ### Code Walkthrough
array_first_element()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" _element _array_length

  # if the array name variable is not empty then determine the length of the
  # named array and assign it into the array_length variable if the array is
  # not empty set the element variable to the value of the first element of the
  # array.  Then print the element to the STDOUT of the calling environment.
  # Return false, 1 if the array is empty and we cannot return an element.
  # otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging
  if variable_is_nonempty _array_name
  then
    eval "_array_length=\"\${#${_array_name}[@]}\""

    if (( _array_length > 0 ))
    then
      eval "_element=\"\${${_array_name}[0]}\""

      printf "${_element}"
    else
      return 1
    fi
  else
    fail "Cannot print the first element of an array"\
      "as an array name was not given."
  fi
}

#
# ## array\_push()
#
# Appends one or more elements to the array with the given name.
#
# ### Input Parameters
#
#   The first parameter is the name of the array variable.
#   Remaining parameters are the elements to be appended to the array.
#
# ### Stream Outputs
#
#   None.
#
# ### Returns
#
#   0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
# Fails if no elements were given (second paramater and beyond).
#
# ### Usage Examples
#
#     $ the_array=(1 2 3 4 5)
#     $ array_push the_array 6
#     $ array_join the_array # print the contents of the array, space separated
#     1 2 3 4 5 6
#
# ### Code Walkthrough
array_push()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # if the array name variable is not empty then remove the array name from the
  # parameters list.  If the array is nonempty then set the elements array to
  # the remaining parameters and declare an element variable.
  # If the number of elements is nonzero then for each element in the passed in
  # elements, append the element to the named array
  # Otherwise if no elements were passed in to push onto the array.
  # This indicates a programming error and as such we call the fail function
  # which yields a message and a backtrace thus enabling quick debugging
  # Otherwise if the array name variable was not passed in. This indicates a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging.
  if variable_is_nonempty _array_name
  then
    shift
    if eval "(( \${#${_array_name}[@]} > 0 ))"
    then
      local _element _elements=("$@")

      if (( ${#_elements[@]} > 0 ))
      then
        for _element in "${_elements[@]}"
        do
          eval "${_array_name}+=(\"\${_element}\")"
        done
      else
        fail "Cannot push elements onto array as no elements were given."
      fi
    fi
  else
    fail "Cannot push elements onto array as an array name was not given."
  fi
}

#
# ## array\_append()
#
# Return the length of the given array.
#
# ### Input Parameters
#
# The first parameter is the name of the array variable.
# Remaining parameters are the elements to append to the end of the array.
#
# ### Stream Outputs
#
# None.
#
# ### Returns
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
# Fails if no elements were given to append to the array.
#
# ### Usage Examples
#
#     user$ the_array=(1)
#     user$ array_append the_array 2 3 4 5
#     user$ array_join the_array # print the contents of the array,
#     space separated.
#     1 2 3 4 5
#
# ### Code Walkthrough
array_append()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # If the array name variable is not empty then remove the array name from the
  # parameters list. Set the elements array to the remaining parameters and
  # declare an element variable.  If the number of elements is nonzero then for
  # each element in the elements append the element to the named array
  # Otherwise if no elements were passed in to push onto the array, this
  # indicates a programming error and as such we call the fail function which
  # yields a message and a backtrace thus enabling developers to pinpoint and
  # fix their code quickly.
  # Otherwise if the array name variable was not passed in. This is also a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging
  if variable_is_nonempty _array_name
  then
    shift

    local _element _elements=("$@")

    if (( ${#_elements[@]} > 0 ))
    then
      for _element in "${_elements[@]}"
      do
        eval "${_array_name}+=(\"\${_element}\")}"
      done
    else
      fail "Cannot push elements onto array as no elements were given."
    fi

  else
    fail "Cannot push onto array as an array name was not given."
  fi
}

#
# ## array\_pop()
#
# Removes the last element of the array and assigns it to variable.
#
# ### Input Parameters
#
#   The first parameter is the name of the array variable.
#   The second parameter is the name of variable to assign.
#
# ### Stream Outputs
#
#   none.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     #!/usr/bin/env bdsm
#
#     modules array
#
#     my_array=(1 2 3 4)
#     echo ${my_array[@]}
#     array_pop my_array my_var
#     echo :$my_var:${my_array[@]}:
#
#     user$ $HOME/test
#     1 2 3 4
#     :4:1 2 3:
#
# ### Code Walkthrough
array_pop()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" temp_array=() index _variable="${2:-}"

  # if the array name variable is not empty then remove the array name from the
  # parameters list. If a variable was specified, assign the first element of
  # the named array into the variable before shifting. Store the value of the
  # first element of the named array. Then shift the array contents over by one
  # using a temporary array. Finally  reassign the shifted temp array contents
  # to the original named variable.
  # Otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging.
  if variable_is_empty _array_name
  then
    fail "Cannot pop from array as an array name was not given."
  fi
  if eval "(( \${#${_array_name}[@]} == 0 ))"
  then
    fail "Cannot pop from array as array '${_array_name}' was empty."
  fi
  if variable_is_nonempty _variable
  then
    eval "${_variable}=\${${_array_name}[\${#${_array_name}[@]}-1]}"
  fi
  eval "unset ${_array_name}[\${#${_array_name}[@]}-1]"
  eval "${_array_name}=( \"\${${_array_name}[@]}\" ) "
}

#
# ## array\_shift()
#
# Removes the first element of the array and prints it.
#
# ### Input Parameters
#
#   The first parameter is the name of the array variable.
#
# ### Stream Outputs
#
#   Prints the first element of the named array to the STDOUT stream of the
#   calling environment.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     #!/usr/bin/env bash
#     source "/usr/local/bdsm/extensions/builtin/core/modules/shell/core/initialize" # Load BDSM framework.
#     modules array
#
#     my_array=(1 2 3 4)
#     echo ${my_array[@]}
#     array_shift my_array
#     echo ${my_array[@]}
#
#     user$ $HOME/test
#     1 2 3 4
#     1
#     2 3 4
#
# ### Code Walkthrough
array_shift()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" temp_array=() index _variable="${2:-}"

  # if the array name variable is not empty then remove the array name from the
  # parameters list. If a variable was specified, assign the first element of
  # the named array into the variable before shifting. Store the value of the
  # first element of the named array. Then shift the array contents over by one
  # using a temporary array. Finally  reassign the shifted temp array contents
  # to the original named variable.
  # Otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging.
  if variable_is_nonempty _array_name
  then
    if variable_is_nonempty _variable
    then
      eval "${_variable}=\${${_array_name}[0]}"
    fi
    unset "${_array_name}[0]"
    eval "${_array_name}=( \"\${${_array_name}[@]}\" ) "
  else
    fail "Cannot shift from array as an array name was not given."
  fi
}

#
# ## array\_unshift()
#
#   Prepends one or more elements to the array whose name is given, in the order
#   given.
#
# ### Input Parameters Parameters
#
#   The first parameter is the name of the array variable.
#   Remaining parameters are the elements to prepend to the array.
#
# ### Stream Outputs
#
#   None.
#   Yields a failure message if no array name was given.
#   Yields a failure message if no elements were given to unshift.
#
# ### Return Codes
#
#   0 denoting success
#
# ### Usage Examples
#
#     $ the_array=(2 3 4 5)
#     $ array_unshift 1
#     user$ array_join the_array # print contents of the array, space separated.
#     1 2 3 4 5
#
#     $ the_array=(4 5)
#     $ array_unshift 3 2 1
#     user$ array_join the_array # print contents of the array, space separated.
#     1 2 3 4 5
#
# ### Code Walkthrough
array_unshift()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # if the array name variable is not empty then remove the array name from the
  # parameters list.  Declare and set the elements variable to the remaining
  # parameters.  If the elements array length is nonzero then concatinate the
  # two arrays into the named array, with the elements of the parameters at the
  # front of the array in the order passed in.
  # otherwise if no elements were passed in to push onto the array.
  # This is a programming error and as such we call the fail function
  # which yields a message and a backtrace thus enabling developers
  # to pinpoint and fix their code quickly.
  # otherwise if the array name variable was not passed in. This is a
  # programming error and as such we call the fail function which yields a
  # message and a backtrace thus enabling quick debugging
  if variable_is_nonempty _array_name
  then
    shift
    local _elements=("$@")
    if (( ${#_elements[@]} > 0 ))
    then
      eval "${_array_name}=(\"${_elements[@]}\" \"\${${_array_name}[@]}\")"
    else
      fail "Cannot push elements onto array as no elements were given."
    fi
  else
    fail "Cannot push onto array as an array name was not given."
  fi
}

#
# ## array\_join()
#
# Joins the named array into a string separated by either a space or
# a given string.
#
# ### Input Parameters
#
# The first parameter is the name of the array variable.
# The second parameter is the separator between elements in the string, this is
# optional and defaults to a space.
#
# ### Stream Outputs
#
# Prints the elements of the named array, separated by either the 2nd parameter
# if given or else a space character, to the STDOUT stream of the calling
# environment.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     $ the_array=(1 2 3 4 5)
#     $ array_join the_array
#     1 2 3 4 5
#
#     $ array_join the_array '.'
#     1.2.3.4.5
#
# ### Code Walkthrough
array_join()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # If the array name variable is not empty then remove the array name from the
  # parameters list. Declare and set the separator variable, default it's value
  # to a space.  Loop over each element of the array, print it out to the
  # calling environment's STDOUT stream with the separator between its entries.
  # Otherwise the array name variable was not passed in. This is a programming
  # error and as such we call the fail function which yields a message and
  # a backtrace thus enabling the developer to pinpoint and fix the issue
  # quickly.
  if variable_is_nonempty _array_name
  then
    shift
    local IFS=${1:-' '}
    eval "printf \"\${${_array_name}[*]}\""
  else
    fail "Cannot join array as an array name was not given."
  fi
}

#
# ## array\_largest()
#
# Outputs the first string in the array with the largest length.
#
# ### Input Parameters
#
# The first element is an array variable name.
#
# ### Stream Outputs
#
# Prints the largest elements of the named array to the STDOUT
# stream of the calling environment.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     $ the_array=(billie bob joe)
#     $ array_largest the_array
#     billie
#
# ### Code Walkthrough
array_largest()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" _index _largest=""

  # If the array name variable is not empty then loop over the array comparing
  # the size of each element with the currently known 'largest' element. If the
  # size of the element at each index is greater than the size of the current
  # largest element then replace the largest variable contents witht the
  # contents of the array at the current index.
  # Print out the value string of the largest array element that was found.
  # Otherwise the array name variable was not passed in. This is a programming
  # error and as such we call the fail function which yields a message and
  # a backtrace thus enabling the developer to pinpoint and fix the issue
  # quickly.
  if variable_is_nonempty _array_name
  then
    eval "
    for (( _index=0 ; _index < \${#${_array_name}[@]} ; _index++ ))
    do
      if (( \${#${_array_name}[\${_index}]} > \${#_largest} ))
      then
        _largest=\${${_array_name}[\${_index}]}
      fi
    done
    "
    printf "%s" "${_largest}"
  else
    fail "Cannot find largest element as an array variable name was not given."
  fi
}

#
# ## array\_sort\_desc()
#
# Sorts the named array contents in descending order.
#
# ### Input Parameters
#
# An array variable name.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     #!/usr/bin/env bash
#     source "/usr/local/bdsm/extensions/builtin/core/modules/shell/core/initialize" # BDSM framework
#     modules array
#
#     arr=(c a d e f b h j i )
#     array_sort_desc arr
#     array_join arr
#     echo
#
#     user$ $HOME/test
#     j i h f e d c b a
#
# ### Code Walkthrough
array_sort_desc()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" _index _largest=""

  # if the array name variable is not empty then replace the named array's
  # contents with the same contents sorted in decending ("reverse") order.
  # otherwise the array name variable was not passed in. This is a programming
  # error and as such we call the fail function which yields a message and
  # a backtrace thus enabling the developer to pinpoint and fix the issue
  # quickly.
  if variable_is_nonempty _array_name
  then
    eval "${_array_name}=(\$(
    echo \"\${${_array_name}[@]}\" | tr ' ' \"\n\" | sort -r
    ))"
  else
    fail "Cannot sort an array in decending order as an array"\
      "variable name was not given."
  fi
}

#
# ## array\_sort\_asc()
#
# Sorts the named array contents in ascending order.
#
# ### Input Parameters
#
# An array variable name.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     #!/usr/bin/env bash
#     source "/usr/local/bdsm/extensions/builtin/core/modules/shell/core/initialize" # BDSM framework
#     modules array
#
#     arr=(c a d e f b h j i )
#     array_sort_asc arr
#     array_join arr
#     echo
#
#     user$ $HOME/test
#     a b c d e f h i j
#
# ### Code Walkthrough
array_sort_asc()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}" _index _largest=""

  # if the array name variable is not empty then replace the named array's
  # contents with the same contents sorted in ascending order.
  # otherwise the array name variable was not passed in. This is a programming
  # error and as such we call the fail function which yields a message and
  # a backtrace thus enabling the developer to pinpoint and fix the issue
  # quickly.
  if variable_is_nonempty _array_name
  then
    eval "${_array_name}=(\$(
    echo \"\${${_array_name}[@]}\" | tr ' ' \"\n\" | sort
    ))"
  else
    fail "Cannot sort an array in ascending order as an array "\
      "variable name was not given."
  fi
}

#
# ## array\_unique()
#
# Sorts the named array contents in ascending order.
#
# ### Input Parameters
#
# An array variable name.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 denoting success
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     #!/usr/bin/env bash
#     source "/usr/local/bdsm/extensions/builtin/core/modules/shell/core/initialize" # BDSM framework
#     modules array
#
#     arr=(a a a b b c c c c d d d d d d)
#     array_unique arr
#     array_join arr
#     echo
#
#     user$ $HOME/test
#     a b c d
#
# ### Code Walkthrough
array_unique()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in. Also initialize the index and largest variables.
  local _array_name="${1:-}" _index _largest=""

  # If the array name variable is not empty then loop over the array finding
  # the largest element using awk.
  # otherwise the array name variable was not passed in. This is a programming
  # error and as such we call the fail function which yields a message and
  # a backtrace thus enabling the developer to pinpoint and fix the issue
  # quickly.
  if variable_is_nonempty _array_name
  then
    eval "${_array_name}=(\$(
    echo \" \${${_array_name}[@]} \" |
    awk -v RS=' ' -v ORS=' ' '!(\$0 in a){a[\$0];print}'
    ))"
  else
    fail "Cannot sort an array in ascending order as an array "\
      "variable name was not given."
  fi
}

# ## array\_is\_even()
#
# Checks to see if an array with the name given as the first parameter
# is even.
#
# ### Input Parameters
#
# The first parameter is the name of the array variable.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 if the array is non-empty.
# 1 if the array is empty.
#
# ### Failure Scenarios
#
# Fails if the array name, the first parameter, is not given.
#
# ### Usage Examples
#
#     user$ cat $HOME/test
#     #!/usr/bin/env bash
#     source "/usr/local/bdsm/extensions/builtin/core/modules/shell/core/initialize" # BDSM framework
#     modules array
#
#     the_array=()
#     printf "($(array_join the_array))"
#     if array_is_even the_array
#     then
#       echo " has an even number of elements"
#     else
#       echo " has an odd number of elements"
#     fi
#
#     the_array=(1)
#     printf "($(array_join the_array))"
#     if array_is_even the_array
#     then
#       echo " has an even number of elements"
#     else
#       echo " has an odd number of elements"
#     fi
#
#     the_array=(1 2 3 4)
#     printf "($(array_join the_array))"
#     if array_is_even the_array
#     then
#       echo " has an even number of elements"
#     else
#       echo " has an odd number of elements"
#     fi
#
#     the_array=(1 2 3 4 5)
#     printf "($(array_join the_array))"
#     if array_is_even the_array
#     then
#       echo " has an even number of elements"
#     else
#       echo " has an odd number of elements"
#     fi
#
#     user$ "$HOME/test"
#     () has an even number of elements
#     (1) has an odd number of elements
#     (1 2 3 4) has an even number of elements
#     (1 2 3 4 5) has an odd number of elements
#
# ### Code Walkthrough
array_is_even()
{
  # Store the array name into a local variable, set to the empty string if it
  # was not passed in.
  local _array_name="${1:-}"

  # If the array name variable is not empty and the length of the array modulo
  # two is zero then the array is even, return true, 0. if the length of the
  # array is odd, return false, 1.
  # If the array name was not passed in, this is a programming error, send a
  # fail message including a backtrace allowing for quick debuging
  if variable_is_nonempty _array_name
  then
    if eval "(( ( \${#${_array_name}[@]} % 2 ) == 0 ))"
    then
      return 0
    else
      return 1
    fi
  else
    fail "Cannot push onto array as an array name was not given."
  fi
}

