# Path: beancount_import/journal_editor.py
# META_IGNORE = get_meta_ignore()
# 
# Path: beancount_import/sorted_list.py
# class SortedList(Generic[K, V]):
#     def __init__(self, items: Iterable[Tuple[K, V]]) -> None:
#         entries = sorted(items, key=lambda x: x[0])
#         self.keys = [x[0] for x in entries]
#         self.values = [x[1] for x in entries]
# 
#     def __repr__(self) -> str:
#         return repr(list(zip(self.keys, self.values)))
# 
#     def find(self, lower_bound: K, upper_bound: K) -> Iterable[V]:
#         keys = self.keys
#         begin_pos = bisect.bisect_left(keys, lower_bound)
#         end_pos = bisect.bisect_right(keys, upper_bound)
#         if begin_pos == end_pos:
#             return ()
#         return itertools.islice(self.values, begin_pos, end_pos)
# 
# Path: beancount_import/posting_date.py
# def get_posting_date(entry, posting):
#     """Returns the date associated with a posting."""
#     return ((posting.meta and (posting.meta.get(POSTING_DATE_KEY) or
#                                posting.meta.get(POSTING_TRANSACTION_DATE_KEY))) or entry.date)
# 
# POSTING_DATE_KEY = 'date'
# 
# POSTING_TRANSACTION_DATE_KEY = 'transaction_date'


import datetime
import collections
import itertools
import beancount.parser.printer
from typing import Sequence, Tuple, List, NamedTuple, Dict, Callable, Optional, Iterable, Set, cast, FrozenSet, Union, Any
from beancount.core.number import MISSING, ZERO, Decimal
from beancount.core.data import Transaction, Posting, Meta, Cost, CostSpec
from beancount.core.amount import mul as amount_mul
from beancount.core.amount import Amount
from beancount.parser import booking_full
from .journal_editor import META_IGNORE
from .sorted_list import SortedList
from .posting_date import get_posting_date, POSTING_DATE_KEY, POSTING_TRANSACTION_DATE_KEY

SingleSignMatchGroups = NamedTuple(
    'SingleSignMatchGroups',
    [('no_removals', SingleSignMatchGroup),
     ('single_removals', Tuple[SingleSignMatchGroup, SingleSignMatchGroup]),
     ('double_removals', SingleSignMatchGroup)])
BothSignMatchGroups = Tuple[SingleSignMatchGroups, SingleSignMatchGroups]


def is_unknown_account(account: str):
    return account == FIXME_ACCOUNT or account.startswith(
        MERGEABLE_FIXME_ACCOUNT_PREFIX)


def get_posting_weight(posting: Posting) -> Optional[Amount]:
    if posting.units is MISSING or posting.units is None:
        return None

    if posting.cost is not None and posting.cost.currency is not None:
        posting = booking_full.convert_costspec_to_cost(posting)
        if posting.cost.number is not None and posting.cost.number is not MISSING:
            return Amount(posting.cost.number * posting.units.number,
                          posting.cost.currency)
        return None
    elif posting.price is not None and posting.price.number is not MISSING:
        return amount_mul(posting.price, posting.units.number)
    return posting.units


def _date_key(entry: Transaction, mp: MatchablePosting):

# Path: beancount_import/journal_editor.py
# META_IGNORE = get_meta_ignore()
# 
# Path: beancount_import/sorted_list.py
# class SortedList(Generic[K, V]):
#     def __init__(self, items: Iterable[Tuple[K, V]]) -> None:
#         entries = sorted(items, key=lambda x: x[0])
#         self.keys = [x[0] for x in entries]
#         self.values = [x[1] for x in entries]
# 
#     def __repr__(self) -> str:
#         return repr(list(zip(self.keys, self.values)))
# 
#     def find(self, lower_bound: K, upper_bound: K) -> Iterable[V]:
#         keys = self.keys
#         begin_pos = bisect.bisect_left(keys, lower_bound)
#         end_pos = bisect.bisect_right(keys, upper_bound)
#         if begin_pos == end_pos:
#             return ()
#         return itertools.islice(self.values, begin_pos, end_pos)
# 
# Path: beancount_import/posting_date.py
# def get_posting_date(entry, posting):
#     """Returns the date associated with a posting."""
#     return ((posting.meta and (posting.meta.get(POSTING_DATE_KEY) or
#                                posting.meta.get(POSTING_TRANSACTION_DATE_KEY))) or entry.date)
# 
# POSTING_DATE_KEY = 'date'
# 
# POSTING_TRANSACTION_DATE_KEY = 'transaction_date'


# Path: beancount_import/matching.py
import datetime
import collections
import itertools
import beancount.parser.printer
from typing import Sequence, Tuple, List, NamedTuple, Dict, Callable, Optional, Iterable, Set, cast, FrozenSet, Union, Any
from beancount.core.number import MISSING, ZERO, Decimal
from beancount.core.data import Transaction, Posting, Meta, Cost, CostSpec
from beancount.core.amount import mul as amount_mul
from beancount.core.amount import Amount
from beancount.parser import booking_full
from .journal_editor import META_IGNORE
from .sorted_list import SortedList
from .posting_date import get_posting_date, POSTING_DATE_KEY, POSTING_TRANSACTION_DATE_KEY


SingleSignMatchGroups = NamedTuple(
    'SingleSignMatchGroups',
    [('no_removals', SingleSignMatchGroup),
     ('single_removals', Tuple[SingleSignMatchGroup, SingleSignMatchGroup]),
     ('double_removals', SingleSignMatchGroup)])
BothSignMatchGroups = Tuple[SingleSignMatchGroups, SingleSignMatchGroups]


def is_unknown_account(account: str):
    return account == FIXME_ACCOUNT or account.startswith(
        MERGEABLE_FIXME_ACCOUNT_PREFIX)


def get_posting_weight(posting: Posting) -> Optional[Amount]:
    if posting.units is MISSING or posting.units is None:
        return None

    if posting.cost is not None and posting.cost.currency is not None:
        posting = booking_full.convert_costspec_to_cost(posting)
        if posting.cost.number is not None and posting.cost.number is not MISSING:
            return Amount(posting.cost.number * posting.units.number,
                          posting.cost.currency)
        return None
    elif posting.price is not None and posting.price.number is not MISSING:
        return amount_mul(posting.price, posting.units.number)
    return posting.units


def _date_key(entry: Transaction, mp: MatchablePosting):

    return get_posting_date(entry, mp.posting)