#---
## @Synopsis Sets up some global variables that contain sources and urls
## @Synopsis delimited by newlines
##
## @Globals "version_switch"
#---
function get_sources_and_urls()
{
  sources_and_urls=$(eval ${version_switch:-:}; . DETAILS &> /dev/null; get_spell_files_and_urls)
  sources=$(cut -d" " -f1 <<< "$sources_and_urls")
  source_urls=()
  explode "$(cut -d" " -f2- <<< "$sources_and_urls")" $'\n' source_urls
}

#---
## @Synopsis Sets a variable from details, first setting the flag version_switch
## @param variable to set
##
## @Globals "version_switch"
#---
function conditional_get_var()
{
  ( eval ${version_switch:-:}; . DETAILS &> /dev/null; eval echo -n \$$1 )
}

#---
## @Synopsis Increments or removes PATCHLEVEL or SECURITY_PATCH. Asks first
## @Synopsis unless the second argument is "skip". Adds variable if necessary.
##
## @param PATCHLEVEL or SECURITY_PATCH - work with which wone?
## @param (optional) skip the query? skip to skip
## @param (optional) remove, increment, add? remove to remove
## @param (optional) default answer for the query, default is n
##
## @Globals none
#---
function update_patchlevel()
{
  local current_value=$(conditional_get_var $1)

  if [[ -z $current_value ]]
  then
    [[ $3 == remove ]] && return
    if [[ $2 == skip ]] || query "Do you want to add $1?" ${4:-n}
    then
      update_patchlevel_sub $1 none add
    fi
  else
    if [[ $2 == skip ]] || query "Do you want to increment $1?" ${4:-n}
    then
      update_patchlevel_sub $1 $current_value $3
    fi
  fi
}

## @Globals SPELL_VERSION
function update_patchlevel_sub()
{
  local current_value=$2 action=$3 new_value count

  if [[ $current_value == none ]]
  then
    new_value=$(count_spaces $1)
    sed -i "s, VERSION=['\"]*${SPELL_VERSION}['\"]*\s*$,&\n$new_value$1=1," DETAILS
    add_history_entry "DETAILS: $1++"
  else
    new_value=$(( current_value + 1 ))
    count=$(grep -c "^[^#]*$1=['\"]*${current_value}['\"]* *$" DETAILS)
    if (( $count  > 1 ))
    then
      echo
      message "Two or more $1 variables with the same value found."
      error_msg "All will be changed - revert the bad ones manually."
      echo
    fi
    if [[ $action == remove ]]
    then #PATCHLEVEL removal on version updates
      sed -i "/^[^#]*$1=['\"]*${current_value}['\"]*/d" DETAILS
    else
      sed -i "/^[^#]*$1=['\"]*${current_value}['\"]*/ s,=.*$,=$new_value," DETAILS
      add_history_entry "DETAILS: $1++"
    fi
  fi
}

#---
## @Synopsis Compute how to insert $1, so = will be aligned properly
## @Synopsis it finds the most used = position
##
## @return string with adequate number of spaces
## @Globals none
#---
function count_spaces()
{
  local count spaces eq_col
  eq_col=$(awk -F '=' '{ if($1)print length($1) }' DETAILS | sort | uniq -c | sort -n | sed -n '$ s,^\s*\S*\s,,p')
  count=$(( $eq_col - ${#1} ))
  for (( i=0 ; i<$count; i++ )) ; do
    spaces="$spaces "
  done
  echo "$spaces"
}

#---
## @Synopsis Checks if the spell is multiversioned and sets the delimiter
## @Synopsis variable (version_switch) if it is
##
## @Globals "versions" "version"
#---
function multiversion_check()
{
  local suggestions
  if [[ ${#versions[@]} != 1 ]]
  then #we have a problem
    message "Oh dear, detected a multiversion spell. Going to cat DETAILS for you "
    message "and then you will tell me which variable I need to set, so I can get "
    message "to the correct version ($version)."
    sleep 3
    cat DETAILS
    suggestions=$(sed -n 's,[{}],,g; s,^.*if.*$\([A-Za-z_]*\).*$,\1,p' DETAILS)
    [[ ! -z $suggestions ]] && query_msg "Perhaps it is one of these:" $suggestions
    query_string version_switch "${QUERY_COLOR}Please enter the appropriate variable. Example: UGU_DEVEL=y${DEFAULT_COLOR} "
  fi
}

#---
## @Synopsis Increment/add PATCHLEVEL or SECURITY_PATCH for any valid version
##
## @Globals SPELL_VERSION SPELL_UPDATED "version"
#---
function user_increment_patchlevel() {
  if query "Do you want to do it for $version?" y; then
    SPELL_VERSION="$version"
    update_patchlevel PATCHLEVEL
    update_patchlevel SECURITY_PATCH
    message "Done."
    SPELL_UPDATED=y
  fi
}

#---
## @Synopsis The core function that ties all the version update stuff
##
## @Globals SPELL_VERSION SPELL_UPDATED GURU_GPGKEY QUILL_SPELL_DIR "version"
## @Globals "versions"
#---
function version_bump() {
  local update_counter="${#versions[@]}" version_switch
  local sources_and_urls sources source_urls source
  local hash current_check i new_value
  if query "Do you want to update $version?" y; then
    query_spell_version
    [[ -z $SPELL_VERSION ]] && error_msg "Empty VERSION!" && continue 2

    #save the chosen version
    sed -i "s/\sVERSION=['\"]*${version}['\"]*\s*$/ VERSION=$SPELL_VERSION/" DETAILS
    SPELL_UPDATED=y

    #check for multiversion spells
    multiversion_check

    # parse the (usually new) source urls
    get_sources_and_urls

    while ! check_source_urls; do
      get_sources_and_urls
    done
    # do it again, needed if the source suffix was changed
    get_sources_and_urls
    echo

    summon_sources

    #update HISTORY - already here, so that the patchlevels come later
    add_history_entries "DETAILS: updated ${version_switch:-spell} to $SPELL_VERSION"
    echo

    # ask for SECURITY_PATCHing
    update_patchlevel SECURITY_PATCH

    # restore patchlevel
    update_patchlevel PATCHLEVEL skip remove

    # remove UPDATED if any
    sed -i "/^\s*UPDATED=/d" DETAILS

    #get hashes and save them, removing any previous hash/gpg
    i=
    for source in $sources; do
      hash=$(quill_hash_get $SOURCE_CACHE/$source)
      # use the original DETAILS, as we already changed the VERSION
      current_check=$(eval ${version_switch:-:}; . DETAILS.orig &> /dev/null; eval echo \$SOURCE${i}_HASH\$SOURCE${i}_GPG\$SOURCE${i}_IGNORE\$\{MD5[${i:-0}]\})

      if [[ -z $current_check ]]; then
        error_msg "Missing SOURCE${i}_HASH/SOURCE${i}_GPG/SOURCE${i}_IGNORE"
        message "Add the appropriate one to the spell!"
        inc_src_num i
        continue
      fi

      #skip SOURCE_IGNORE
      if grep -Eq "volatile|signature|unversioned" <<< "$current_check"; then
        inc_src_num i
        continue
      fi

      # MD5? These contain no :
      if ! grep -q ":" <<< "$current_check"; then
        new_value=$(count_spaces SOURCE${i}_HASH)
        sed -i "s/^.*MD5\[${i:-0}\]=['\"]*${current_check}['\"]*\s*$/${new_value}SOURCE${i}_HASH=sha512:$hash/" DETAILS
        remove_old_sigs "$version"
        upstream_gpg_ad

        inc_src_num i
        continue
      fi

      #SOURCE_GPG?
      if grep -Eq "(^(sha(512|256|1)|md5):.*|UPSTREAM_KEY)" <<< "$current_check"; then
        # UPSTREAM_HASH is rare and probably not fetched - ignoring
        if grep -q "UPSTREAM_KEY" <<< "$current_check"; then
          inc_src_num i
          continue
        fi
        # otherwise just do nothing, SOURCE_HASH handling comes next
      else
        #it is a non-upstream gpg
        echo "SOURCE${i}_GPG=$current_check"
        if ! grep -q "gurus.gpg" <<< "$current_check"; then
          error_msg "This looks like an upstream keyring and should be marked as such."
          error_msg "Probably with :UPSTREAM_KEY at the end of the $current_check."
          error_msg "Do not replace it!"
        fi
        if ! query "Do you want to replace SOURCE${i}_GPG with a hash?" n; then
          # sign it and continue
          gpg --default-key $GURU_GPGKEY -v --digest-algo SHA512 -o $QUILL_SPELL_DIR/$SPELL_NAME/$source.sig --detach-sign $SOURCE_CACHE/$source
          echo
          remove_old_sigs "$version"
          upstream_gpg_ad

          inc_src_num i
          continue
        fi
      fi

      upstream_gpg_ad
      # it is either a SOURCE_HASH or the user wants to replace SOURCE_GPG
      # SOURCE_GPG usually has unexpanded variables, while we have the expanded
      unexpand_source_gpg || {
      inc_src_num i
      continue; }


      #it is either a SOURCE_HASH or the user wants to replace SOURCE_GPG
      new_value=$(count_spaces SOURCE${i}_HASH)
      sed -i "s/^.*SOURCE${i}_[^=]*=['\"]*${current_check}.*['\"]*\s*$/${new_value}SOURCE${i}_HASH=sha512:$hash/" DETAILS

      # remove sigs, trying not to touch any that are still needed
      remove_old_sigs "$version"

      inc_src_num i
    done

    echo
  else
    let update_counter-=1
  fi
  [[ $update_counter == 0 ]] && continue 2 # there were no updates

}


#---
## @Synopsis Loops over relevant spell versions and runs the passed command
## @Synopsis over each version
##
## @Globals none
#---
function main_update_loop() {
  local version versions=()

  #fetch current versions, ignoring SCM ones
  versions=( $(sed -n 's/\s*\<VERSION=//p' DETAILS |
              grep -Eiv '\$[(]date *+|cvs|svn|tla|git|scm' | sort | uniq) )
  [[ -z ${versions[@]} ]] && error_msg "No versions to update!" && continue

  message "Current relevant version(s): ${versions[@]}"

  for version in "${versions[@]}"; do
    $1
  done

}

#---
##
## 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
##
#---
