#!/bin/bash
#---------------------------------------------------------------------
##
## Set of functions for working with an associative array type data
## structure.  Values can be stored and retrieved using strings as
## the index into the data structure instead of numbers.
##
## The hash data structure provided in this file allows you to store
## values into fields of a table.  The 'hash_put' function takes the
## name of the table, a field name in the table, and the value to be
## stored in the table.  The 'hash_get' function retrieves a value from
## the table given the table and field name.  
##
## <pre>
## To store a value into a field of a table, use hash_put:
##
##    hash_put "myTable" "aField" "theValue"
##
## The value stored in the table can be retrieved with hash_get:
##
##    hash_get "myTable" "aField"
##
## In this example, the hash_get function would echo "theValue".
## </pre>
## <br>
## <p>IMPLEMENTATION NOTE</p>
## <br>
## Bash does not provide direct support for hash tables.  These 
## functions are implemented by first building a variable using the
## table name and field name, then using the eval function to store
## (retrieve) value into (from) the variable.
##
## The idea for the hash data structure in bash was inspired by a 
## short example by Phil Howard which shows the use of hashes in bash.
## Phil Howard's original example can be found here:
##
##    http://www.codebits.com/bit.cfm?BitID=92
##
## @Copyright Copyright 2002 by the Source Mage Team
##
##
#---------------------------------------------------------------------


#---------------------------------------------------------------------
## @param table name
## @param field name
## @param returning variable
## @Type Private
## Given a table and field name, bulds the name of
## the variable into which a value will be stored.  Also changes '+',
## '-', and '.' in the table name into text since bash doesn't like
## variable names with those characters.
##
#---------------------------------------------------------------------
function hash_build_variable_name() {
  local ___TABLE="$1"
  local ___FIELD="$2"

#  debug "libhash" "hash_build_variable_name() - TABLE=$___TABLE:FIELD=$___FIELD"

  ___TABLE=${___TABLE//\+/_P_}
  ___TABLE=${___TABLE//\-/_M_}
  ___TABLE=${___TABLE//\./_D_}
  ___TABLE=${___TABLE//\:/_CLN_}
  ___TABLE=${___TABLE// /_SPC_}
  ___TABLE=${___TABLE//[/_OSB_}
  ___TABLE=${___TABLE//]/_CSB_}  
  
  if [[ $___FIELD ]] ; then
    ___FIELD=${___FIELD//\+/_P_}
    ___FIELD=${___FIELD//\-/_M_}
    ___FIELD=${___FIELD//\./_D_}
    ___FIELD=${___FIELD//\:/_CLN_}
    ___FIELD=${___FIELD// /_SPC_}
    ___FIELD=${___FIELD//]/_CSB_}
    ___FIELD=${___FIELD//]/_OSB_}
  fi

  # If this format is changed, modify hash_get_table_fields to suite
  if [[ $___FIELD ]] ; then ___FIELD="HASH_${___TABLE}_${___FIELD}_"
  else ___FIELD="HASH_${___TABLE}_" ; fi

  eval $3=\"$___FIELD\"
}


#---------------------------------------------------------------------
## @param field name
## @param table name
## @param returning variable
## @Type Private
## most likely reverses hash_build_field_name
##
#---------------------------------------------------------------------
function hash_unbuild_field_name() {
  local ___TABLE="$2"
  local ___FIELD=${1#$___TABLE}
  ___FIELD=${___FIELD%_*}
#  `echo "$1" | sed -n "s/^$2\(.*\)_$/\1/p"`
  
#  debug "libhash" "hash_unbuild_field_name() - TABLE=$___TABLE:FIELD=$___FIELD"

  ___FIELD=${___FIELD//_P_/\+}
  ___FIELD=${___FIELD//_M_/\-}
  ___FIELD=${___FIELD//_D_/\.}
  ___FIELD=${___FIELD//_CLN_/\:}
  ___FIELD=${___FIELD//_SPC_/ }
  ___FIELD=${___FIELD//_CSB_/]}
  ___FIELD=${___FIELD//_OSB_/[}

  eval $3=\"$___FIELD\"
}


#---------------------------------------------------------------------
## @param table name
## @param field name
## @param value
## 
## Saves the value in the specified table/field.
##
#---------------------------------------------------------------------
function hash_put() {
  local VARIABLE_NAME
  hash_build_variable_name "$1" "$2" VARIABLE_NAME
  eval "${VARIABLE_NAME}=\"${3}\""
  debug "libhash" "hash_put() - VARIABLE_NAME=$VARIABLE_NAME, data=$3"
}


#---------------------------------------------------------------------
## @param table name
## @param field name
## 
## @Stdout Value stored in table/field
## Echos the value stored in the table/field.  If no value was 
## previously stored in the table/field, this function echos an empty 
## string.
##
#---------------------------------------------------------------------
function hash_get() {
  local VARIABLE_NAME
  hash_build_variable_name "$1" "$2" VARIABLE_NAME
  echo "${!VARIABLE_NAME}"
}

#---------------------------------------------------------------------
## @param table name
## @param field name
## @param value
## 
## Appends the value to the specified table/field.
##
#---------------------------------------------------------------------
function hash_append() {
  local VARIABLE_NAME
  local old_value
  local sep=${4:-" "}
  hash_build_variable_name "$1" "$2" VARIABLE_NAME
  old_value=${!VARIABLE_NAME}
  if [[ -n $old_value ]] ; then
    eval "${VARIABLE_NAME}=\"$old_value${sep}${3}\""
  else 
    eval "${VARIABLE_NAME}=\"$3\""
  fi
}

#---------------------------------------------------------------------
## @param table name
## 
## 'export' all the values in the table. This is useful for getting
## hash table data from cast's pass_one/two into pass_three/pass_four
## which are run through make. Essentially exporting lets us pass
## the variables through make.
##
#---------------------------------------------------------------------
function hash_export() {
  local VARIABLE_NAME
  hash_build_variable_name $1 "" VARIABLE_NAME
  # make sure the hash has something in it before trying to export it
  [[ $(eval echo '${!'$VARIABLE_NAME'*}') ]] &&
  eval 'export ${!'$VARIABLE_NAME'*}'
}

#---------------------------------------------------------------------
## @param table name
## @param field name
## 
## Unsets field. Deletes value.
##
#---------------------------------------------------------------------
function hash_unset() {
  local VARIABLE_NAME
  hash_build_variable_name "$1" "$2" VARIABLE_NAME
  eval unset ${VARIABLE_NAME}
}


#---------------------------------------------------------------------
## @param table name
## 
## Unsets all fields in a table.
##
#---------------------------------------------------------------------
function hash_reset()  {
  local TABLE_NAME
  hash_build_variable_name "$1" '' TABLE_NAME
  local VARIABLES=`eval 'echo ${!'${TABLE_NAME}'*}'`
  unset $VARIABLES   

}

#---------------------------------------------------------------------
## @param table name
## @param opt delimiter
## @Stdout table data
## Outputs the entire table data, with fields separated by the  
## optional delimiter. If no delimiter is give, \n will be used.
##
#---------------------------------------------------------------------
function hash_get_table()  {

  local TABLE_NAME
  hash_build_variable_name "$1" '' TABLE_NAME
  local VARIABLES i
  local separator="$2"
  separator=${separator:-$'\n'}
  VARIABLES=`eval 'echo ${!'${TABLE_NAME}'*}'`
  
  for i in $VARIABLES; do
  	echo -n "${!i}${separator}"
  done
  
}


#---------------------------------------------------------------------
## @param table name
## @param opt delimiter
## @Stdout Fields in table
## Outputs all of the fields in the table , with fields separated    
## by the optional delimiter. If no delimiter is give, \n wil be 
## used.
##
#---------------------------------------------------------------------
function hash_get_table_fields()  {

  local TABLE_NAME
  hash_build_variable_name "$1" '' TABLE_NAME
  local VARIABLES i
  local separator="$2"
  separator=${separator:-$'\n'}
  VARIABLES=`eval 'echo ${!'${TABLE_NAME}'*}'`
  
  local FIELD
  for i in $VARIABLES ; do
    hash_unbuild_field_name "$i" "$TABLE_NAME" FIELD
    echo -n "${FIELD}${separator}"
  done
  
}

#---------------------------------------------------------------------
## @param table name
## @Stdout Print the table in some reasonably readable form
## As the name would imply, this is mainly for development use
## and is not intended for regular use.
##
#---------------------------------------------------------------------
function hash_debug_dump() {
  local TABLE_NAME
  local FIELD
  for FIELD in $(hash_get_table_fields $1); do
    echo "${FIELD} : $(hash_get $1 ${FIELD})"
  done
}


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