# DT Wesabe
#
# Douglas Thrift
#
# $Id$

from datetime import datetime
import decimal
from M2Crypto import m2urllib2, SSL
import urllib2
from xml.etree import ElementTree

EPOCH = datetime.utcfromtimestamp(0)
ISO_8601 = '%Y-%m-%dT%H:%M:%SZ'

class Account(object):
	def __init__(self, account):
		self.id = int(account.find('id').text)
		self.guid = account.find('guid').text
		account_number = account.find('account-number')
		self.account_number = int(account_number.text) if account_number is not None else None
		self.name = account.find('name').text
		financial_institution = account.find('financial-institution')
		self.financial_institution = FinancialInstitution(financial_institution) if financial_institution is not None else None
		self.account_type = account.find('account-type').text
		self.currency = Currency(account.find('currency'))
		current_balance = account.find('current-balance')

		assert current_balance.get('type') == 'float'

		self.current_balance = decimal.Decimal(current_balance.text)
		last_uploaded_at = account.find('last-uploaded-at')

		if last_uploaded_at is not None:
			assert last_uploaded_at.get('type') == 'datetime'

			self.last_uploaded_at = datetime.strptime(last_uploaded_at.text, ISO_8601)
		else:
			self.last_uploaded_at = EPOCH

		self.txaction_count = int(account.find('txaction-count').text)
		oldest_txaction = account.find('oldest-txaction')

		if oldest_txaction is not None:
			assert oldest_txaction.get('type') == 'datetime'

			self.oldest_txaction = datetime.strptime(oldest_txaction.text, ISO_8601)
		else:
			self.oldest_txaction = EPOCH

		newest_txaction = account.find('newest-txaction')

		if newest_txaction is not None:
			assert newest_txaction.get('type') == 'datetime'

			self.newest_txaction = datetime.strptime(newest_txaction.text, ISO_8601)
		else:
			self.newest_txaction = EPOCH

class Currency(object):
	def __init__(self, currency):
		self.symbol = currency.get('symbol')
		self.separator = currency.get('separator')
		self.delimiter = currency.get('delimiter')
		self.decimal_places = int(currency.get('decimal_places'))
		self.name = currency.text

class FinancialInstitution(object):
	def __init__(self, financial_institution):
		self.id = financial_institution.find('id').text
		self.name = financial_institution.find('name').text

class Wesabe(object):
	def __init__(self, email, password):
		context = SSL.Context()

		context.set_verify(SSL.verify_peer | SSL.verify_fail_if_no_peer_cert, depth = 9)
		context.load_verify_locations('/etc/ssl/cert.pem')

		handler = urllib2.HTTPBasicAuthHandler()

		handler.add_password('RESTRICTED', 'https://www.wesabe.com/', email, password)
		handler.add_password('Wesabe Upload API', 'https://api.wesabe.com/rest/upload/statement', email, password)

		self.opener = m2urllib2.build_opener(context, handler)
	
	def accounts(self):
		accounts = ElementTree.parse(self.opener.open('https://www.wesabe.com/accounts.xml')).getroot()

		return map(lambda account: Account(account), accounts.getchildren())

	def upload(self, account_number, account_type, wesabe_id, data, balance = None):
		upload = ElementTree.Element('upload')
		statement = ElementTree.SubElement(upload, 'statement')

		statement.set('acctid', str(account_number))
		statement.set('accttype', account_type)
		statement.set('wesabe_id', wesabe_id)

		if balance is not None:
			statement.set('balance', str(balance))

		statement.text = data

		self.opener.open('https://api.wesabe.com/rest/upload/statement', ElementTree.tostring(upload, 'UTF-8'))
