#!/bin/bash
	
export D_MASTER D_FILE D_HASH D_CACHE

# DICTIONARY
dbg "defining dictionary"

# d_reload_from_file - will just load the file into the map. It's called during d_start and probably after running another contate
function d_reload_from_file {
	dbg "d_reload_from_file() (${D_FILE})"
	dbg "file:$(cat ${D_FILE})"
	dbg "D_CACHE: $D_CACHE"
	dbg "D_HASH: $D_HASH"
	unset TEMP_HASH
	while IFS= read -r line; do
		if [ -z "$TEMP_HASH" ]; then
			dbg "TEMP_HASH EMPTY SO $line"
			TEMP_HASH="$line"
			if [ "$TEMP_HASH" = "$D_HASH" ]; then
				dbg "CACHE HIT"
				return
			fi
			unset D_CACHE
			export D_CACHE
			D_HASH="${TEMP_HASH}"
		else
			dbg "Line: $line;"
			D_CACHE+="${line} "
		fi
	done < "${D_FILE}"
	D_CACHE="${D_CACHE% }"
	dbg "D_CACHE: ${D_CACHE}"
}

# d_rewrite_to_file - will write the map to the file, should be called anytime we modify the cache
function d_rewrite_to_file {
	dbg "d_rewrite_to_file()"
	echo -n "" > "${D_FILE}"
	for key in $D_CACHE; do
		echo "$key" >> "${D_FILE}"
	done
	dbg "Wrote file:$(cat ${D_FILE})"
	D_HASH="$(md5sum "${D_FILE}")"
	sed -i "1i$D_HASH" ${D_FILE}
	dbg "Wrote file:$(cat ${D_FILE})"
	if [ -z "$(cat ${D_FILE})" ]; then
		echo "$D_HASH" > "${D_FILE}"
	fi
}

# d_start - should be called at the beginning of any contate script
function d_start {
	dbg "d_start()"
	if [[ -z "${D_MASTER}" ]]; then
		D_HASH=""
		D_MASTER=$$
		D_FILE="$(mktemp)"
		d_rewrite_to_file
	elif [[ ! -f ${D_FILE} ]]; then
		err "D_FILE should not be null if D_MASTER is non-zero"
		return 1
	fi
	dbg "D_MASTER: ${D_MASTER}"
	dbg "D_FILE: ${D_FILE}"
	d_reload_from_file
	dbg "D_CACHE: ${D_CACHE}"
}

# d_clean - should be set to trap EXIT/FINISH
function d_clean {
	dbg "d_clean()"
	if [[ "$$" = "${D_MASTER}" && -f "${D_FILE}" ]]; then
		rm "${D_FILE}"
	fi
	unset D_MASTER
	unset D_FILE
	unset D_CACHE
	unset D_HASH
}


# d_get KEY - gets key or ""
function d_get {
	dbg "d_get($1)"
	d_reload_from_file
	unset D_CACHE_MAP
	declare -A D_CACHE_MAP
	unset TEMPKEY
	dbg "D_CACHE: ${D_CACHE}"
	for thing in $D_CACHE; do
		if [ -z "${TEMPKEY}" ]; then
			TEMPKEY="$thing"
			dbg "Get, Key: $thing"
		else
			D_CACHE_MAP[$TEMPKEY]="$thing"
			dbg "Get, Val: $thing"
			unset TEMPKEY
		fi
	done
	# write map
	dbg "Keys:${!D_CACHE_MAP[*]}"
	dbg "Vals:${D_CACHE_MAP[*]}"
	dbg "Got: $(base64 -d <<< "${D_CACHE_MAP["$(base64 <<< "$1")"]}")"
	echo -n  "$(base64 -d <<< "${D_CACHE_MAP["$(base64 <<< "$1")"]}")"
}

# d_set KEY VALUE - sets KEY to VALUE
function d_set {
	dbg "d_set($1, $2)"
	d_reload_from_file
	# TODO: keys cannot contain spaces
	unset D_CACHE_MAP
	declare -A D_CACHE_MAP
	unset TEMPKEY
	dbg "D_CACHE: ${D_CACHE}"
	for thing in $D_CACHE; do
		if [ -z "${TEMPKEY}" ]; then
			TEMPKEY="$thing"
		else
			D_CACHE_MAP[$TEMPKEY]="$thing"
			unset TEMPKEY
		fi
	done
	dbg "Keys:${!D_CACHE_MAP[*]}"
	dbg "Vals:${D_CACHE_MAP[*]}"
	D_CACHE_MAP["$(base64 <<< "$1")"]="$(base64 <<< "$2")"
	dbg "Keys:${!D_CACHE_MAP[*]}"
	dbg "Vals:${D_CACHE_MAP[*]}"
	unset D_CACHE
	export D_CACHE 
	for key in "${!D_CACHE_MAP[@]}"; do
		D_CACHE+="${key} ${D_CACHE_MAP["$key"]} "
	done
	D_CACHE="${D_CACHE% }"
	dbg "D_CACHE: ${D_CACHE}"
	d_rewrite_to_file
}

# d_exists KEY - returns whether or not key exists
function d_exists {
	dbg "d_exists($1)"
	d_reload_from_file
	unset D_CACHE_MAP
	declare -A D_CACHE_MAP
	unset TEMPKEY
	dbg "D_CACHE: ${D_CACHE}"
	for thing in $D_CACHE; do
		if [ -z "${TEMPKEY}" ]; then
			TEMPKEY="$thing"
		else
			D_CACHE_MAP[$TEMPKEY]="$thing"
			unset TEMPKEY
		fi
	done
	dbg "Keys:${!D_CACHE_MAP[*]}"
	dbg "Vals:${D_CACHE_MAP[*]}"
	return $([ ${D_CACHE_MAP["$(base64 <<< "$1")"]+_} ])
}

# d_del KEY - deletes the keyu
function d_del {
	dbg "d_del($1)"
	d_reload_from_file
	# TODO: keys cannot contain spaces
	unset D_CACHE_MAP
	declare -A D_CACHE_MAP
	unset TEMPKEY
	dbg "D_CACHE: ${D_CACHE}"
	for thing in $D_CACHE; do
		if [ -z "${TEMPKEY}" ]; then
			TEMPKEY="$thing"
		else
			D_CACHE_MAP[$TEMPKEY]="$thing"
			unset TEMPKEY
		fi
	done
	dbg "Keys:${!D_CACHE_MAP[*]}"
	dbg "Vals:${D_CACHE_MAP[*]}"
	unset D_CACHE_MAP["$(base64 <<< "$1")"]
	unset D_CACHE
	export D_CACHE #TODO is this everywhere
	for key in "${!D_CACHE_MAP[@]}"; do
		D_CACHE+="${key} ${D_CACHE_MAP["$key"]} "
	done
	D_CACHE="${D_CACHE% }"
	d_rewrite_to_file
}


export -f d_start d_clean d_get d_set d_del d_reload_from_file d_rewrite_to_file
