# -*- shell-script -*-

################################################################################

§class "config" --properties "type" "names"

################################################################################

function §config.add_name () {
    local name="$1"
    if [[ -z "$(§config.get_names)" ]]; then
	§config.set_names "$name"
    else
	§config.set_names "$(§config.get_names) $name"
    fi

    # assure "user" config is always at the end
    local names="$(§config.get_names)"
    if [[ " $names " =~ \ user\  ]]; then
	if [[ ! "$names" =~ user$ ]]; then
	    names=${names/ user / }
	    names="$names user"
	    §config.set_names "$names"
	fi
    fi
}

function §configs.list () {

    §configs.seek_start
    while §configs.next?; do
	printf '%s\n' "$(§config.get_type) ($(§config.get_names))"
	§configs.next
    done
}

function §config.get_dumpname { # $wanted

    local wanted="$1"
    local dump="$(§config.get_type)"
    local name=""
    
    for name in $(§config.get_names); do	
	dump="$dump-$name"
	[[ "$name" == "$wanted" ]] && break
    done
    printf '%s' "$dump.dump"
}

function §config.get_final_dumpname {
    §config.get_dumpname "user"
}

function §config.get_rcname { # $wanted

    local wanted="$1"
    local dump="$(§config.get_type)"
    local name=""
    
    for name in $(§config.get_names); do	
	dump="$dump-$name"
	[[ "$name" == "$wanted" ]] && break
    done

    printf '%s' "$dump.rc"
}

function §config.changed? { # $name

    local name="$1"
    local state="$2"
    local rcfile="$bashrun_cache_home/$(§config.get_rcname "$name")"
    local function="$(§config.get_funcname "$name")"

    if [[ "$state" == "reconfiguring" ]]; then
	return 0

    elif [[ ! -f $rcfile ]]; then
	return 0    

    elif [[ "$(<$rcfile)" != "$(§function.code "$function")" ]]; then
	return 0
    fi
    return 1
}

function §config.get_funcname { # $wanted
    local name="$1"
    if [[ "$name" == "user" ]]; then
	printf '%s' "+configure-$(§config.get_type)"
    else
	printf '%s' "+configure-$name-$(§config.get_type)"
    fi
}

function §configs.restore {

    §separator "Creating/Restoring configuration"

    source $bashrun_site/core
    source $bashrun_rcfile

    §configs.restore_core
    §configs.collect_user_configs

    §configs.seek_start
    while §configs.next?; do
	§config.restore
	§configs.next
    done
}

function §config.restore {

    local type="$(§config.get_type)"
    local restore="$(§config.get_dumpname core)"
    local state="restoring"
    local name=""

    §progress.update +7 "$bashrun_status [$type]"

    for name in $(§config.get_names); do
	[[ "$name" == "core" ]] && continue

	if §config.changed? "$name" "$state"; then

	    §debug -y "$(§config.get_funcname "$name")" "->" -c "reconfigure..."

	    # restore the previous dump unless reconfiguring	    
	    if [[ "$state" == "restoring" ]]; then
		§debug "restore" -v "$restore"
		. "$bashrun_cache_home/$restore"
	    fi

	    state="reconfiguring" # we're reconfiguring from now on...

	    # run the config function for this part
	    §debug "calling" -v "$(§config.get_funcname "$name")"

	    $(§config.get_funcname "$name")

	    # dump the results in the corresponding dumpfile
	    §debug "dumping" -v "$(§config.get_dumpname "$name")"

	    §$type.dump "$(§config.get_dumpname "$name")"

	    # cache the config function in the corresponding rcfile
	    §debug "caching" -v "$(§config.get_rcname "$name")"

	    §function.code "$(§config.get_funcname "$name")" > \
		$bashrun_cache_home/$(§config.get_rcname "$name")
	
	else
	    §debug -y "$(§config.get_funcname "$name")" "->" -c "cached..."
	fi
	restore="$(§config.get_dumpname "$name")"
    done
    
    if [[ "$state" == "restoring" ]]; then
	§debug -c "restore" -v "$(§config.get_final_dumpname)"
	. "$bashrun_cache_home/$(§config.get_final_dumpname)"
    fi	    
}

function §configs.restore_core {

    local keys="$(§readline.get_setting 'editing-mode')-mode" &>/dev/null
    local types="${1:-actions|modes|terminals|rules|handlers|$keys|bookmarks}"
    local functions="$(declare -f | grep '^+configure-')"

    local line function name type dumpfile

    §progress.update +5 "$bashrun_status [core]"

    for function in $functions; do
	if [[ "$function" =~ ^\+configure-core-(.+) ]]; then

	    type="${BASH_REMATCH[1]}"
	    dumpfile="$type-core.dump"	    

	    if [[ ! -f $bashrun_cache_home/$dumpfile ]]; then
		§debug -y "core" -c "$type" "->" -v "$dumpfile"
		$function
		§$type.dump $dumpfile
	    fi

	    if ! §configs.seek "$type"; then
		§config.new "$type"
	    fi
	    §configs.seek "$type"
	    §config.add_name "core"
	fi
    done
}

function §configs.collect_user_configs {

    local keys="$(§readline.get_setting 'editing-mode')-mode" &>/dev/null
    local types="${1:-actions|modes|terminals|rules|handlers|$keys|bookmarks}"
    local functions="$(declare -f | grep '^+configure-')"

    local line function name type

    # then we'll process the user config functions
    
    for function in $functions; do

	# parse the function name to determine the identifier, the
	# name and the type
	
	[[ "$function" =~ ^(\+configure-([^-]+)?-?($types)) ]] || continue

	function="${BASH_REMATCH[1]}"
	type="${BASH_REMATCH[3]}"
	name="${BASH_REMATCH[2]:-user}"

	[[ "$name" == "core" ]] && continue

	if ! §configs.seek "$type"; then
	    §config.new "$type"
	fi
	§configs.seek "$type"
	§config.add_name "$name"
    done   
}

