#!/bin/bash
#---------------------------------------------------------------------
## Handles storage of state information, incluing depends and package
## files. Also handles looking information up about what is installed
## and what depends on what.
##
## @Copyright Copyright (C) 2002 The Source Mage Team <http://www.sourcemage.org>
#---------------------------------------------------------------------

#---------------------------------------------------------------------
##
## Adds a dependency to the a depends database file.  Returns 1 if the
## 3rd or 4th fields are not valid.
##
## @param  Depends status file
## @param  Name of the "parent" spell
## @param  Name of the spell the parent spell depends on
## @param  "on" or "off" depending on whether the user installed the dependency
## @param  Type of dependency (required or optional)
## @param  option to pass to C&lt;configure&gt; if the dependency is installed
## @param  option to pass to C&lt;configure&gt; if the dependency is not installed
##
## @Example add_depends kdelibs alsa-driver on optional --with-alsa --without-alsa
##
#---------------------------------------------------------------------
function add_depends()
{ # $1=depends file $2=spell, $3=depends, $4=on/off, $5=optional/required, $6=on arg, $7=off arg
  debug "libstate" "add_depends() - $*"

  #already here for some reason
  search_depends_status_exact "$@" >/dev/null  && return 0

  local depends_status=$1
  shift

  # ensure the info is valid (perhaps add check that spells exist?)
  list_find "on off" "$3" || return 1
  list_find "required optional runtime suggest" "$4" || return 1

  # Allow add_depends to override previous ones for the same pair of spells
  search_depends_status "$depends_status" "$1" "$2" >/dev/null &&
  remove_depends_status "$depends_status" "$1" "$2"

  local t_status
#  lock_start_transaction "$depends_status" t_status
  echo "$1:$2:$3:$4:$5:$6" >> "$depends_status"
#  lock_commit_transaction "$depends_status"

  return 0

}

#---------------------------------------------------------------------
##
## In case you want to search in all the fields of the $1
##
## Arguments can be regexp
##
## Prints out the matching line(s)
## @Stdout the matching line(s)
## @param depends file
## @param spell
## @param depends
## @param on/off
## @param optional/required
## @param on arg
## @param off arg
##
## @return 0 if entry was found
## @return 1 if entry was not found
## @return 2 on error
##
#---------------------------------------------------------------------
function search_depends_status_exact()
{ # $1=depends file $2=spell, $3=depends, $4=on/off, $5=optional/required, $6=on arg, $7=off arg

  local depends_status=$1
  shift

  local a1 a2 a3 a4 a5 a6
  esc_str "$1" a1; esc_str "$3" a3
  esc_str "$4" a4; esc_str "$5" a5; esc_str "$6" a6
  esc_provider_str "$2" a2
  debug "libstate" "search_depends_status_exact: [$a1:$a2:$a3:$a4:$a5:$a6]"

  lock_file "$depends_status"
  grep "^$a1:$a2:$a3:$a4:$a5:$a6$" "$depends_status"
  rc=$?
  unlock_file "$depends_status"

  return $rc
}

#---------------------------------------------------------------------
##
## Search depends status, dont do anything escaping.
##
## Arguments can be regexp
##
## Prints out the matching line(s)
## @Stdout the matching line(s)
## @param depends file
## @param spell
## @param depends
## @param on/off (optional)
## @param optional/required (optional)
## @param on arg (optional)
## @param off arg (optional)
##
#---------------------------------------------------------------------
function search_depends_status_simple()
{ # $1=depends file $2=spell, $3=depends, $4=on/off, $5=optional/required, $6=on arg, $7=off arg

    local depends_status=$1
    shift

    local a1 a2 a3 a4 a5 a6
    esc_str "$1" a1; esc_provider_str "$2" a2
    a3=${3:-.*} ; a4=${4:-.*}
    esc_str "$5" a5; esc_str "$6" a6
    a5=${5:-.*} ; a6=${6:-.*}

    lock_file "$depends_status"
    grep "^$a1:$a2\(([^:]*)\)\?:$a3:$a4:$a5:$a6$" "$depends_status"
    unlock_file "$depends_status"
}


#---------------------------------------------------------------------
## @param depends file
## @param spell
## @param depends (optional)
## @Stdout matching lines
## In case you want to search by spell or dependency in $1
##
## Arguments can be regexp
##
## Prints out the matching line(s)
##
#---------------------------------------------------------------------
function search_depends_status()
{ # $1=depends file $2=spell, $3=(opt)depends

  [[ -z $2 ]] && return 1
  local depends_status=$1
  shift

  local spell
  esc_str "$1" spell
#  lock_file "$depends_status"
  if [[ -z $2 ]]; then
    grep "^$spell:" "$depends_status"
  else
    local depends
    esc_provider_str "$2" depends
    grep "^$spell:$depends:" "$depends_status"
  fi
#  unlock_file "$depends_status"
}



#---------------------------------------------------------------------
##
## @param depends file
## @param spell
## @param dependency spell
## @Stdout list of options
##
## Returns a list of options for ./configure from $1
## Primarily aimed at generating $OPTS contents
##
## Prints out one line of output
#---------------------------------------------------------------------
function get_depends_options()
{ # $1=depends_status $2=spell

  local depends_status=$1
  shift

  [ -z "$1" ] && {
    message "${PROBLEM_COLOR}${1:-<null>} is not a spell name${DEFAULT_COLOR}"
    return
  }

  local START
  esc_str "$1" START
  debug "libstate" "get_depends_options() - START=$START"
  lock_file "$depends_status"
  awk -F ':' -v start=$START '$1 == start { OPTS = OPTS " " ($3 == "on" ? $5 : $6) } END { print OPTS }' $depends_status 2> /dev/null
  unlock_file "$depends_status"
}


#---------------------------------------------------------------------
##
## Arguments can be regexp, and all but the spell are optional
##
## @param depends file
## @param spell
## @param depends
## @param on/off
## @param optional/required
## @param on arg
## @param off arg
##
#---------------------------------------------------------------------
function remove_depends_status()
{ # $1=depends file $2=spell, $3=(OPT)depends, $4=(OPT)on/off, $5=(OPT)optional/required, $6=(OPT)on arg, $7=(OPT)off arg

   local depends_status=$1
   shift

    local a1 a2 a3 a4 a5 a6
    # arguments 1 and 2 are spell names, which might have characters that
    # look like regexps, 5 and 6 might like funny too
    # contrast 3 and 4 which are "on", "off", "required" or "optional"
    # if they are regexps its probably desired so dont escape those
    esc_str "$1" a1; esc_str "$2" a2
    a1=${a1:-.*}; a2=${a2:-.*}

    a3=${3:-.*} ; a4=${4:-.*}

    esc_str "$5" a5; esc_str "$6" a6
    a5=${a5:-.*}; a6=${a6:-.*}
    [[ "$a5" == "[none]" ]] && a5="\\[none\\]"

    local t_status
    lock_start_transaction "$depends_status" t_status
    sedit "/^$a1:$a2:$a3:$a4:$a5:$a6$/D" "$t_status"
    lock_commit_transaction "$depends_status"
}

#---------------------------------------------------------------------
## Toggle optional and suggested dependencies on/off
##
## @param depends file
## @param spell
## @param dependency
##
#---------------------------------------------------------------------
function toggle_depends_status() {
  local depends_status=$1
  shift

  local spell dependency
  esc_str "$1" spell; esc_str "$2" dependency

  local t_status
  lock_start_transaction "$depends_status" t_status
  awk -F ':' -v OFS=':' \
    -v re="^$spell:$dependency:(on|off):(optional|suggest):" -- \
    '$0 ~ re { $3 = ($3 == "on") ? "off" : "on" } { print; }' \
    $depends_status > $t_status
  lock_commit_transaction "$depends_status"
}

#---------------------------------------------------------------------
## Changes the $spell's provider of $feature to a $new one. Can also
## toggle it to be enabled or disabled.
##
## @param depends file
## @param spell
## @param new provider
## @param feature
## @param on/off
##
#---------------------------------------------------------------------
function change_spell_provider() {
  local depends_status=$1
  shift

  local spell new_provider feature enabled
  esc_str "$1" spell
  esc_str "$2" new_provider
  esc_str "$3" feature
  enabled=$4

  local t_status
  lock_start_transaction "$depends_status" t_status
  if [[ -z $enabled ]]; then
    sed -i "s/^$spell:[^:]*($feature):/$spell:$new_provider($feature):/" $t_status
  else
    sed -i "s/^$spell:[^:]*($feature):[^:]*:/$spell:$new_provider($feature):$enabled:/" $t_status
  fi
  lock_commit_transaction "$depends_status"
}

#---------------------------------------------------------------------
## Sets up the uncommitted depends file. If the name isn't
## found in the hash table create it. If the file already exists
## move it to the abandoned depends directory and start with a new one.
## The uncommitted_hash hash table should be hash_export'ed to
## make it through the call to make.
##
## @param spell
## @param variable name to put the filename name in (pass by reference)
##
#---------------------------------------------------------------------
function get_uncommitted_depends_file() {
    local SPELL=$1
    local temp_spell_depends
    hash_get_ref "uncommitted_hash" $SPELL temp_spell_depends

    if ! [[ $temp_spell_depends ]] ; then
      temp_spell_depends="$UNCOMMITTED_DEPENDS/$SPELL"
      hash_put "uncommitted_hash" "$SPELL" "$temp_spell_depends"

      mkdir -p "$ABANDONED_DEPENDS"
      mv "$temp_spell_depends" "$ABANDONED_DEPENDS" &>/dev/null
      mv "$temp_spell_depends:*" "$ABANDONED_DEPENDS" &>/dev/null

      mkdir -p "$UNCOMMITTED_DEPENDS"
      touch "$temp_spell_depends"
    fi
    eval "$2=\"$temp_spell_depends\""
}

#---------------------------------------------------------------------
## Get the uncommitted sub-depends file. Uses get_uncommitted_depends_file.
## This file is intended for use by the sub-dependee.
##
## @param spell
## @param variable name to put the filename in
#---------------------------------------------------------------------
function get_uncommitted_sub_depends_file() {
  local SPELL=$1
  local upvar=$2
  local __tmp
  get_uncommitted_depends_file "$SPELL" __tmp
  # : cannot be in spell names, so we can take advantage of the namespace
  __tmp=${__tmp}:s
  # we can assume that the parent directory exists because
  # get_uncommitted_depends_file creates it
  touch "$__tmp"
  eval "$2=\"$__tmp\""
}

#---------------------------------------------------------------------
## Get the uncommitted sub-depends file. Uses get_uncommitted_depends_file
## This file is intended for use by the requester.
##
## @param spell
## @param variable name to put the filename in
#---------------------------------------------------------------------
function get_uncommitted_rsub_depends_file() {
  local SPELL=$1
  local upvar=$2
  local __tmp
  get_uncommitted_depends_file "$SPELL" __tmp
  # : cannot be in spell names, so we can take advantage of the namespace
  __tmp=${__tmp}:rs
  # we can assume that the parent directory exists because
  # get_uncommitted_depends_file creates it
  touch "$__tmp"
  eval "$2=\"$__tmp\""
}

#---------------------------------------------------------------------
## Add a sub-dependency.
##
## @param sub-depends file
## @param requester file
## @param sub-dependee
## @param sub-depends
#---------------------------------------------------------------------
function add_sub_depends() {
  $STD_DEBUG
  remove_sub_depends "$@" || return 1
  local file=$1
  shift

  local t_file
  lock_start_transaction "$file" t_file
  echo "$1:$2:$3" >> "$t_file"
  lock_commit_transaction "$file"
}

#---------------------------------------------------------------------
## Search in sub-depends file.
##
## @param sub-depends file
## @param requester file (optional)
## @param sub-dependee (optional)
## @param sub-depends (optional)
#---------------------------------------------------------------------
function search_sub_depends() {
  $STD_DEBUG
  local file=$1
  shift
  local a1 a2 a3
  esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
  a1=${a1:-.*}
  a2=${a2:-.*}
  a3=${a3:-.*}

  lock_file "$file"
  grep "^$a1:$a2:$a3$" "$file"
  unlock_file "$file"
}

#---------------------------------------------------------------------
## Remove a sub-depends.
##
## @param sub-depends file
## @param requester
## @param sub-dependee
## @param sub-depends
#---------------------------------------------------------------------
function remove_sub_depends() {
  $STD_DEBUG
  local file=$1
  shift

  test -f $file || return

  local a1 a2 a3
  esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
  a1=${a1:-.*}; a2=${a2:-.*}; a3=${a3:-.*}

  local t_file
  lock_start_transaction "$file" t_file
  sedit "/^$a1:$a2:$a3$/D" "$t_file"
  lock_commit_transaction "$file"
}

#---------------------------------------------------------------------
## Default depends and default provider api
## default depends examples:
##
## default xfree86 provider to ImageMagick is xfree86
## ImageMagick:X11-LIBS:xfree86
##
## default answer to optional_depends graphviz for ImageMagick is "no"
## ImageMagick:graphviz:off
##
##
## default provider examples:
## use xorg as X11-LIBS even if its optional
## xorg:X11-LIBS:on
##
## use xfree86 as X11-LIBS unless the [none] option exists (and use that instead)
## xfree86:X11-LIBS:off
#---------------------------------------------------------------------

#---------------------------------------------------------------------
##
## add default depends entry, if $3 is a spell $4 must be on/off
## if $3 is a PROVIDER $4 must be a spell
##
## @param depends file
## @param spell
## @param depends/PROVIDER
## @param on/off
##
#---------------------------------------------------------------------
function add_default_depends() {
        debug "libstate" "add_default_depends() - $*"

        #already here
        search_default_depends "$@" >/dev/null  && return 0

        local file=$1
        shift
        # ensure the info is valid... (this is redundant if calling
        # from sorcery, but that may not always be the case...
        if [[ $3 != on ]] && [[ $3 != off ]] ; then
          return 1
        fi

        { [[ ! $1 ]] && [[ ! $2 ]] ; } && return 1

        if [[ $1 ]] && ! codex_does_spell_exist $1 &>/dev/null; then
          return 1
        fi

        if [[ $2 ]] && ! codex_does_spell_exist $2; then
          return 1
        fi

        lock_start_transaction "$file" tfile
        remove_default_depends $tfile $1 $2
        echo "$1:$2:$3" >> $tfile
        lock_commit_transaction $file

       return 0

}

#---------------------------------------------------------------------
##
## Arguments can be regexp, $2, $3 and $4 are optional
## Caller must lock the file
##
## @param depends file
## @param spell
## @param depends/PROVIDER
## @param on/off/spell
##
#---------------------------------------------------------------------
function remove_default_depends() {

        local file=$1
        shift
        test -e $file || return

        local a1 a2 a3
        esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3

        a3=${a3:-.*}

        local t_file
        lock_start_transaction "$file" t_file
        sedit "/^$a1:$a2:$a3$/D" $t_file
        lock_commit_transaction "$file"
}

#---------------------------------------------------------------------
##
## Arguments can be regexp, $2 $3 and $4 are optional
##
## @param depends file
## @param spell
## @param depends/PROVIDER
## @param on/off/spell
##
#---------------------------------------------------------------------
function search_default_depends() {

        local default_depends=$1
        shift
        [[ -s $default_depends ]] || return

        local a1 a2 a3
        esc_str "$1" a1; esc_str "$2" a2; esc_str "$3" a3
        a3=${a3:-.*}

        debug "libstate" "search_default_depends: [$a1:$a2:$a3]"
        lock_file "$default_depends"
        grep "^$a1:$a2:$a3$" $default_depends
        rc=$?
        unlock_file "$default_depends"

        return $rc
}


#---------------------------------------------------------------------
##
## Arguments can be regexp, $3 and $4 are optional
##
## @param depends file
## @param spell
## @param PROVIDER
## @param on/off
##
#---------------------------------------------------------------------
function add_default_provider() {
  debug "libstate" "add_default_depends() - $*"

  #already here
  search_default_provider "$@" >/dev/null  && return 0

  local file=$1
  shift

  #ensure the info is valid...
  { [[ ! $1 ]] && [[ ! $2 ]] ; } && return 1
  { [[ $3 != on ]] && [[ $3 != off ]] ; } && return 1

  if [[ $1 ]] && ! codex_does_spell_exist $1 &>/dev/null ; then
    return 1
  fi
  if [[ $2 ]] && ! codex_does_service_exist $2 &>/dev/null ; then
    return 1
  fi

  lock_start_transaction "$file" tfile
  remove_default_provider $tfile "" $2
  echo "$1:$2:$3" >> $tfile
  lock_commit_transaction $file

  return 0
}

# these are the same, as their countparts but are here for completeness
# and incase they do someday diverge
function remove_default_provider() {
  remove_default_depends "$@"
}

function search_default_provider() {
  search_default_depends "$@"
}

#---------------------------------------------------------------------
## @param cache file
## @param spell name
##
## Removes the spell info from the passed file ($VERSION_STATUS)
##
#---------------------------------------------------------------------
function remove_version_cache()  {
  local file=$1
  lock_start_transaction "$file" t_file
  sed -i "/^$2 /d" $t_file
  lock_commit_transaction $file
}

#---------------------------------------------------------------------
## @param cache file
## @param spell name
## @param version
## @param patchlevel
## @param security patch
## @param updated
##
## Given a spell and the factors that affect queuing, this function
## adds the info to the passed file (usually $VERSION_STATUS)
##
#---------------------------------------------------------------------
function add_version_cache()  {
  local file=$1
  shift
  remove_version_cache "$file" $1

  lock_start_transaction "$file" t_file
  echo "$1 ${2:-0} ${3:-0} ${4:-0} ${5:-0}" >> $t_file
  lock_commit_transaction $file
}

#---------------------------------------------------------------------
##
## Adds an entry to the SPELL_STATUS file
##
## Arguments may either be SPELL, ACTION, VERSIONS, or just
## ACTION if there exists SPELL and VERSIONS variables already
## set.
## @param spell OR action
## @param (if spell) action
## @param (if spell) version
##
#---------------------------------------------------------------------
function add_spell_status()
{ #$1=spell, $2=action, $3=version, OR $1=action.

  local spell action version date
  if [ $# -eq 1 ] ; then
    spell="$SPELL"
    action="$1"
    version="$VERSION"
  else
    spell=$1
    action=$2
    version=$3
  fi
  [[ $spell ]] && [[ $action ]] && [[ $version ]] || return 1
  date=`date +%Y%m%d`
  lock_start_transaction "$SPELL_STATUS" tSPELL_STATUS
  echo "$spell:$date:$action:$version" >> $tSPELL_STATUS
  lock_commit_transaction $SPELL_STATUS

}

#---------------------------------------------------------------------
## @param spell name
##
## Given a spell, status (installed, held, etc), and version, add_spell
## adds the spell to the /var/state/sorcery/packages file
##
#---------------------------------------------------------------------
function add_spell()  {
  remove_spell  $1
  add_spell_status $1 $2 $3
}

#---------------------------------------------------------------------
## @param spell status file
## @param spell
## @param version (optional)
## @Stdout matching lines
##
## Arguments can be regexp
##
## Prints out the matching line(s)
##
#---------------------------------------------------------------------
function search_spell_status() {
  [[ -z $2 ]] && return 1
  local spell_status=$1
  shift

  local spell
  esc_str "$1" spell
  lock_file "$spell_status"
  if [[ -z $2 ]]; then
    grep "^$spell:" $spell_status
  else
    local version
    esc_str "$2" version
    grep "^$spell:$version:" $spell_status
  fi
  unlock_file "$spell_status"
}

#---------------------------------------------------------------------
##
## @param spell ( [A-Za-z0-9_-] )
## @param version (optional and may not contain spaces or colons; '.' and '*' have special meaning)
## @param variable to set
## @Stdout last matching line ( only one even if there are more )
##
## Searches the SPELL_STATUS file for a spell and optionally
## a version.
##
## Prints out the matching spell's status
## @return 1 only for critical problems ( missing SPELL_STATUS file )
## @return 0 for all other cases ( even when spell is not found )
##
#---------------------------------------------------------------------
function query_spell_status()
{ #$1=spell, $2=(OPT)version

  local return_var __status
  [[ -e $SPELL_STATUS ]] || return 1

  lock_file "$SPELL_STATUS"
  if [[ -z $3 ]]; then
    [[ -z $2 ]] && return 0
    return_var="$2"
    __status=$(awk -F: -v spell="$1" '$1 == spell { status = $3 } END { print status }' "$SPELL_STATUS" 2>/dev/null)
  else
    return_var="$3"
    __status=$(awk -F: -v spell="$1" -v version="$2" '$1 == spell && $4 == version { status = $3 } END { print status }' "$SPELL_STATUS" 2>/dev/null)
  fi
  unlock_file "$SPELL_STATUS"

  eval "$return_var=\"\$__status\""
  return 0
}

#---------------------------------------------------------------------
## @Type API
## @param spell name
##
## @return 0 if the given spell's status is "installed"
#---------------------------------------------------------------------
function real_spell_installed() {
  local status
  query_spell_status "$1" status
  [[ $status == installed ]]
}


#---------------------------------------------------------------------
## @param spell name
##
## @return 0 if the given spell's status is "held"
##
#---------------------------------------------------------------------
function real_spell_held()      {
  local status
  query_spell_status "$1" status
  [[ $status == held ]]
}

#---------------------------------------------------------------------
## @Type API
## @param spell name
##
## @return 0 if the given spell's status is "installed" or "held"
#---------------------------------------------------------------------
function real_spell_ok() {
  local status
  query_spell_status "$1" status
  [[ $status == installed ]] || [[ $status == held ]]
}


#---------------------------------------------------------------------
## @Type API
## @param Provider name
##
## @return 0 if any provider of $1 is installed
#---------------------------------------------------------------------
function real_provider_ok() {
  for spell in $(search_depends_status_exact $DEPENDS_STATUS '.*' ".*($1)" \
                 'on' '.*'  '.*' |cut -f2 -d:|cut -f1 -d\(|sort -u); do
    spell_ok $spell && return 0
  done
  return 1
}

#---------------------------------------------------------------------
## @Type API
## @param Spell name
## @param Provider name
## @param If empty get the uncommited spell info, if anything else get info from the committed ($DEPENDS_STATUS) database. If the uncommited db doesnt exist (maybe we're not casting) use DEPENDS_STATUS
##
## @return 0 if a provider could be found 1 if not
## @return 0 if a dependency from $1 on $2 is enabled, 1 otherwise.
## @stdout the provider name(s)
#---------------------------------------------------------------------
function real_get_spell_provider() {
  local dep_status
  if [[ $3 ]] ; then
    dep_status=$DEPENDS_STATUS
  else
    hash_get_ref uncommitted_hash $1 dep_status
    [[ $dep_status ]] || dep_status=$DEPENDS_STATUS
  fi
  search_depends_status_exact $dep_status "$1" ".*($2)" \
                 'on' '.*'  '.*' '.*' |cut -f2 -d:|cut -f1 -d\(|sort -u
}

#---------------------------------------------------------------------
## @Type API
## @param Spell name
## @param Target spell name
## @param If empty get the uncommited spell info, if anything else get info from
##        the committed ($DEPENDS_STATUS) database. If the uncommited db doesnt
##        exist (maybe we're not casting) use DEPENDS_STATUS
##
## @return 0 if a dependency from $1 on $2 is enabled, 1 otherwise.
## @stdout the provider name(s)
#---------------------------------------------------------------------
function real_is_depends_enabled() {
  local dep_status
  if [[ $3 ]] ; then
    dep_status=$DEPENDS_STATUS
  else
    hash_get_ref uncommitted_hash $1 dep_status
    [[ $dep_status ]] || dep_status=$DEPENDS_STATUS
  fi
  [[ -n $(search_depends_status_simple $dep_status "$1" "$2" 'on' ) ]]
}


#---------------------------------------------------------------------
## @param spell name
##
##  @return 0 if the given spell's status is "exiled"
##
#---------------------------------------------------------------------
function real_spell_exiled()    {
  local status
  query_spell_status "$1" status
  [[ $status == exiled ]]
}


#---------------------------------------------------------------------
## @param spell to remove status of
## Removes all specified offending entries in SPELL_STATUS
##
#---------------------------------------------------------------------
function remove_spell_status()
{ #$1=spell to remove status of

  lock_start_transaction "$SPELL_STATUS" tSPELL_STATUS
  grep  -v  "^$1:" $SPELL_STATUS  >  $tSPELL_STATUS
  lock_commit_transaction $SPELL_STATUS

}

#---------------------------------------------------------------------
## @param spell name
##
## Removes the given spell from the /var/state/sorcery/packages file.
## if C<EXILE> is set, the spell is changed to "exiled" in the file.
##
#---------------------------------------------------------------------
function remove_spell()  {
  debug  "libsorcery" "Running remove_spell() on $1"
  remove_spell_status $1
  if  [  -n  "$EXILE"  ];  then
    add_spell_status $1 "exiled" "0.0"
  fi
}


#---------------------------------------------------------------------
## @Stdout All spell stati
## Just here to round out the SPELL_STATUS functions so that
## SPELL_STATUS doesn't have to mentioned in libsorcery
##
#---------------------------------------------------------------------
function all_spell_status()
{
  lock_file "$SPELL_STATUS"
  cat $SPELL_STATUS
  unlock_file "$SPELL_STATUS"
}


#---------------------------------------------------------------------
## @param spells
## sets &lt;spells&gt;'s status to held
##
#---------------------------------------------------------------------
function set_held () {
    local t_status
    lock_start_transaction "$SPELL_STATUS" t_status
    for to_hold in $@; do
        sedit 's/\(^'$(esc_str $to_hold)':[^:]*:\)installed/\1held/' $t_status
    done
    lock_commit_transaction $SPELL_STATUS
}


#---------------------------------------------------------------------
## @param spells
## sets &lt;spells&gt;'s status to exiled
##
#---------------------------------------------------------------------
function set_exiled () {
    local TO_DISPELL=""
    local TO_EXILE
    local MY_STATUS

    for TO_EXILE in $@; do
        query_spell_status "$TO_EXILE" MY_STATUS
        case "$MY_STATUS" in
            "" )
                add_spell_status $TO_EXILE exiled 0.0
                message "Spell '$TO_EXILE' exiled."
                ;;
            "exiled" )
                message "${MESSAGE_COLOR}Spell ${DEFAULT_COLOR}'$TO_EXILE'" \
                    "${MESSAGE_COLOR}is allready exiled.${DEFAULT_COLOR}"
                ;;
            "installed" )
                local ask="'$TO_EXILE' is installed."
                ask="${ask} Do you want to dispel and exile it ?"
                query "$ask" &&
                TO_DISPELL="$TO_DISPELL $TO_EXILE"
                ;;
            * )
                message "${PROBLEM_COLOR}Can't exile spell" \
                    "${DEFAULT_COLOR}'$TO_EXILE'${PROBLEM_COLOR}" \
                    "which has status '$MY_STATUS'${DEFAULT_COLOR}"
                ;;
        esac
    done
    if [ -n "$TO_DISPELL" ]; then
        dispel -e $TO_DISPELL
    fi
}


#---------------------------------------------------------------------
## @param spells
## resets <spells>'s 'exiled' status
##
#---------------------------------------------------------------------
function set_unexiled () {
    local MY_STATUS
    local TO_UNEXILE
    for TO_UNEXILE in $@; do
        query_spell_status "$TO_UNEXILE" MY_STATUS
        if [ x"$MY_STATUS" == x"exiled" ]; then
            remove_spell $TO_UNEXILE
        else
            message "${MESSAGE_COLOR}Can't unexile spell${DEFAULT_COLOR}" \
                "'$TO_UNEXILE'${MESSAGE_COLOR}, it's not exiled${DEFAULT_COLOR}"
        fi
    done
}


#---------------------------------------------------------------------
## @param spells
## sets <spells>'s status to installed
##
#---------------------------------------------------------------------
function set_unheld () {
    local t_status
    lock_start_transaction "$SPELL_STATUS" t_status
    for to_hold in $@; do
        sedit 's/\(^'$(esc_str $to_hold)':[^:]*:\)held/\1installed/' $t_status
    done
    lock_commit_transaction $SPELL_STATUS
}


#---------------------------------------------------------------------
## @param status (installed, held, exiled or ok[for the first two])
## @Stdout spells
## returns all spells that are in that status
##
#---------------------------------------------------------------------
function get_all_spells_with_status () {
  local status=$1
  lock_file $SPELL_STATUS
  if [[ $status != ok ]]; then
    awk -F: -v status="$status" '$3 == status { print $1 }' $SPELL_STATUS
  else
    awk -F: '$3 == "installed" || $3 == "held" { print $1 }' $SPELL_STATUS
  fi
  unlock_file $SPELL_STATUS
}


#---------------------------------------------------------------------
## @param variable
## @param value
## @param command (optional)
##
## Modifies (or adds) an entry in the local/config.
## If "command" is the third argument, a space will separate the
## variable and value rather than the equals sign.
##
#---------------------------------------------------------------------
function modify_local_config() {
    debug "libstate" "modify_local_config() - $*"
    modify_config $LOCAL_CONFIG "$@"
}


#---------------------------------------------------------------------
## @param Filename
## @param variable
## @param value
## @param command (optional)
##
## Modifies (or adds) an entry in the local/config.
## If "command" is the third argument, a space will separate the
## variable and value rather than the equals sign.
##
#---------------------------------------------------------------------
function modify_config()  {

  debug "libstate" "modify_config() - $*"
  local FILE=$1
  shift;

  if ! [[ $1 ]]; then
    debug "libstate" "modify_config() - Warning: No name given for config option."
    return 1
  fi

  local TEMP separator EQUALS_COL VARIABLE

  if ! test -f $FILE; then
    if ! test -d $(smgl_dirname $FILE); then
      if test -e $(smgl_dirname $FILE); then
        message "Trying to modify $FILE, but $(smgl_dirname $FILE) is not a directory"
        return 1
      fi
      mkdir -p $(smgl_dirname $FILE)
    fi &&
    touch $FILE || {
      message "Failed to create $FILE"
      return 1
    }
  fi

  # remove previous reference
  lock_start_transaction "$FILE" tFILE
  grep  -v  "^[[:blank:]]*${1}${separator}" $FILE >  $tFILE

  # justifying...
  EQUALS_COL=$((20-${#1}))
  [ $EQUALS_COL -lt 0  ] && EQUALS_COL=0
  TEMP=""
  for (( ; EQUALS_COL>0 ; EQUALS_COL-- )) ; do
    TEMP="$TEMP "
  done

  debug "libstate" "modify_config() - entering new value $VARIABLE $seperator $@ into $tFILE"
  # put the new value and justification in
  # assign the value in a way that can be overriden from the environment #14454
  if [[ $3 == command ]]; then
    echo "${TEMP}${1} \"$2\""
  else
    echo "${TEMP}${1}=\"\${$1:-$2}\""
  fi >> $tFILE

  lock_commit_transaction $FILE

}

#---------------------------------------------------------------------
## @param Filename
## @param variable
## @param command (optional)
##
## Removes an entry in the local/config.
## If "command" is the third argument, a space will separate the
## variable and value rather than the equals sign.
##
#---------------------------------------------------------------------
function remove_config()  {

  debug "libstate" "remove_config() - $*"
  local FILE=$1
  shift;

  if ! [[ $1 ]]; then
    debug "libstate" "remove_config() - Warning: No name given for config option."
    return 1
  fi

  local separator

  # what to use as separator?
  if [[ $2 == command ]]
  then separator=" "
  else separator="=" ; fi

  # remove previous reference
  lock_start_transaction "$FILE" tFILE
  grep  -v  "^[[:blank:]]*${1}${separator}" $FILE >  $tFILE
  lock_commit_transaction $FILE

}

#---------------------------------------------------------------------
##
## This software 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 software 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 software; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
##
#---------------------------------------------------------------------
# vim: filetype=sh:tabstop=4:shiftwidth=4:expandtab
