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

from ConfigParser import NoOptionError, SafeConfigParser
import gdata.calendar.service
import getpass
import imaplib
import keyring
import optparse
import os
import sys

MODULES = frozenset(('creditcards', 'facebook'))

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.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 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 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()

	if options.debug:
		imaplib.Debug = 4

	imap = imaplib.IMAP4_SSL(config.get('imap', 'server'))

	imap.login(config.getusername('imap'), config.getpassword('imap'))

	for module in options.modules if not options.all else sorted(MODULES):
		exec 'import %s' % module
		exec '%s.main(calendar, imap, Config(config, module), options.debug)' % module

	imap.logout()
