summaryrefslogtreecommitdiff
path: root/filters.h
diff options
context:
space:
mode:
Diffstat (limited to 'filters.h')
-rw-r--r--filters.h702
1 files changed, 702 insertions, 0 deletions
diff --git a/filters.h b/filters.h
new file mode 100644
index 00000000..7f67cbd8
--- /dev/null
+++ b/filters.h
@@ -0,0 +1,702 @@
+/*
+ * Copyright (c) 2003-2008, John Wiegley. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * - Neither the name of New Artisans LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _FILTERS_H
+#define _FILTERS_H
+
+#include "handler.h"
+#include "predicate.h"
+#include "entry.h"
+
+namespace ledger {
+
+//////////////////////////////////////////////////////////////////////
+//
+// Transaction filters
+//
+
+class ignore_xacts : public item_handler<xact_t>
+{
+public:
+ virtual void operator()(xact_t&) {}
+};
+
+class clear_xact_xdata : public item_handler<xact_t>
+{
+public:
+ virtual void operator()(xact_t& xact) {
+ xact.clear_xdata();
+ }
+};
+
+class xacts_iterator;
+
+class pass_down_xacts : public item_handler<xact_t>
+{
+ pass_down_xacts();
+
+public:
+ pass_down_xacts(xact_handler_ptr handler, xacts_iterator& iter);
+
+ virtual ~pass_down_xacts() {
+ TRACE_DTOR(pass_down_xacts);
+ }
+};
+
+class push_to_xacts_list : public item_handler<xact_t>
+{
+ push_to_xacts_list();
+
+public:
+ xacts_list& xacts;
+
+ push_to_xacts_list(xacts_list& _xacts) : xacts(_xacts) {
+ TRACE_CTOR(push_to_xacts_list, "xacts_list&");
+ }
+ virtual ~push_to_xacts_list() {
+ TRACE_DTOR(push_to_xacts_list);
+ }
+
+ virtual void operator()(xact_t& xact) {
+ xacts.push_back(&xact);
+ }
+};
+
+class truncate_entries : public item_handler<xact_t>
+{
+ int head_count;
+ int tail_count;
+
+ xacts_list xacts;
+
+ truncate_entries();
+
+public:
+ truncate_entries(xact_handler_ptr handler,
+ int _head_count, int _tail_count)
+ : item_handler<xact_t>(handler),
+ head_count(_head_count), tail_count(_tail_count) {
+ TRACE_CTOR(truncate_entries, "xact_handler_ptr, int, int");
+ }
+ virtual ~truncate_entries() {
+ TRACE_DTOR(truncate_entries);
+ }
+
+ virtual void flush();
+ virtual void operator()(xact_t& xact) {
+ if (tail_count == 0 && head_count > 0 &&
+ xacts.size() >= static_cast<unsigned int>(head_count))
+ return;
+ xacts.push_back(&xact);
+ }
+};
+
+class set_account_value : public item_handler<xact_t>
+{
+public:
+ set_account_value(xact_handler_ptr handler = xact_handler_ptr())
+ : item_handler<xact_t>(handler) {}
+
+ virtual void operator()(xact_t& xact);
+};
+
+class sort_xacts : public item_handler<xact_t>
+{
+ typedef std::deque<xact_t *> xacts_deque;
+
+ xacts_deque xacts;
+ const expr_t sort_order;
+
+ sort_xacts();
+
+public:
+ sort_xacts(xact_handler_ptr handler,
+ const expr_t& _sort_order)
+ : item_handler<xact_t>(handler),
+ sort_order(_sort_order) {
+ TRACE_CTOR(sort_xacts,
+ "xact_handler_ptr, const value_expr&");
+ }
+ sort_xacts(xact_handler_ptr handler,
+ const string& _sort_order)
+ : item_handler<xact_t>(handler),
+ sort_order(_sort_order) {
+ TRACE_CTOR(sort_xacts,
+ "xact_handler_ptr, const string&");
+ }
+ virtual ~sort_xacts() {
+ TRACE_DTOR(sort_xacts);
+ }
+
+ virtual void post_accumulated_xacts();
+
+ virtual void flush() {
+ post_accumulated_xacts();
+ item_handler<xact_t>::flush();
+ }
+
+ virtual void operator()(xact_t& xact) {
+ xacts.push_back(&xact);
+ }
+};
+
+class sort_entries : public item_handler<xact_t>
+{
+ sort_xacts sorter;
+ entry_t * last_entry;
+
+ sort_entries();
+
+public:
+ sort_entries(xact_handler_ptr handler,
+ const expr_t& _sort_order)
+ : sorter(handler, _sort_order) {
+ TRACE_CTOR(sort_entries,
+ "xact_handler_ptr, const value_expr&");
+ }
+ sort_entries(xact_handler_ptr handler,
+ const string& _sort_order)
+ : sorter(handler, _sort_order) {
+ TRACE_CTOR(sort_entries,
+ "xact_handler_ptr, const string&");
+ }
+ virtual ~sort_entries() {
+ TRACE_DTOR(sort_entries);
+ }
+
+ virtual void flush() {
+ sorter.flush();
+ item_handler<xact_t>::flush();
+ }
+
+ virtual void operator()(xact_t& xact) {
+ if (last_entry && xact.entry != last_entry)
+ sorter.post_accumulated_xacts();
+
+ sorter(xact);
+
+ last_entry = xact.entry;
+ }
+};
+
+class filter_xacts : public item_handler<xact_t>
+{
+ item_predicate<xact_t> pred;
+
+ filter_xacts();
+
+public:
+ filter_xacts(xact_handler_ptr handler,
+ const expr_t& predicate)
+ : item_handler<xact_t>(handler), pred(predicate) {
+ TRACE_CTOR(filter_xacts,
+ "xact_handler_ptr, const value_expr&");
+ }
+
+ filter_xacts(xact_handler_ptr handler,
+ const string& predicate)
+ : item_handler<xact_t>(handler), pred(predicate) {
+ TRACE_CTOR(filter_xacts,
+ "xact_handler_ptr, const string&");
+ }
+ virtual ~filter_xacts() {
+ TRACE_DTOR(filter_xacts);
+ }
+
+ virtual void operator()(xact_t& xact) {
+ if (pred(xact)) {
+ xact.xdata().add_flags(XACT_EXT_MATCHES);
+ (*handler)(xact);
+ }
+ }
+};
+
+class calc_xacts : public item_handler<xact_t>
+{
+ xact_t * last_xact;
+
+ calc_xacts();
+
+public:
+ calc_xacts(xact_handler_ptr handler)
+ : item_handler<xact_t>(handler), last_xact(NULL) {
+ TRACE_CTOR(calc_xacts, "xact_handler_ptr");
+ }
+ virtual ~calc_xacts() {
+ TRACE_DTOR(calc_xacts);
+ }
+
+ virtual void operator()(xact_t& xact);
+};
+
+class invert_xacts : public item_handler<xact_t>
+{
+ invert_xacts();
+
+public:
+ invert_xacts(xact_handler_ptr handler)
+ : item_handler<xact_t>(handler) {}
+
+ virtual void operator()(xact_t& xact);
+};
+
+inline void clear_entries_xacts(std::list<entry_t>& entries_list) {
+ foreach (entry_t& entry, entries_list)
+ entry.xacts.clear();
+}
+
+class collapse_xacts : public item_handler<xact_t>
+{
+ value_t subtotal;
+ unsigned int count;
+ entry_t * last_entry;
+ xact_t * last_xact;
+ account_t totals_account;
+
+ std::list<entry_t> entry_temps;
+ std::list<xact_t> xact_temps;
+
+ collapse_xacts();
+
+public:
+ collapse_xacts(xact_handler_ptr handler)
+ : item_handler<xact_t>(handler), count(0),
+ last_entry(NULL), last_xact(NULL),
+ totals_account(NULL, "<Total>") {
+ TRACE_CTOR(collapse_xacts, "xact_handler_ptr");
+ }
+ virtual ~collapse_xacts() {
+ TRACE_DTOR(collapse_xacts);
+ clear_entries_xacts(entry_temps);
+ }
+
+ virtual void flush() {
+ if (subtotal)
+ report_subtotal();
+ item_handler<xact_t>::flush();
+ }
+
+ void report_subtotal();
+
+ virtual void operator()(xact_t& xact);
+};
+
+class component_xacts : public item_handler<xact_t>
+{
+ item_predicate<xact_t> pred;
+
+ component_xacts();
+
+public:
+ component_xacts(xact_handler_ptr handler,
+ const expr_t& predicate)
+ : item_handler<xact_t>(handler), pred(predicate) {
+ TRACE_CTOR(component_xacts,
+ "xact_handler_ptr, const value_expr&");
+ }
+ component_xacts(xact_handler_ptr handler,
+ const string& predicate)
+ : item_handler<xact_t>(handler), pred(predicate) {
+ TRACE_CTOR(component_xacts,
+ "xact_handler_ptr, const string&");
+ }
+ virtual ~component_xacts() throw() {
+ TRACE_DTOR(component_xacts);
+ }
+
+ virtual void operator()(xact_t& xact);
+};
+
+class related_xacts : public item_handler<xact_t>
+{
+ xacts_list xacts;
+ bool also_matching;
+
+ related_xacts();
+
+public:
+ related_xacts(xact_handler_ptr handler,
+ const bool _also_matching = false)
+ : item_handler<xact_t>(handler),
+ also_matching(_also_matching) {
+ TRACE_CTOR(related_xacts,
+ "xact_handler_ptr, const bool");
+ }
+ virtual ~related_xacts() throw() {
+ TRACE_DTOR(related_xacts);
+ }
+
+ virtual void flush();
+ virtual void operator()(xact_t& xact) {
+ xact.xdata().add_flags(XACT_EXT_RECEIVED);
+ xacts.push_back(&xact);
+ }
+};
+
+class changed_value_xacts : public item_handler<xact_t>
+{
+ // This filter requires that calc_xacts be used at some point
+ // later in the chain.
+
+ bool changed_values_only;
+ xact_t * last_xact;
+ value_t last_balance;
+
+ std::list<entry_t> entry_temps;
+ std::list<xact_t> xact_temps;
+
+ changed_value_xacts();
+
+public:
+ changed_value_xacts(xact_handler_ptr handler,
+ bool _changed_values_only)
+ : item_handler<xact_t>(handler),
+ changed_values_only(_changed_values_only), last_xact(NULL) {
+ TRACE_CTOR(changed_value_xacts,
+ "xact_handler_ptr, bool");
+ }
+ virtual ~changed_value_xacts() {
+ TRACE_DTOR(changed_value_xacts);
+ clear_entries_xacts(entry_temps);
+ }
+
+ virtual void flush() {
+ if (last_xact) {
+ output_diff(current_date);
+ last_xact = NULL;
+ }
+ item_handler<xact_t>::flush();
+ }
+
+ void output_diff(const date_t& current);
+
+ virtual void operator()(xact_t& xact);
+};
+
+class subtotal_xacts : public item_handler<xact_t>
+{
+ class acct_value_t
+ {
+ acct_value_t();
+
+ public:
+ account_t * account;
+ value_t value;
+
+ xacts_list components;
+
+ acct_value_t(account_t * a) : account(a) {
+ TRACE_CTOR(acct_value_t, "acount_t *");
+ }
+ acct_value_t(account_t * a, value_t& v) : account(a), value(v) {
+ TRACE_CTOR(acct_value_t, "acount_t *, value_t&");
+ }
+ acct_value_t(const acct_value_t& av)
+ : account(av.account), value(av.value),
+ components(av.components) {
+ TRACE_CTOR(acct_value_t, "copy");
+ }
+ ~acct_value_t() throw() {
+ TRACE_DTOR(acct_value_t);
+ }
+ };
+
+ typedef std::map<string, acct_value_t> values_map;
+ typedef std::pair<string, acct_value_t> values_pair;
+
+ subtotal_xacts();
+
+protected:
+ values_map values;
+ bool remember_components;
+
+ std::list<entry_t> entry_temps;
+ std::list<xact_t> xact_temps;
+
+public:
+ date_t start;
+ date_t finish;
+
+ subtotal_xacts(xact_handler_ptr handler,
+ bool _remember_components = false)
+ : item_handler<xact_t>(handler),
+ remember_components(_remember_components) {
+ TRACE_CTOR(subtotal_xacts,
+ "xact_handler_ptr, bool");
+ }
+ virtual ~subtotal_xacts() {
+ TRACE_DTOR(subtotal_xacts);
+ clear_entries_xacts(entry_temps);
+ }
+
+ void report_subtotal(const char * spec_fmt = NULL);
+
+ virtual void flush() {
+ if (values.size() > 0)
+ report_subtotal();
+ item_handler<xact_t>::flush();
+ }
+ virtual void operator()(xact_t& xact);
+};
+
+class interval_xacts : public subtotal_xacts
+{
+ interval_t interval;
+ xact_t * last_xact;
+ bool started;
+
+ interval_xacts();
+
+public:
+ interval_xacts(xact_handler_ptr _handler,
+ const interval_t& _interval,
+ bool remember_components = false)
+ : subtotal_xacts(_handler, remember_components),
+ interval(_interval), last_xact(NULL), started(false) {
+ TRACE_CTOR(interval_xacts,
+ "xact_handler_ptr, const interval_t&, bool");
+ }
+ interval_xacts(xact_handler_ptr _handler,
+ const string& _interval,
+ bool remember_components = false)
+ : subtotal_xacts(_handler, remember_components),
+ interval(_interval), last_xact(NULL), started(false) {
+ TRACE_CTOR(interval_xacts,
+ "xact_handler_ptr, const string&, bool");
+ }
+ virtual ~interval_xacts() throw() {
+ TRACE_DTOR(interval_xacts);
+ }
+
+ void report_subtotal(const date_t& moment = date_t());
+
+ virtual void flush() {
+ if (last_xact)
+ report_subtotal();
+ subtotal_xacts::flush();
+ }
+ virtual void operator()(xact_t& xact);
+};
+
+class by_payee_xacts : public item_handler<xact_t>
+{
+ typedef std::map<string, subtotal_xacts *> payee_subtotals_map;
+ typedef std::pair<string, subtotal_xacts *> payee_subtotals_pair;
+
+ payee_subtotals_map payee_subtotals;
+ bool remember_components;
+
+ by_payee_xacts();
+
+ public:
+ by_payee_xacts(xact_handler_ptr handler,
+ bool _remember_components = false)
+ : item_handler<xact_t>(handler),
+ remember_components(_remember_components) {
+ TRACE_CTOR(by_payee_xacts,
+ "xact_handler_ptr, bool");
+ }
+ virtual ~by_payee_xacts();
+
+ virtual void flush();
+ virtual void operator()(xact_t& xact);
+};
+
+class set_comm_as_payee : public item_handler<xact_t>
+{
+ std::list<entry_t> entry_temps;
+ std::list<xact_t> xact_temps;
+
+ set_comm_as_payee();
+
+public:
+ set_comm_as_payee(xact_handler_ptr handler)
+ : item_handler<xact_t>(handler) {
+ TRACE_CTOR(set_comm_as_payee, "xact_handler_ptr");
+ }
+ virtual ~set_comm_as_payee() {
+ TRACE_DTOR(set_comm_as_payee);
+ clear_entries_xacts(entry_temps);
+ }
+
+ virtual void operator()(xact_t& xact);
+};
+
+class set_code_as_payee : public item_handler<xact_t>
+{
+ std::list<entry_t> entry_temps;
+ std::list<xact_t> xact_temps;
+
+ set_code_as_payee();
+
+public:
+ set_code_as_payee(xact_handler_ptr handler)
+ : item_handler<xact_t>(handler) {
+ TRACE_CTOR(set_code_as_payee, "xact_handler_ptr");
+ }
+ virtual ~set_code_as_payee() {
+ TRACE_DTOR(set_code_as_payee);
+ clear_entries_xacts(entry_temps);
+ }
+
+ virtual void operator()(xact_t& xact);
+};
+
+class dow_xacts : public subtotal_xacts
+{
+ xacts_list days_of_the_week[7];
+
+ dow_xacts();
+
+public:
+ dow_xacts(xact_handler_ptr handler,
+ bool remember_components = false)
+ : subtotal_xacts(handler, remember_components) {
+ TRACE_CTOR(dow_xacts, "xact_handler_ptr, bool");
+ }
+ virtual ~dow_xacts() throw() {
+ TRACE_DTOR(dow_xacts);
+ }
+
+ virtual void flush();
+ virtual void operator()(xact_t& xact) {
+ days_of_the_week[xact.date().day_of_week()].push_back(&xact);
+ }
+};
+
+class generate_xacts : public item_handler<xact_t>
+{
+ generate_xacts();
+
+protected:
+ typedef std::pair<interval_t, xact_t *> pending_xacts_pair;
+ typedef std::list<pending_xacts_pair> pending_xacts_list;
+
+ pending_xacts_list pending_xacts;
+ std::list<entry_t> entry_temps;
+ std::list<xact_t> xact_temps;
+
+public:
+ generate_xacts(xact_handler_ptr handler)
+ : item_handler<xact_t>(handler) {
+ TRACE_CTOR(dow_xacts, "xact_handler_ptr");
+ }
+
+ virtual ~generate_xacts() {
+ TRACE_DTOR(generate_xacts);
+ clear_entries_xacts(entry_temps);
+ }
+
+ void add_period_entries(period_entries_list& period_entries);
+
+ virtual void add_xact(const interval_t& period, xact_t& xact);
+};
+
+class budget_xacts : public generate_xacts
+{
+#define BUDGET_NO_BUDGET 0x00
+#define BUDGET_BUDGETED 0x01
+#define BUDGET_UNBUDGETED 0x02
+
+ unsigned short flags;
+
+ budget_xacts();
+
+public:
+ budget_xacts(xact_handler_ptr handler,
+ unsigned long _flags = BUDGET_BUDGETED)
+ : generate_xacts(handler), flags(_flags) {
+ TRACE_CTOR(budget_xacts,
+ "xact_handler_ptr, unsigned long");
+ }
+ virtual ~budget_xacts() throw() {
+ TRACE_DTOR(budget_xacts);
+ }
+
+ void report_budget_items(const date_t& date);
+
+ virtual void operator()(xact_t& xact);
+};
+
+class forecast_xacts : public generate_xacts
+{
+ item_predicate<xact_t> pred;
+
+ public:
+ forecast_xacts(xact_handler_ptr handler,
+ const expr_t& predicate)
+ : generate_xacts(handler), pred(predicate) {
+ TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const expr_t&");
+ }
+ forecast_xacts(xact_handler_ptr handler,
+ const string& predicate)
+ : generate_xacts(handler), pred(predicate) {
+ TRACE_CTOR(forecast_xacts, "xact_handler_ptr, const string&");
+ }
+ virtual ~forecast_xacts() throw() {
+ TRACE_DTOR(forecast_xacts);
+ }
+
+ virtual void add_xact(const interval_t& period,
+ xact_t& xact);
+ virtual void flush();
+};
+
+//////////////////////////////////////////////////////////////////////
+//
+// Account filters
+//
+
+class clear_account_xdata : public item_handler<account_t>
+{
+public:
+ virtual void operator()(account_t& acct) {
+ acct.clear_xdata();
+ }
+};
+
+class accounts_iterator;
+
+class pass_down_accounts : public item_handler<account_t>
+{
+ pass_down_accounts();
+
+public:
+ pass_down_accounts(acct_handler_ptr handler, accounts_iterator& iter);
+
+ virtual ~pass_down_accounts() {
+ TRACE_DTOR(pass_down_accounts);
+ }
+};
+
+} // namespace ledger
+
+#endif // _FILTERS_H