from collections import namedtuple
from ConfigParser import NoOptionError

Auth = namedtuple('Auth', ('username', 'password'))
HttpConnectionSettings = namedtuple('HttpConnectionSettings', ('url', 'auth'))

class ConfigSection(object):
	"""Dictionary-like interface to configuration section.

	Also allows to refer part of keys starting with given prefix.
	"""
	def __init__(self, config, section_name, prefix=''):
		self.config = config
		self.section_name = section_name
		self.prefix = prefix

	def __getitem__(self, name):
		return self.config.get(self.section_name, self.prefix+name)

	def get(self, name, default=None):
		return self.get_or_exec(name, lambda: default)

	def get_or_exec(self, name, get_default):
		try:
			return self.config.get(self.section_name, self.prefix+str(name))
		except NoOptionError:
			return get_default()

	def keys(self):
		return [key for key in self.config.options(self.section_name) if key.startswith(self.prefix)]

	def items(self):
		return [(k, v) for (k, v) in self.config.items(self.section_name) if k.startswith(self.prefix)]

	def __contains__(self, name):
		return self.config.has_option(self.section_name, self.prefix+name)

	def prefixed(self, prefix):
		return ConfigSection(self.config, self.section_name, self.prefix+prefix)

	def with_defaults(self, defaults):
		return ConfigSectionWithDefaults(self, defaults)

class ConfigSectionWithDefaults(object):
	"""Configuration section with default values.
	"""
	def __init__(self, section, defaults):
		self.section = section
		self.defaults = defaults

	def __getitem__(self, name):
		return self.section.get_or_exec(name, lambda: self.defaults[name])

	def get(self, name, default=None):
		return self.get_or_exec(name, lambda: default)

	def get_or_exec(self, name, get_default):
		try:
			return self.section.get_or_exec(name, lambda: self.defaults[name])
		except ValueError:
			return get_default()

	def keys(self):
		return set(self.section.keys()) + set(self.defaults.keys())

	def __contains__(self, name):
		return name in self.section or name in self.defaults

	def with_defaults(self, defaults):
		return ConfigSectionWithDefaults(self, defaults)

def config_get(config, section, option, default):
	if option in config.options(section):
		return config.get(section, option)
	else:
		return default

def read_auth(section):
	return Auth(section.get('username'), section.get('password'))

def read_url(section):
	import urlparse
	
	if 'url' in section:
		url = section['url']
		
	else:
		host = section['host']
		protocol = section['protocol']
		port = int(section['port'])
		path = section['path']
		
		url = urlparse.urlunparse((protocol, '%s:%d' % (host, port), path, '', '', ''))
		
	return url

def read_http_connection_settings(section):
	return HttpConnectionSettings(url = read_url(section), auth = read_auth(section))

