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

import base64
from ConfigParser import SafeConfigParser
import optparse
import os.path
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, *args, **kwargs):
		return self.config.getpassword(self.module, *args, **kwargs)

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, *args, **kwargs):
		return base64.b64decode(self.get(*args, **kwargs).decode('rot13'))

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('-m', '--module', action = 'callback', callback = self.__module, dest = 'modules', 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)

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

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

	config = ConfigParser()

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

	calendar = gdata.calendar.service.CalendarService()
	calendar.email = config.get('google', 'username')
	calendar.password = config.getpassword('google', 'password')
	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'])))
