# Path: lib/fpos/core.py
# def money(value):
# def lcs(a, b):
# 
# Path: lib/fpos/core.py
# def money(value):
#     return "{:.2f}".format(value)
# 
# Path: lib/fpos/groups.py
# class DynamicGroups(GroupProtocol):
#     def __init__(self, threshold=0.85, size=4, backend=None):
#         if backend is None:
#             backend = SqlGroupCollection()
#         self.backend = backend
#         self._strgrp = Strgrp(threshold=threshold, size=size)
#         self.size = size
#         self.threshold = threshold
#         self.map = dict()
# 
#     def __iter__(self):
#         return iter(self._strgrp)
# 
#     def __enter__(self):
#         self.backend.__enter__()
#         return self
# 
#     def __exit__(self, exc_type, exc_value, traceback):
#         self.backend.__exit__(exc_type, exc_value, traceback)
# 
#     def _split_heap(self, heap):
#         i = None
# 
#         for i, grpbin in enumerate(heap):
#             acceptable = grpbin.is_acceptible(self._strgrp)
#             if not acceptable:
#                 r = (heap[:i], heap[i:])
#                 break
#         else:
#             r = (heap, [])
# 
#         return r
# 
#     def find_group(self, description):
#         grpbin = self._strgrp.grp_exact(description)
#         if grpbin is not None:
#             return grpbin
# 
#         did = gen_id(description, salt)
#         if self.backend.have_association(did):
#             cid = self.backend.get_canonical(did)
#             if cid in self.map:
#                 return self._strgrp.grp_exact(self.map[cid])
#             return None
# 
#         heap = self._strgrp.grps_for(description)
# 
#         if self.size == 0:
#             return heap[0] if len(heap) else None
# 
#         needles, haystack = self._split_heap(heap)
#         if len(needles) == 0:
#             return None
# 
#         dynamic = [n.is_dynamic(self._strgrp) for n in needles]
#         if sum(dynamic) == 1:
#             return needles[dynamic.index(True)]
# 
#         # Otherwise get user input
#         return self._request_match(description, needles)
# 
#     def insert(self, description, value, group=None):
#         did = gen_id(description, salt)
#         if group:
#             group.add(self._strgrp, description, value)
#             gid = gen_id(group.key(), salt)
#             cid = self.backend.get_canonical(gid);
#             if not self.backend.have_association(did):
#                 self.backend.associate(cid, did)
#         else:
#             group = self._strgrp.add(description, value)
#             if self.backend.have_association(did):
#                 cid = self.backend.get_canonical(did)
#                 self.map[cid] = description
#             else:
#                 self.map[did] = description
#                 self.backend.associate(did, did)
# 
#         return group
# 
#     def add(self, description, value):
#         return self.insert(description, value, self.find_group(description))


import argparse
import csv
import collections
import math
import re
from .core import categories
from .core import money
from .groups import DynamicGroups

class TagIO(object):
    def __init__(self, categories):
        self.categories = categories

    def banner(self, entry):
        fmtargs = ("Spent" if 0 > float(entry.amount) else "Earnt",
                money(abs(float(entry.amount))),
                entry.date,
                entry.description)
        print("{} ${!s} on {!s}: {!s}".format(*fmtargs))

    def resolve(self, guess):
        prompt = "Category [{!s}]: ".format("?" if guess is None else guess)
        return input(prompt).strip()

    def confirm(self, category):
        return input("Confirm {} [y/N]: ".format(category)).strip()

    def help(self):
        print()
        print(*self.categories, sep='\n')
        print()

    def warn(self, message):
        print(message)

class _Tagger(object):
    def __init__(self, grouper=None, io=None):
        self.grouper = DynamicGroups() if grouper is None else grouper

# Path: lib/fpos/core.py
# def money(value):
# def lcs(a, b):
# 
# Path: lib/fpos/core.py
# def money(value):
#     return "{:.2f}".format(value)
# 
# Path: lib/fpos/groups.py
# class DynamicGroups(GroupProtocol):
#     def __init__(self, threshold=0.85, size=4, backend=None):
#         if backend is None:
#             backend = SqlGroupCollection()
#         self.backend = backend
#         self._strgrp = Strgrp(threshold=threshold, size=size)
#         self.size = size
#         self.threshold = threshold
#         self.map = dict()
# 
#     def __iter__(self):
#         return iter(self._strgrp)
# 
#     def __enter__(self):
#         self.backend.__enter__()
#         return self
# 
#     def __exit__(self, exc_type, exc_value, traceback):
#         self.backend.__exit__(exc_type, exc_value, traceback)
# 
#     def _split_heap(self, heap):
#         i = None
# 
#         for i, grpbin in enumerate(heap):
#             acceptable = grpbin.is_acceptible(self._strgrp)
#             if not acceptable:
#                 r = (heap[:i], heap[i:])
#                 break
#         else:
#             r = (heap, [])
# 
#         return r
# 
#     def find_group(self, description):
#         grpbin = self._strgrp.grp_exact(description)
#         if grpbin is not None:
#             return grpbin
# 
#         did = gen_id(description, salt)
#         if self.backend.have_association(did):
#             cid = self.backend.get_canonical(did)
#             if cid in self.map:
#                 return self._strgrp.grp_exact(self.map[cid])
#             return None
# 
#         heap = self._strgrp.grps_for(description)
# 
#         if self.size == 0:
#             return heap[0] if len(heap) else None
# 
#         needles, haystack = self._split_heap(heap)
#         if len(needles) == 0:
#             return None
# 
#         dynamic = [n.is_dynamic(self._strgrp) for n in needles]
#         if sum(dynamic) == 1:
#             return needles[dynamic.index(True)]
# 
#         # Otherwise get user input
#         return self._request_match(description, needles)
# 
#     def insert(self, description, value, group=None):
#         did = gen_id(description, salt)
#         if group:
#             group.add(self._strgrp, description, value)
#             gid = gen_id(group.key(), salt)
#             cid = self.backend.get_canonical(gid);
#             if not self.backend.have_association(did):
#                 self.backend.associate(cid, did)
#         else:
#             group = self._strgrp.add(description, value)
#             if self.backend.have_association(did):
#                 cid = self.backend.get_canonical(did)
#                 self.map[cid] = description
#             else:
#                 self.map[did] = description
#                 self.backend.associate(did, did)
# 
#         return group
# 
#     def add(self, description, value):
#         return self.insert(description, value, self.find_group(description))


# Path: lib/fpos/annotate.py
import argparse
import csv
import collections
import math
import re
from .core import categories
from .core import money
from .groups import DynamicGroups


class TagIO(object):
    def __init__(self, categories):
        self.categories = categories

    def banner(self, entry):
        fmtargs = ("Spent" if 0 > float(entry.amount) else "Earnt",
                money(abs(float(entry.amount))),
                entry.date,
                entry.description)
        print("{} ${!s} on {!s}: {!s}".format(*fmtargs))

    def resolve(self, guess):
        prompt = "Category [{!s}]: ".format("?" if guess is None else guess)
        return input(prompt).strip()

    def confirm(self, category):
        return input("Confirm {} [y/N]: ".format(category)).strip()

    def help(self):
        print()
        print(*self.categories, sep='\n')
        print()

    def warn(self, message):
        print(message)

class _Tagger(object):
    def __init__(self, grouper=None, io=None):
        self.grouper = DynamicGroups() if grouper is None else grouper

        self.io = TagIO(categories) if io is None else io