#!/usr/local/bin/python
# Reminder
#
# Douglas Thrift
#
# $Id$

from ConfigParser import NoOptionError, SafeConfigParser
import getpass
import keyring
import optparse
import os
import sys
import warnings

with warnings.catch_warnings():
	warnings.filterwarnings('ignore', r'the sha module is deprecated', DeprecationWarning)

	import gdata.calendar.service

MODULES = frozenset(('creditcards', 'facebook', 'wesabe'))
NOT_BANKS = MODULES | frozenset(('google',))

class Bank(object):
	def __init__(self, module, config, debug):
		self.module = module
		self.bank = None
		self.config = config
		self.debug = debug

	def __call__(self):
		if self.bank is None:
			exec 'import %s' % self.module
			exec "self.bank = %s.Bank(Config(self.config, self.module), self.debug)" % self.module

		return self.bank

class Banks(object):
	def __init__(self, config, debug):
		self.banks = {}
		self.config = config
		self.debug = debug

	def bank(self, module):
		if module not in NOT_BANKS:
			return self.banks.setdefault(module, Bank(module, self.config, self.debug))()

class Config(object):
	def __init__(self, config, module):
		self.config = config
		self.module = module

	def get(self, *args, **kwargs):
		return self.config.get(self.module, *args, **kwargs)

	def getboolean(self, *args, **kwargs):
		return self.config.getboolean(self.module, *args, **kwargs)

	def getfloat(self, *args, **kwargs):
		return self.config.getfloat(self.module, *args, **kwargs)

	def getint(self, *args, **kwargs):
		return self.config.getint(self.module, *args, **kwargs)

	def getlist(self, *args, **kwargs):
		return self.config.getlist(self.module, *args, **kwargs)

	def getpassword(self):
		return self.config.getpassword(self.module)

	def getusername(self):
		return self.config.getusername(self.module)

class ConfigParser(SafeConfigParser):
	def __init__(self, *args, **kwargs):
		SafeConfigParser.__init__(self, *args, **kwargs)

	def getlist(self, *args, **kwargs):
		return self.get(*args, **kwargs).split(',')

	def getpassword(self, section):
		return keyring.get_password('reminder_%s' % section, self.getusername(section))

	def getusername(self, section):
		return self.get(section, 'username')

class OptionParser(optparse.OptionParser):
	def __init__(self, *args, **kwargs):
		optparse.OptionParser.__init__(self, *args, **kwargs)
		self.add_option('-A', '--all', action = 'store_true', dest = 'all')
		self.add_option('-d', '--dbus', action = 'store_true', dest = 'dbus')
		self.add_option('-m', '--module', action = 'callback', callback = self.__module, dest = 'modules', type = 'string')
		self.add_option('-p', '--password', action = 'callback', callback = self.__password, dest = 'passwords', type = 'string')
		self.add_option('-D', '--debug', action = 'store_true', dest = 'debug')

	def __module(self, option, opt_str, value, parser):
		if value not in MODULES:
			raise optparse.OptionValueError, '%s unknown module %s' % (opt_str, value)

		parser.values.ensure_value(option.dest, []).append(value)

	def __password(self, option, opt_str, value, parser):
		parser.values.ensure_value(option.dest, []).append(value)

if __name__ == '__main__':
	parser = OptionParser()
	options = parser.parse_args()[0]
	config = ConfigParser()

	config.read([os.path.expanduser('~/.reminder')])

	if options.passwords:
		for section in options.passwords:
			try:
				username = config.getusername(section)
				password = getpass.getpass('%s password for %s: ' % (section, username))

				keyring.set_password('reminder_%s' % section, username, password)
			except NoOptionError:
				pass

		sys.exit(0)

	if options.dbus:
		dbus = os.environ['DBUS_SESSION_BUS_ADDRESS']

		with open(os.path.expanduser('~/.reminder.dbus'), 'wb') as file:
			file.write(dbus + '\n')

		sys.exit(0)

	try:
		os.environ['DBUS_SESSION_BUS_ADDRESS']
	except KeyError:
		with open(os.path.expanduser('~/.reminder.dbus'), 'rb') as file:
			os.environ['DBUS_SESSION_BUS_ADDRESS'] = file.readline().rstrip()

	if not options.all and not options.modules:
		parser.error('-A or -m not specified')

	calendar = gdata.calendar.service.CalendarService()
	calendar.email = config.getusername('google')
	calendar.password = config.getpassword('google')
	calendar.source = 'Reminder-0.9'

	calendar.ProgrammaticLogin()

	banks = Banks(config, options.debug)

	for module in options.modules if not options.all else sorted(MODULES):
		exec 'import %s' % module
		exec '%s.main(%s)' % (module, ', '.join(['calendar', 'Config(config, module)'] + (['banks', 'options.debug'] if module in ('creditcards', 'wesabe') else ['options.debug'])))
