#!/usr/bin/env bash

detect_template()
{
  local extensions_path=$1 _module_path
  shift
  rebuild_path "templates" $extensions_path $@
  _template_path="${rebuilded_path}"

  if [[ -f "${_template_path}.template" ]]
  then
    template_path="${_template_path}.template"
    return 0
  elif [[ -f "${_template_path}" ]]
  then
    template_path="${_template_path}"
    template_name=$(echo -n $@ | sed 's/ /\//g' )
    return 0
  else
    return 1
  fi
}

#
# ## template_exists()
#
# Checks if a named template file exists in the extension_templates_path
#
# ### Input Parameters
#
# First parameter must be the name of a template file, eg. a string.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 if the named template file exists and is nonempty.
# 1 if the named template file does not exist or is empty.
#
# ### Failure Scenarios
#
# Fails if no template name is given.
#
# ### Usage Examples
#
#     user$ {{ setup the scenario }}
#     user$ function_name {{ parameters }}
#     user$ {{ demonstrate the results}}
#
# ### Code Walkthrough
template_exists()
{
  if in_search_paths detect_template "$@"
  then
    log_search "template" "$template_name" "${template_path##${bdsm_path}\/extensions\/}"
    return 0
  else
    return 1
  fi
}

#
# ## install_template()
#
# Installs a named template to a given location.
#
# ### Input Parameters
#
# The first parameter should be the template name.
# Remaining parameters specify the target, mode and owner:
#   owner "<<user>>[:<<group>>]"
#   mode 0755
#   to "/path/to/new/file"
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 if successful
# 1 otherwise
#
# ### Failure Scenarios
#
# Fails if no template name was given.
# Fails if the template name given is a directory.
#
# ### Usage Examples
#
#     user$ install_template "nginx.conf" \
#           to "${nginx_path}/nginx.conf" \
#           mode 0644 owner "${nginx_user}"
#
# ### Code Walkthrough
install_template()
{
  # Declare function local variables, also set source mode and owner defaults
  local _template _name _target _source="${extension_templates_path}" \
    _mode=0644 _owner=$USER

  # While there are still function parameters left store the first parameter
  # as the token and remove it from the parameter list.
  #
  # Then switch based on what the parameter contains.
  #
  # If the parameter is 'to' then teh next parameter contains the target,
  # store it in the target variable and remove it from the parameters list.
  #
  # If the next parameter contains the mode, store it in the mode variable
  # and remove the mode from the parameters list.
  #
  # If the next parameter contains the owner, store it in the owner variable
  # and remove the owner from the parameters list.
  #
  # If the next parameter contains 'from' then store it in the source
  # variable and remove it from the parameters list.
  #
  # If we do not know what the token is
  # If a name has not yet been set then the token must be the name,
  # store it in the name variable otherwise if the target has not yet been
  # set then the token must be the target, store it in the target variable.
  while (( $# > 0 ))
  do
    token="${1}"
    shift
    case "${token}" in
      to)
        _target="$1"
        shift
        ;;
      mode)
        _mode="$1"
        shift
        ;;
      owner)
        _owner="$1"
        shift
        ;;
      from)
        fail 'install_template from is no more valid'
        ;;
      *)
        if variable_is_empty _name
        then
          _name="$token"
        elif variable_is_empty _target
        then
          _target="$token"
        fi
        ;;
    esac
  done

  if template_exists "${_name}"
  then
    _template="${template_path}"
    _name="$(basename "${_name}")"
  else
    fail "No template was found matching '${_name}'."
  fi

  # Create the target path if it does not exist. and then copy the template file
  # to the target location and name given.
  #
  # If the mode variable is not empty then we change the files access mode
  #
  # If the owner variable is not empty then we change the owner of the file
  #
  # Otherwise if the target is not a directory, it must be a fully specified
  # template name. Copy the template directly to the target as a file.
  # TODO: Ensure that the target's path exists.
  # If mode variable is not empty then change the file mode of the target.
  # If owner variable is not empty then change the owner of the target
  ensure_paths_exist "$(dirname "${_target}")"
  if path_exists "${_target}"
  then
    if path_exists "${_target}/${_name}"
    then
      fail "Cannot install the template '${_template}' to ${_target}/${_name}"\
        " as it is a directory"
    else
      copy_file "${_template}" to "${_target}/${_name}"

      if variable_is_nonempty _mode
      then
        chmod "${_mode}" "${_target}/${_name}"
      fi

      if variable_is_nonempty _owner
      then
        chown "${_owner}" "${_target}/${_name}"
      fi
    fi
  else
    copy_file --force "${_template}" to "${_target}"

    if variable_is_nonempty _mode
    then
      chmod_files "${_mode}" "${_target}"
    fi

    if variable_is_nonempty _owner
    then
      chown_files "${_owner}" "${_target}"
    fi
  fi
}

#
# ## seed_template()
#
# Seed a template file replacing all given keys with given values.
#
# ### Input Parameters
#
# First parameter must be the template filename to seed.
# Remaining parameters must come in pairs, the first of each pair specifies
# the key to search and replace in the template file and the second is the
# value to replace {{$key}} with.
#
# ### Stream Outputs
#
# None.
#
# ### Return Codes
#
# 0 for success
#
# ### Failure Scenarios
#
# Fails if no template filename is given.
# Fails if the template given does not exist.
# Fails if no key/value pairs are given.
# Fails if for every key there is no associated value.
# Fails if the intermediate template file does not exist...
#
# ### Usage Examples
#
#    user$ seed_template "/etc/conf.d/${extension}.conf" \
#      prefix_path "${prefix_path}" \
#      init_scripts_path "${init_scripts_path}" \
#      modules_path "${modules_path}" \
#      data_path "${data_path}" \
#      confd_path "${confd_path}" \
#      extension "${extension}"
#
# Note that if you wish to eliminate all unset strings then you pass the pair
#     ".*" ""
# As the last pair of arguments to seed_template
#
# ### Code Walkthrough
seed_template()
{
  # Store the first parameter into the template variable
  local _template="${1:-}"

  # if the template variable is not empty then remove the template from the
  # parameters list and store the remaining parameters into the hash variable
  # If the template file exists on the filesystem and if the hash array is
  # nonempty and if the hash array contains an even number of elements then
  # Loop over the hash and aggregate the replacement strings into their own
  # array. Filter the template with the replacments and if the filtering
  # happened successfully the timestamped template file will exist on the
  # filesystem then move the timestamped version to the target
  #
  # Otherwise if no key/value pairs were specified. This is typically a
  # programming error so send a fail message which will also trigger a
  # backtrace allowing the developer to fix the issue quickly.
  # Also if no template was given or the template file does not exist on the
  # filesystem then fail giving an error message and backtrace for debugging.
  if variable_is_nonempty _template
  then
    shift
    local _hash=("$@") _strings=() temporary=${_template}.${timestamp}.$$

    if file_exists "${_template}"
    then
      if array_is_nonempty _hash
      then
        if array_is_even _hash
        then
          for (( index=0 ; index < ${#_hash[@]} ; index++ ))
          do
            _strings+=(-e "s#{{${_hash[${index}]}}}#${_hash[$((++index))]}#g")
          done

          if sed "${_strings[@]}" ${_template} > ${temporary}
          then
            if file_exists "${temporary}"
            then
              move_file "${temporary}" "${_template}"
            else
              fail "Something went horribly wrong, the template intermediate file "\
                "'${temporary}' does not exist."
            fi
          else
            error "There was an error (?) seeding the template '${_template}'" \
              "Most often this is due to filesystem permissions / disk full."
          fi
        else
          fail "Every replacement key must have a replacement value."
        fi
      else
        fail "Cannot seed template '${_template}'"\
          "as no replacement keys were specified"
      fi
    else
      fail "Can not seed template template file '${_template}' does not exist."
    fi
  else
    fail "Can not install template as no template was given."
  fi
}

update_seed_template()
{
  local _template="${1:-}" _target="${2:-}"
  shift 2
  local  _incoming="${1:-${_target}.incoming}"
  shift || true
  local _hash=("$@") _strings=() _variables="${_target}.var.$$"

  if template_exists "${_template}"
  then
    _template="${template_path}"
  else
    fail "No template was found matching '${_name}'."
  fi

  for (( index=0 ; index < ${#_hash[@]} ; index++ ))
  do
    _strings+=(-e "s#{{${_hash[${index}]}}}#${_hash[$((++index))]}#g")
  done

  sed "${_strings[@]}" ${_template} | grep -E '^[^#]+=' > "${_variables}"

  diff -wN --left-column \
    <( grep -Eo '(^[^#]+=)' "${_target}" 2>/dev/null | sed 's/export //' | sort ) \
    <( grep -Eo '(^[^#]+=)' "${_variables}" | sed 's/export //' | sort ) | \
    awk -F '> ' '/^>/ {print$2}' | \
    xargs -n 1 | \
    xargs -I {} grep "^[^#]*{}" "${_variables}" > "${_incoming}"

  rm "${_variables}"
}
