# Common
#
# Douglas Thrift
#
# $Id$

import base64
from ConfigParser import SafeConfigParser
import optparse
import os.path
import sys

FORBIDDEN = ('common', 'creditcard', 'google', 'wesabe')

class Bank(object):
	def download(self, account):
		raise NotImplementedError

	def due(self, account):
		raise NotImplementedError

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('-b', '--bank', action = 'callback', callback = self.__bank, dest = 'banks', type = 'string')
		self.add_option('-a', '--account', action = 'callback', callback = self.__account, dest = 'banks', type = 'string')
		self.add_option('-l', '--list', action = 'store_true', dest = 'list')
		self.add_option('-D', '--debug', action = 'store_true', dest = 'debug')
	
	def __bank(self, option, opt_str, value, parser):
		if value in FORBIDDEN:
			raise optparse.OptionValueError, '%s must not be %s' % (opt_str, value)

		self.bank = value

		parser.values.ensure_value(option.dest, {}).setdefault(value, [])

	def __account(self, option, opt_str, value, parser):
		try:
			getattr(parser.values, option.dest)[self.bank].append(value)
		except NameError:
			raise optparse.OptionValueError, '%s must be after -b/--bank' % opt_str

def config(parser, options, file):
	if not options.all and not options.banks and not options.list:
		parser.error('-A, -b, or -l not specified')

	config = SafeConfigParser()

	config.read([os.path.expanduser('~/%s' % file)])

	banks = dict(map(lambda bank: (bank, config.get(bank, 'accounts').split(',')), (options.banks.iterkeys() if options.banks else filter(lambda section: section not in FORBIDDEN, config.sections()))))

	if options.banks:
		for bank in banks.iterkeys():
			accounts = frozenset(options.banks[bank])

			if accounts:
				all_accounts = frozenset(banks[bank])

				if accounts <= all_accounts:
					banks[bank] = accounts
				else:
					parser.error('not account(s): %s' % ', '.join(accounts - all_accounts))

	if options.list:
		for bank, accounts in banks.iteritems():
			print bank

			for account in accounts:
				print '   ' + account

		sys.exit(0)

	return config, banks

def decode(string):
	return base64.b64decode(string.decode('rot13'))

def bank(bank, options, config):
	exec 'import %s' % bank
	exec "bank = %s.Bank(config.get(bank, 'username'), decode(config.get(bank, 'password')), options.debug)" % bank

	return bank
