#---
## @Synopsis query_list function from init-manager
## $1 - the question
## $2 - the VARIABLE to which to store the answer
## $3 - the default answer
## $4...$n - the options for the list
##
## @Globals none
#---
function query_list()
{
  local question="$1"
  shift
  query_msg "$question"
  select_list "$@"
}

#---
## @Synopsis generate basic spell dir
##
## @Globals QUILL_SPELL_DIR SPELL_NAME DEPENDSISON CONFLICTSON
#---
function create_spell_base(){
  mkdir -p ${QUILL_SPELL_DIR}/${SPELL_NAME}
  cd ${QUILL_SPELL_DIR}/${SPELL_NAME}
  touch DETAILS
  chmod +x DETAILS
  DEPENDSISON=""
  CONFLICTSON=""
}

#---
## @Synopsis download spell's source file
##
## @Globals QUILL_TMP_DIR QUILL_SPELL_DIR SPELL_SRC_FILE SPELL_SRC_URL
## @Globals SPELL_NAME
#---
function get_spell_source(){
  mkdir -p ${QUILL_TMP_DIR}
  cd ${QUILL_TMP_DIR}
  if [[ -e $SPELL_SRC_FILE ]]; then
    message "Found the spell tarball in the quill dir, continuing ..."
  elif [[ -e $SOURCE_CACHE/$SPELL_SRC_FILE ]]; then
    message "Found the spell tarball in the sorcery cache, copying it over ..."
    cp $SOURCE_CACHE/$SPELL_SRC_FILE .
    message "Done."
  else
    wget -c "${SPELL_SRC_URL}"
  fi
  echo
  cd ${QUILL_SPELL_DIR}/${SPELL_NAME}
}

#---
## @Synopsis Print the sha512 hash, a simplified gpg_hashsum
##
## @Globals none
#---
function quill_hash_get() {
  gpg --print-md sha512 "$@" | tr -d '\n ' | tr 'A-F' 'a-f' | cut -d: -f2
}

#---
## @Synopsis Get's gurus info and stuff and puts it into
## @Synopsis $QUILL_QUILLRC or reads it from there
##
## @Globals QUILL_OLD_QUILLRC QUILL_QUILLRC QUILL_MODE QUILL_HOME_DIR
## @Globals GURU_NAME GURU_EMAIL GURU_GPGKEY QUILL_SPELL_DIR QUILL_GIT_DIR
## @Globals QUILL_OUR_CONFIG_VERSION QUILL_SUDO
#---
function quill_rc() {
  local saved
  if [[ -f ${QUILL_OLD_QUILLRC} ]]
  then
    query_msg "With accordance to Source Mage standards moving"
    query_msg "$QUILL_OLD_QUILLRC to $QUILL_QUILLRC"
    mkdir -p ~/.sourcemage/quill
    cp ${QUILL_OLD_QUILLRC} ${QUILL_QUILLRC}
    if [[ -f ${QUILL_QUILLRC} ]]
    then
      query_msg "Removing $QUILL_OLD_QUILLRC"
      rm ${QUILL_OLD_QUILLRC}
    else
      error_msg "Ugghhh... something went wrong..."
    fi
  fi
  if [[ ! -f ${QUILL_QUILLRC} ]] ||
     [[ $QUILL_MODE == reconfigure ]]
  then
    mkdir -p $QUILL_HOME_DIR
    touch $QUILL_QUILLRC
    . $QUILL_QUILLRC # get the contents if there are any (for defaults)
    message "${MESSAGE_COLOR}This will (re)create ${QUILL_QUILLRC} for you${DEFAULT_COLOR}"
    query_string GURU_NAME "${QUERY_COLOR}Please enter your name for the HISTORY entries.${DEFAULT_COLOR}" "$GURU_NAME"
    query_string GURU_EMAIL "${QUERY_COLOR}Please enter your email for the HISTORY entries.${DEFAULT_COLOR}" "$GURU_EMAIL"
    query_string QUILL_SPELL_DIR "${QUERY_COLOR}Where do you want to store generated spells (absolute path)?${DEFAULT_COLOR}" "$QUILL_SPELL_DIR"
    query_string QUILL_GIT_DIR "${QUERY_COLOR}Where is the dir that contains your git grimoires if you have any (absolute path)?${DEFAULT_COLOR}" "$QUILL_GIT_DIR"

    if [[ -z $QUILL_SUDO ]]; then
      saved=n
    else
      [[ -z ${QUILL_SUDO/sudo bash/} ]] && saved=y || saved=n
    fi
    if query "Do you want to use sudo where possible?" $saved; then
      # we need the bash since we call multiple commands at a time
      # and sudo doesn't like just sudo -c "ls; ls; ls"
      QUILL_SUDO="sudo bash"
    else
      QUILL_SUDO="su"
    fi

    [[ -z $GURU_GPGKEY ]] && saved=n || saved=y
    if query "Do you use guru GPG signatures?" $saved ; then
      query_list "${QUERY_COLOR}Please select one of the following keys as the guru signing key${DEFAULT_COLOR}" GURU_GPGKEY "$GURU_GPGKEY" $(gpg -K | sed -n "/^sec[^#]/ s,^sec\s*[^/]*/\(\S*\)\s.*$,\1,p")
    fi

    message "Thank you. Now generating ${QUILL_QUILLRC}"
    cat << QUA > $QUILL_QUILLRC
  QUILL_CONFIG_VERSION="$QUILL_OUR_CONFIG_VERSION"
  GURU_NAME="$GURU_NAME"
  GURU_EMAIL="$GURU_EMAIL"
  QUILL_SPELL_DIR="$QUILL_SPELL_DIR"
  QUILL_GIT_DIR="$QUILL_GIT_DIR"
  QUILL_SUDO="$QUILL_SUDO"
  GURU_GPGKEY="$GURU_GPGKEY"
QUA
    mkdir -p "$QUILL_SPELL_DIR" "$QUILL_GIT_DIR"
    exit 0
  else
     . $QUILL_QUILLRC
     mkdir -p $QUILL_SPELL_DIR
  fi
}

#---
## @Synopsis The welcome message for quill
##
## @Globals QUILL_SPELL_DIR
function quill_welcome() {
  message "Welcome to SourceMage GNU/Linux quill - a spell creator and updater script."
  message "-----------------------------------------------------------------------------"
  message "This makes an immediately useable spell from some minor data or "
  message "updates an exsisting one.."
  message "-----------------------------------------------------------------------------"
  message "The spell will be put into a grimoire/section you define(if you choose to)"
  message "and a tar.bz2 file will be created in $QUILL_SPELL_DIR."
  message "-----------------------------------------------------------------------------"
  message "All lists should be space delimited(dependencies and optional dependencies)"
  message "-----------------------------------------------------------------------------"
}

#---
## @Synopsis used to edit spell files
##
## @Globals EDITOR QUILL_SPELL_DIR SPELL_NAME
#---
function quill_edit() {
  local spell_file type

  message "Now invoking $EDITOR to edit ${1:-spell files}."
  cd ${QUILL_SPELL_DIR}/${SPELL_NAME}
  for spell_file in ${1:-*}
  do
    type=$(file -bi $spell_file)
    if list_find "$type" "text/plain;"
    then
      $EDITOR $spell_file
    fi
  done
  message "All modifications complete."
}

#---
## @Synopsis generate a tarball of the spell
##
## @Globals QUILL_SPELL_DIR SPELL_NAME
#---
function quill_final_tarball() {
  message "Now creating a bziped2 tarball of the spell files ..."
  cd ${QUILL_SPELL_DIR}
  tar -jcvf ${SPELL_NAME}.tar.bz2 ${SPELL_NAME}
  if [[ $? != 0 ]]; then
     error_msg "Failed to create spell tarball."
  else
     message "Spell tarball created successfully."
  fi
}

#---
## @Synopsis function to chmod +x all the relevant spell files
##
## @Globals QUILL_SPELL_DIR SPELL_NAME
#---
function quill_set_executable_bit() {
  local spell_file

  for spell_file in $QUILL_SPELL_DIR/$SPELL_NAME/*
  do
    if [[ "$spell_file" != "$QUILL_SPELL_DIR/$SPELL_NAME/HISTORY" ]]
    then
      chmod +x $spell_file
    fi
  done
}

#---
## @Synopsis cleans out $QUILL_TMP_DIR and/or $QUILL_SPELL_DIR
##
## @Globals QUILL_TMP_DIR QUILL_SPELL_DIR
#---
function quill_purge() {
  local rc

  quill_rc
  message -n "Purging ... "
  if [[ $1 == "tmp" ]]
  then
    [[ -d $QUILL_TMP_DIR ]] && rm -rf $QUILL_TMP_DIR && mkdir $QUILL_TMP_DIR
  elif [[ $1 == "spells" ]]
  then
    [[ -d $QUILL_SPELL_DIR ]] && rm -rf $QUILL_SPELL_DIR && mkdir $QUILL_SPELL_DIR
  else
    [[ -d $QUILL_TMP_DIR ]] && [[ -d $QUILL_SPELL_DIR ]] && rm -rf $QUILL_SPELL_DIR $QUILL_TMP_DIR && mkdir $QUILL_TMP_DIR $QUILL_SPELL_DIR
  fi

  rc=$?
  if [[ $rc == 0 ]]
  then
    message "done."
  else
    error_msg "failed!"
  fi
  exit $rc
}

#---
## @Synopsis checks if spell source urls are valid
## @Synopsis and perhaps changes them if they are trivially fixable
##
## @return 0 if all source urls are either valid or not trivially checkable
## @return 1 otherwise
##
## @Globals SPELL_VERSION SPELL_NAME "source_urls" "sources_and_urls" "version"
#---
function check_source_urls() {
  local su old_su oldest_su source old_source rc i source_num mirror_num

  message "Checking source urls (this may take a while) ..."
  for ((source_num=0; source_num < ${#source_urls[@]}; source_num++))
  do
    mirror_num=0
    for su in ${source_urls[$source_num]}
    do
      if url_verify "$su" > /dev/null
      then
        message "SOURCE${i}_URL[$mirror_num] is ok!"
        rc=0
      else
        # first retry with a changed suffix
        old_su="$su"
        [[ ${su/.gz/.bz2} == $su ]] && su="${su/.bz2/.gz}" || su="${su/.gz/.bz2}"
        if url_verify "$su" > /dev/null
        then
          message "SOURCE${i}_URL[$mirror_num] is ok after changing the file extension!"
          # tricky tricky - if we only change the url, it is likely
          # that the accompanying SOURCE will be bad. So we need to change
          # SOURCEn too. Or just that, if the url contains it as a variable

          # try to unexpanded the url - maybe changing the source is enough
          old_source=$(sed -n "s, $old_su .*,,p" <<< "$sources_and_urls")
          source="$old_source"
          if [[ ${source/.gz/.bz2} == $source ]]
          then
            source="${source/.bz2/.gz}"
          else
            source="${source/.gz/.bz2}"
          fi

          # we need another one since $old_source would match only $old_su
          # and we also need the substituted $old_su
          oldest_su="$old_su"
          substitute_with_variables old_su "$old_source" {SOURCE$i}
          if grep -Eq "\.(bz2|gz)$"  <<< "$old_su"
          then
            # the url most likely does not use SOURCE then
            # however if it does, lets put the substitutions in anyway
            # so we change the url in the file; reparsing is the next call
            # also check if it contains the old expanded VERSION ($version)

            # substitute the longer string first, more likely to give correct results
            # think 1.2 and 1.2.1
            if (( ${#SPELL_VERSION} > ${#version} ))
            then
              substitute_with_variables su "$old_source" {SOURCE$i} "$SPELL_NAME" {SPELL} "$SPELL_VERSION" {VERSION} "$version" {VERSION}
            else
              substitute_with_variables su "$old_source" {SOURCE$i} "$SPELL_NAME" {SPELL} "$version" {VERSION} "$SPELL_VERSION" {VERSION}
            fi

            # some urls may contain other expanded vars that we are not aware of
            if grep -q "$oldest_su" DETAILS
            then # all is fine
              sed -i "s,$oldest_su,$su," DETAILS
            else
              error_msg "Couldn't find $oldest_su in DETAILS,"
              error_msg "probably due to it containing nonstandard variables"
              message "Replace it manually with $su"
            fi
            add_history_entry "DETAILS: Changed SOURCE${i}_URL[$mirror_num] extension"
          else
            substitute_with_variables source "$SPELL_NAME" {SPELL} "$SPELL_VERSION" {VERSION}
            sed -i "s,$old_source,$source," DETAILS
            # we don't know if the SOURCE is expanded or not, trying just both extremes
            substitute_with_variables old_source "$SPELL_NAME" {SPELL} "$SPELL_VERSION" {VERSION}
            sed -i "s,$old_source,$source," DETAILS
            # and with the beautiful syntax last
            old_source="$(tr -d "{}" <<< "$old_source")"
            sed -i "s,$old_source,$source," DETAILS
            add_history_entry "DETAILS: Changed SOURCE${i} extension"
          fi
          rc=0
        else
          # if they are still not ok ask for fixed ones
          error_msg  "SOURCE${i}_URL[$mirror_num] is hopelessly broken! Fix it manually."
          sleep 2
          quill_edit DETAILS
          add_history_entry "DETAILS: Fixed SOURCE${i}_URL[$mirror_num]"
          rc=1
        fi
      fi
      let mirror_num++
    done
    inc_src_num i
  done
  return $rc
}

#---
## @Synopsis dumps the default spell file function, taking into
## account that devel has a new spell file inheritance scheme
##
## @Globals none
#---
function dump_default_function() {
  if ! declare -f real_default_sorcery_$1; then
    # old sorcery
    declare -f real_default_$1
  fi | sed -e '1,3 d' -e '$ d' -e 's,    ,,'
}

#---
## @Synopsis function that displays the version and exits
##
## @Globals QUILL_VERSION
#---
function quill_version() {

  message "quill - $QUILL_VERSION
Copyright (C) 2006-2007 Source Mage
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

Originally written by:
Andraž 'ruskie' Levstik
Rewritten by:
Andraž 'ruskie' Levstik
Jaka 'lynxlynxlynx' Kranjc
Juuso 'iuso' Alasuutari

Contributions by:
Andrew 'afrayedknot' Stitt
Arjan 'abouter' Bouter
"
  exit 0
}

#---
## @Synopsis checks if the parameter is missing
## @Synopsis if not, saves it in QUILL_TARGET and QUILL_ORIG_TARGET
##
## @Globals QUILL_TARGET QUILL_ORIG_TARGET
#---
function check_parameter() {
  [[ -z $1 ]] &&
  error_msg "Missing parameter" &&
  quill_help 101 ||
  QUILL_ORIG_TARGET="$1" &&
  QUILL_TARGET=$(tr '[[:upper:]]' '[[:lower:]]' <<< "$1")
}

#---
## @Synopsis verbosely checks if the argument is a dir and optionally exits
##
## @param path
## @param (optional) be fatal
##
## @return 0 if it is a dir
## @return 1 otherwise
##
## @Globals none
#---
function dir_check() {
  if [[ ! -d $1 ]]
  then
    error_msg "Not a directory: $1!"
    if [[ -z $2 ]]
    then
      return 1
    else
      exit 17
    fi
  fi
  return 0
}

#---
## @Synopsis adds && to all full lines not already ending with &&, \
## @Synopsis or being the last line
##
## @Globals none
#---
function andand_lines() {
  local file="$1"
  sed -e 's/^ *$//' -e 's/[^\\&]\s*$/& \&\&/' "$file" |
    tac |
    awk '{ if (removed!=1){ if (sub("&&$","") > 0){ removed=1 }}; print }' |
    tac > "temporary-$file"
  mv "temporary-$file" "$file"
}


#---
## @Synopsis cleans out various special chars from html
##
## @Globals QUILL_MODULES
#---
function clear_html_specials(){
  local file="$1"
  sed -i -f ${QUILL_MODULES}/html_specials.list $file
}

#---
## @Synopsis checks if spell files are executable and possibly fixes them
## @Synopsis it ignores known files that don't need it
##
## @Globals QUILL_SPELL_DIR SPELL_NAME
#---
function check_executable_bits(){
  local file

  find $QUILL_SPELL_DIR/$SPELL_NAME -type f \
    -wholename '*/[A-Z][A-Z]*[A-Z]' ! -perm /111 |
  grep -vE "HISTORY|TESTS|WIP|MAINTAINER|README|LICENSE|PROVIDES|REPAIR|EXPORTS" |
  while read file; do
    message "${file##*/} does not have the executable bit set!"
    if query "Do you want to add it?" y; then
      chmod +x "$file"
    fi
  done
}

#---
## @Synopsis ensures the long description is wrapped properly
##
## @Globals none
#---
function check_description_wrap(){

  sed -n '/cat *<< *EOF/,/EOF/p' DETAILS > long.description
  awk '{ if(length($0)>a) a=length($0)} \
       END{if(a>80)exit 1; else exit 0}' \
      long.description && rm long.description && return 0

  sed -i '/cat *<< *EOF/,/EOF/d' DETAILS
  sed '1d; $d' long.description | fmt -w 80 > long.description.2
  mv long.description.2 long.description
  echo 'cat << EOF' >> DETAILS
  cat long.description >> DETAILS
  echo 'EOF' >> DETAILS
  add_history_entry "DETAILS: fixed long description wrap"
  rm long.description

}

#---
## @Synopsis checks if anything needs summoning and does so
##
## @param none
##
## @Globals "sources" "sources_and_urls"
#---
function summon_sources() {
    local to_summon source

    message "Summoning ..."
    #download; we are not a grimoire so some hacking is needed
    # also workaround sorcery bug #13412
    to_summon="$sources_and_urls"
    for source in $sources; do
      [[ -e $SOURCE_CACHE/$source ]] &&
      to_summon="$(sed "/^$source /d" <<< "$to_summon")"
    done
    if [[ -z $to_summon ]]; then
      message "Nothing new to summon, all sources found."
    else
      if ! summon -r <<< "$to_summon"; then
        error_msg "Summoning failed, aborting update!"
        query "Do you want to edit DETAILS? (you can retry the update)" n && quill_edit DETAILS
        continue 2 || return 1
      fi
    fi
    echo
}

#---
## @Synopsis sets the parameter to the next free (biggest+1) source number
##
## @param variable
##
## @Globals "version_switch"
#---
function inc_to_unique_src_num() {
  local name="$1" num

  num=$(
    eval ${version_switch:-:}; . DETAILS &> /dev/null
    # the numbers are alphabetically sorted, which is not good enough in the
    # rare case where there are more than 9 sources - so we resort to resorting
    get_source_nums | sort -n | tail -n1
  )
  [[ ! $num ]] && num=1

  eval $name=\$\(\(++num\)\)
}

#---
## @Synopsis increments the parameter by 1 or sets it to 1 if it is empty
##
## @param variable
##
## @Globals none
#---
function inc_src_num() {
  local name="$1" num

  num="${!name}"
  [[ ! $num ]] && num=1

  eval $name=\$\(\(++num\)\)
}

#---
## @Synopsis prints a colored error message
##
## @Globals none
#---
function error_msg() {
  message "$PROBLEM_COLOR$@$DEFAULT_COLOR"
}

#---
## @Synopsis prints a colored query message
##
## @Globals none
#---
function query_msg() {
  message "$QUERY_COLOR$@$DEFAULT_COLOR"
}

#---
## @Synopsis function that displays help and exits
##
## @Globals QUILL_VERSION
#---
function quill_help() {

  message "quill $QUILL_VERSION
Copyright (C) 2006-2007 Source Mage
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

USAGE: quill [OPTIONS]
A spell creator and updater.

OPTIONS:
  --fmxml, -f <SPELL>		get spell data from Freshmeat if possible
  --perlcpan, -c <SPELL>	get spell data from Perl-CPAN if possible
  --rubyraa, -y <SPELL>		get spell data from Ruby Application Archive if possible
  --update, -u <SPELL>		update exsisting spell
  --apprentice, -a		apprentice mode	(default)
  --mage, -m			mage mode (advanced)
  --wizard, -w			wizard mode (expert)(DOES NOTHING FOR NOW)
  --help, -h			display this help
  --version, -v			display version
  --reconfigure, -r		reconfigure settings
  --purge, -p [spells|tmp]	purge internal quill files, defaults to both dirs

EXAMPLES:
  Create a spell; try to get some information from Freshmeat and ask about some
  additional spell files:
    quill -f wormux -m

  Update a spell; try to get some information from Perl-CPAN:
    quill -c wormux -u wormux

  The same can be done with shorter forms (fu, uc, yu and inverses are supported):
    quill -cu wormux
"
  exit ${1:-0}
}


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

