#!/usr/bin/env python

"""Ledger module for the Lemonade accounting project"""

from .journal import Journal
from .ledger_account import LedgerAccount
from lemonade import helpers


class Ledger(object):
    """Ledger abstraction for General Ledger"""

    def __init__(self, name=None, journal=None):

        if name is None:
            raise TypeError("name is a required named parameter")
        else:
            self._name = name

        if journal is None or not isinstance(journal, Journal):
            raise TypeError("journal is a required named parameter")
        else:
            self._journal = journal

        self._accounts = {}
        self._parse_journal()

    def lookup_account(self, account_number):
        """Given account_number, return title of account

        Title of Account is given by ChartOfAccount (accessed
        via Journal). If there is no ChartOfAccount, this
        account will be "unknown."
        """
        coa = self._journal.coa

        if coa is None:
            return "unknown"
        else:
            return coa.get_title(account_number)

    def _ensure_account_entry(self, debit_credit):
        """Ensure that self._accounts has a LedgerAccount entry for account

        If self._accounts doesn't have an account entry for the credit
        or debit in question, then a new LedgerAccount instance is created.
        """
        if isinstance(debit_credit.post_ref, basestring):
            account_number = debit_credit.post_ref
        else:
            account_number = str(debit_credit.post_ref)

        if account_number not in self._accounts:
            self._accounts[account_number] = LedgerAccount(
                account_number=debit_credit.post_ref,
                account_name=self.lookup_account(debit_credit.post_ref))

    def _parse_journal(self):
        """"Parse the attached journal sorting entries by account number."""
        for entry in self._journal.entries:
            for debit in entry.debits:
                self._ensure_account_entry(debit)
                self._accounts[str(debit.post_ref)].add_debit(debit)
            for credit in entry.credits:
                self._ensure_account_entry(credit)
                self._accounts[str(credit.post_ref)].add_credit(credit)

    def __getitem__(self, key):
        return self._accounts[key]

    @property
    def accounts(self):
        """Return list of all accounts in Ledger"""
        return self._accounts.keys()

    def get_credits(self, account_number):
        """Return all credits associated with given `account_number`

        If `account_number` is given as an integer, it is converted to
        a string before doing the lookup as all keys are stored as
        strings.
        """

        account_number = helpers.to_s(account_number)
        return self._accounts[account_number].credits

    def get_debits(self, account_number):
        """Return all credits associated with given `account_number`

        If `account_number` is given as an integer, it is converted to
        a string before doing the lookup as all keys are stored as
        strings.
        """

        account_number = helpers.to_s(account_number)
        return self._accounts[account_number].debits
