#!/usr/bin/perl

use strict;
use warnings;
use IO::Handle;
use POSIX;
use utf8;

# Initialized my hash referecence.
my $conf={
	file	=>	{
		config		=>	"/path/to/some/file.conf",
	},
}


# This parses through the config file, feeding values into the 'conf' hash as
# they are read.
sub read_conf
{
	my ($conf)=@_;
	# Logging is not enabled here because this is always called before our logging
	# is enabled. We need the config info to know where our log file is... :)
	
	my $read_conf=IO::Handle->new();
	my $shell_call="<$conf->{file}{config}";
	# Calling 'error' this early causes a loop.
	open ($read_conf, $shell_call) or die "$THIS_FILE; ".__LINE__.": executing: [$shell_call] failed with error: $!\n";
	binmode $read_conf, ":utf8:";
	while (<$read_conf>)
	{
		chomp;
		my $line=$_;
		$line=~s/#!/_!|/;			# Protect my left-side substitute keys
		$line=~s/!#/|!_/;			# Protect my right-side substitute keys
		$line=~s/#(.*)//;			# Chop off '#' and anything after it
		$line=~s/_!\|/#!/;			# Restore my left-side substitute keys
		$line=~s/\|!_/!#/;			# Restore my right-side substitute keys
		next if ( $line !~ /=/ );		# Skip lines without an '=' (this skips blank lines and such).
		my ($var, $val)=split/=/, $line, 2;	# Split on the first '='.
		$var=~s/^\s+//; $var=~s/\s+$//;		# Split leading and trailing spaces off of 'var'
		$val=~s/^\s+//; $val=~s/\s+$//;		# Split leading and trailing spaces off of 'val'
		
		# Parse the variable into the 'conf' hash and store the data.
		&make_hash_reference($conf, $var, $val);
	}
	$read_conf->close();
	
	### Invoke some values.
	# Choose the database driver.
	if ( $conf->{db}{type} eq "postgresql" )
	{
		$conf->{db}{driver}="DBI:Pg";
	}
	elsif ( $conf->{db}{type} eq "mysql" )
	{
		$conf->{db}{driver}="DBI:mysql";
	}
	elsif ( $conf->{db}{type} eq "sqlite" )
	{
		$conf->{db}{driver}="DBI:Pg";
	}
	else
	{
		# Error, unknown DB type.
	}
	
	return(1);
}

# This is only called by the 'make_hash_reference' functions and is used to
# either push the value into the final hash key or, if there are more hash
# keys to parse, to re-enter itself until it reaches the end.
sub add_hash_reference
{
	my ($href1, $href2)=@_;
	
	for my $key (keys %$href2)
	{
		if (ref $href1->{$key} eq 'HASH')
		{
			# Go in another level.
			&add_hash_reference($href1->{$key}, $href2->{$key});
		}
		else
		{
			# There's the end value, store it.
			$href1->{$key} = $href2->{$key};
		}
	}
}

# This is called when I need to parse a double-colon seperated string into two
# or more elements which represent keys in the 'conf' hash. Once suitably split
# up, the 'value' is stored. For example, passing ('conf', 'foo::bar', 'baz')
# will make 'baz the value stored in '$conf->{foo}{bar}'.
# 
# This was contributed by Shaun Fryer and Viktor Pavlenko by way of the 
# 'Toronto Perl Mongers' (TPM) Mailing list. Thanks!
sub make_hash_reference
{
	# 'href' is the hash reference I am working on.
	my ($href, $key_string, $value)=@_;
	
	my @keys=split /::/, $key_string;
	my $last_key=pop @keys;
	my $_href={};
	$_href->{$last_key}=$value;
	while (my $key=pop @keys)
	{
		my $elem={};
		$elem->{$key}=$_href;
		$_href=$elem;
	}
	&add_hash_reference($href, $_href);
}

