#!/bin/bash

key_expr="[a-zA-Z][_a-zA-Z0-9]*\.[a-zA-Z][_a-zA-Z0-9]*"

get_conf() {
  local BASEDIR=$1
  local name=$2
  local instance=$3
  local key=$4
  local default=$5
  local file=$BASEDIR/$name/$instance/current/etc/app.conf

  if [ ! -r $file ]
  then
    echo "$default"
    return 0
  fi

  value=`sed -n "s,^${key}[ ]*=[ ]*\(.*\)$,\1,p" $file`

  if [ -z "$value" ]
  then
    echo "$default"
  fi

  echo "$value"
}

get_conf_all() {
  local BASEDIR=$1
  local name=$2
  local instance=$3
  local file=$BASEDIR/$name/$instance/current/etc/app.conf

  if [ ! -r $file ]
  then
    return 0
  fi

  sed -n "s,^[ ]*\($key_expr\)[ ]*=[ ]*\(.*\)$,\1=\2,p" $file | sort
}

get_conf_in_group() {
  local BASEDIR=$1
  local name=$2
  local instance=$3
  local group=$4

  get_conf_all "$BASEDIR" "$name" "$instance" | \
    sed -n "s,^[ ]*${group}\.\([._a-zA-Z]*\)=\(.*\)$,\1=\2,p"
}

assert_key() {
  key=$1

  local x=`echo $key | sed -n "/^$key_expr$/p"`
  if [ -z "$x" ]
  then
    echo "Invalid key: $key" >&2
    exit 1
  fi
}

conf_set() {
  local BASEDIR=$1
  local name=$2
  local instance=$3
  local key=$4
  local value=$5

  local file=$BASEDIR/$name/$instance/current/etc/app.conf

  assert_key "$key"

  if [ -r $file ]
  then
    sed "/^$key[ ]*=.*/d" $file > $file.tmp
  fi

  echo "$key=$value" >> $file.tmp
  mv $file.tmp $file
}

conf_delete() {
  local BASEDIR=$1
  local name=$2
  local instance=$3
  local key=$4

  local file=$BASEDIR/$name/$instance/current/etc/app.conf

  assert_key "$key"

  sed "/^$key[ ]*=.*/d" $file > $file.tmp
  mv $file.tmp $file
}

method_conf_usage() {
  if [ -n "$1" ]
  then
    echo "Error:" $@ >&2
  fi

  echo "usage: $0 conf <method>" >&2
  echo ""
  echo "Available methods:" >&2
  echo "  get                     - list all configuration parameters" >&2
  echo "  set [group.key] [value] - set a configuration parameter" >&2
  echo "  delete [group.key]      - deletes a configuration parameter" >&2
  exit 1
}

method_conf() {
  local name="$1"; shift
  local instance="$1"; shift
  local mode="list"

  while getopts "s:d:" opt
  do
    case $opt in
      d)
        mode="delete"
        key="$OPTARG"
        ;;
      s)
        mode="set"
        key="$OPTARG"
        # Remove all options so far
        shift $((OPTIND-1))
        value="$1"
        ;;
      \?)
        method_conf_usage "Invalid option: -$OPTARG" 
        ;;
    esac
  done

  assert_is_instance conf_usage "$name" "$instance"

  case $mode in
    list)
      get_conf_all "$BASEDIR" "$name" "$instance" | (IFS==; while read key value
      do
        printf "%-20s %-20s" "$key" "$value"
        echo
      done)
      ;;
    set)
      conf_set "$BASEDIR" "$name" "$instance" "$key" "$value"
      ;;
    delete)
      conf_delete "$BASEDIR" "$name" "$instance" "$key"
      ;;
  esac
}