"""
Gathers up all of the expenses and breaks down the values by month.
"""
from datetime import datetime
import time

from gnu_reporting.reports.base import Report
from gnu_reporting.wrapper import get_splits, account_walker
from gnu_reporting.periods import PeriodStart, PeriodEnd, PeriodSize
from dateutil.relativedelta import relativedelta
from gnu_reporting.collate.bucket import PeriodCollate, CategoryCollate
from gnu_reporting.collate.store import split_summation
from gnu_reporting.collate.bucket_generation import decimal_generator
from operator import itemgetter
import numpy as np


class ExpensesMonthly(Report):
    report_type = 'expenses_period'

    def __init__(self, name, expenses_base, ignore_list=None, period_start=PeriodStart.this_month_year_ago.value,
                 period_end=PeriodEnd.this_month.value, period_size=PeriodSize.month.value):
        super(ExpensesMonthly, self).__init__(name)
        self.expenses_base = expenses_base

        if ignore_list:
            self.ignore_list = ignore_list
        else:
            self.ignore_list = []

        self._start = PeriodStart(period_start)
        self._end = PeriodEnd(period_end)
        self._size = PeriodSize(period_size)

    def __call__(self):

        bucket = PeriodCollate(self._start.date, self._end.date, decimal_generator, split_summation,
                               frequency=self._size.frequency, interval=self._size.interval)

        for account in account_walker(self.expenses_base, self.ignore_list):
            for split in get_splits(account, self._start.date, self._end.date):
                bucket.store_value(split)

        return_value = self._generate_result()
        sorted_results = []

        for key, value in bucket.container.iteritems():
            sorted_results.append(dict(date=time.mktime(key.timetuple()), value=value))

        return_value['data']['expenses'] = sorted(sorted_results, key=lambda s: s['date'])

        return return_value


class ExpensesMonthlyBox(Report):
    report_type = 'expenses_box'

    def __init__(self, name, expenses_base, ignore_list=None, period_start=PeriodStart.this_month_year_ago,
                 period_end=PeriodEnd.this_month, period_size=PeriodSize.month):
        super(ExpensesMonthlyBox, self).__init__(name)
        self.expenses_base = expenses_base

        if ignore_list:
            self.ignore_list = ignore_list
        else:
            self.ignore_list = []

        self._start = PeriodStart(period_start)
        self._end = PeriodEnd(period_end)
        self._size = PeriodSize(period_size)

    def __call__(self):

        bucket = PeriodCollate(self._start.date, self._end.date, decimal_generator, split_summation,
                               frequency=self._size.frequency, interval=self._size.interval)

        for account in account_walker(self.expenses_base, self.ignore_list):
            for split in get_splits(account, self._start.date, self._end.date):
                bucket.store_value(split)

        return_value = self._generate_result()
        results = []

        for key, value in bucket.container.iteritems():
            results.append(float(value))

        return_value['data']['low'] = np.percentile(results, 0)
        return_value['data']['high'] = np.percentile(results, 100)
        return_value['data']['q1'] = np.percentile(results, 25)
        return_value['data']['q2'] = np.percentile(results, 50)
        return_value['data']['q3'] = np.percentile(results, 75)

        return return_value


class ExpenseCategories(Report):
    report_type = 'expenses_categories'

    def __init__(self, name, expenses_base, ignore_list=None, period_start=PeriodStart.this_year.value,
                 period_end=PeriodEnd.this_year.value):
        super(ExpenseCategories, self).__init__(name)
        self.expenses_base = expenses_base

        if ignore_list:
            self.ignore_list = ignore_list
        else:
            self.ignore_list = []

        self._start = PeriodStart(period_start)
        self._end = PeriodEnd(period_end)

    def __call__(self):
        bucket = CategoryCollate(decimal_generator, split_summation)

        for account in account_walker(self.expenses_base, self.ignore_list):
            for split in get_splits(account, self._start.date, self._end.date):
                bucket.store_value(split)

        return_value = self._generate_result()

        return_value['data']['categories'] = sorted([[key, value] for key, value in bucket.container.iteritems()],
                                                    key=itemgetter(1))

        return return_value

if __name__ == '__main__':

    import simplejson as json
    from gnu_reporting.wrapper import initialize

    session = initialize('data/Accounts.gnucash')

    try:
        report = ExpensesMonthlyBox('expenses', ['Expenses'], ['Expenses.Taxes',
                                                               'Expenses.Seaside View',
                                                               'Expenses.ISSACCorp',
                                                               'Expenses.DQI'])

        result = report()

        print json.dumps(result)
    finally:
        session.end()




@@ -464,16 +464,23 @@
 ummation
+, count
 %0Afrom gn
@@ -541,16 +541,35 @@
 enerator
+, integer_generator
 %0Afrom op
@@ -882,24 +882,49 @@
 .month.value
+, show_record_count=False
 ):%0A        s
@@ -1252,32 +1252,84 @@
 ize(period_size)
+%0A        self._show_record_count = show_record_count
 %0A%0A    def __call
@@ -1524,32 +1524,228 @@
 ._size.interval)
+%0A        record_count = PeriodCollate(self._start.date, self._end.date, integer_generator, count,%0A                                     frequency=self._size.frequency, interval=self._size.interval)
 %0A%0A        for ac
@@ -1920,32 +1920,80 @@
 ore_value(split)
+%0A                record_count.store_value(split)
 %0A%0A        return
@@ -2044,32 +2044,66 @@
 ted_results = %5B%5D
+%0A        sorted_count_results = %5B%5D
 %0A%0A        for ke
@@ -2245,56 +2245,348 @@
     
-return_value%5B'data'%5D%5B'expenses'%5D = sorted(sorted
+for key, value in record_count.container.iteritems():%0A            sorted_count_results.append(dict(date=time.mktime(key.timetuple()), value=value))%0A%0A        return_value%5B'data'%5D%5B'expenses'%5D = sorted(sorted_results, key=lambda s: s%5B'date'%5D)%0A%0A        if self._show_record_count:%0A            return_value%5B'data'%5D%5B'count'%5D = sorted(sorted_count
 _res
@@ -5259,17 +5259,17 @@
 mgetter(
-1
+0
 ))%0A%0A    

Add record count to monthly expenses.