/***************************************************************************
                          mymoneytransactionfilter.cpp  -  description
                             -------------------
    begin                : Fri Aug 22 2003
    copyright            : (C) 2003 by Thomas Baumgart
    email                : mte@users.sourceforge.net
                           Javier Campos Morales <javi_c@users.sourceforge.net>
                           Felix Rodriguez <frodriguez@users.sourceforge.net>
                           John C <thetacoturtle@users.sourceforge.net>
                           Thomas Baumgart <ipwizard@users.sourceforge.net>
                           Kevin Tambascio <ktambascio@users.sourceforge.net>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

// ----------------------------------------------------------------------------
// TQt Includes

// ----------------------------------------------------------------------------
// TDE Includes

// ----------------------------------------------------------------------------
// Project Includes

#include <kmymoney/mymoneyfile.h>
#include "mymoneytransactionfilter.h"

MyMoneyTransactionFilter::MyMoneyTransactionFilter()
{
  m_filterSet.allFilter = 0;
  m_reportAllSplits = true;
  m_considerCategory = true;
  m_invertText = false;
}

MyMoneyTransactionFilter::MyMoneyTransactionFilter(const TQString& id)
{
  m_filterSet.allFilter = 0;
  m_reportAllSplits = false;
  m_considerCategory = false;
  m_invertText = false;

  addAccount(id);
  // addCategory(id);
}

MyMoneyTransactionFilter::~MyMoneyTransactionFilter()
{
}

void MyMoneyTransactionFilter::clear(void)
{
  m_filterSet.allFilter = 0;
  m_invertText = false;
  m_accounts.clear();
  m_categories.clear();
  m_payees.clear();
  m_types.clear();
  m_states.clear();
  m_validity.clear();
  m_matchingSplits.clear();
  m_fromDate = TQDate();
  m_toDate = TQDate();
}

void MyMoneyTransactionFilter::clearAccountFilter(void)
{
  m_filterSet.singleFilter.accountFilter = 0;
  m_accounts.clear();
}

void MyMoneyTransactionFilter::setTextFilter(const TQRegExp& text, bool invert)
{
  m_filterSet.singleFilter.textFilter = 1;
  m_invertText = invert;
  m_text = text;
}

void MyMoneyTransactionFilter::addAccount(const TQStringList& ids)
{
  TQStringList::ConstIterator it;

  m_filterSet.singleFilter.accountFilter = 1;
  for(it = ids.begin(); it != ids.end(); ++it)
    addAccount(*it);
}

void MyMoneyTransactionFilter::addAccount(const TQString& id)
{
  if(!m_accounts.isEmpty() && !id.isEmpty()) {
    if(m_accounts.find(id.utf8()) != 0)
      return;
  }
  if(m_accounts.count() >= m_accounts.size()*2) {
    m_accounts.resize(457);
  }
  m_filterSet.singleFilter.accountFilter = 1;
  if(!id.isEmpty())
    m_accounts.insert(id.utf8(), "");
}

void MyMoneyTransactionFilter::addCategory(const TQStringList& ids)
{
  TQStringList::ConstIterator it;

  m_filterSet.singleFilter.categoryFilter = 1;
  for(it = ids.begin(); it != ids.end(); ++it)
    addCategory(*it);
}

void MyMoneyTransactionFilter::addCategory(const TQString& id)
{
  if(!m_categories.isEmpty() && !id.isEmpty()) {
    if(m_categories.find(id.utf8()) != 0)
      return;
  }
  if(m_categories.count() >= m_categories.size()*2) {
    m_categories.resize(457);
  }
  m_filterSet.singleFilter.categoryFilter = 1;
  if(!id.isEmpty())
    m_categories.insert(id.utf8(), "");
}

void MyMoneyTransactionFilter::setDateFilter(const TQDate& from, const TQDate& to)
{
  m_filterSet.singleFilter.dateFilter = from.isValid() | to.isValid();
  m_fromDate = from;
  m_toDate = to;
}

void MyMoneyTransactionFilter::setAmountFilter(const MyMoneyMoney& from, const MyMoneyMoney& to)
{
  m_filterSet.singleFilter.amountFilter = 1;
  m_fromAmount = from.abs();
  m_toAmount = to.abs();

  // make sure that the user does not try to fool us  ;-)
  if(from > to) {
    MyMoneyMoney tmp = m_fromAmount;
    m_fromAmount = m_toAmount;
    m_toAmount = tmp;
  }
}

void MyMoneyTransactionFilter::addPayee(const TQString& id)
{
  if(!m_payees.isEmpty() && !id.isEmpty()) {
    if(m_payees.find(id.utf8()) != 0)
      return;
  }
  if(m_payees.count() >= m_payees.size()*2) {
    m_payees.resize(457);
  }
  m_filterSet.singleFilter.payeeFilter = 1;
  if(!id.isEmpty())
    m_payees.insert(id.utf8(), "");
}

void MyMoneyTransactionFilter::addType(const int type)
{
  if(!m_types.isEmpty()) {
    if(m_types.find(type) != 0)
      return;
  }
  // we don't have more than 4 or 5 types, so we don't worry about
  // the size of the TQIntDict object.
  m_filterSet.singleFilter.typeFilter = 1;
  m_types.insert(type, "");
}

void MyMoneyTransactionFilter::addState(const int state)
{
  if(!m_states.isEmpty()) {
    if(m_states.find(state) != 0)
      return;
  }
  // we don't have more than 4 or 5 states, so we don't worry about
  // the size of the TQIntDict object.
  m_filterSet.singleFilter.stateFilter = 1;
  m_states.insert(state, "");
}

void MyMoneyTransactionFilter::addValidity(const int type)
{
  if(!m_validity.isEmpty()) {
    if(m_validity.find(type) != 0)
      return;
  }
  // we don't have more than 4 or 5 states, so we don't worry about
  // the size of the TQIntDict object.
  m_filterSet.singleFilter.validityFilter = 1;
  m_validity.insert(type, "");
}

void MyMoneyTransactionFilter::setNumberFilter(const TQString& from, const TQString& to)
{
  m_filterSet.singleFilter.nrFilter = 1;
  m_fromNr = from;
  m_toNr = to;
}

void MyMoneyTransactionFilter::setReportAllSplits(const bool report)
{
  m_reportAllSplits = report;
}

void MyMoneyTransactionFilter::setConsiderCategory(const bool check)
{
  m_considerCategory = check;
}

const TQValueList<MyMoneySplit>& MyMoneyTransactionFilter::matchingSplits(void) const
{
  return m_matchingSplits;
}

bool MyMoneyTransactionFilter::matchText(const MyMoneySplit * const sp) const
{
  // check if the text is contained in one of the fields
  // memo, value, number, payee, account, date
  if(m_filterSet.singleFilter.textFilter) {
    MyMoneyFile* file = MyMoneyFile::instance();
    const MyMoneyAccount& acc = file->account(sp->accountId());
    const MyMoneySecurity& sec = file->security(acc.currencyId());
    if(sp->memo().contains(m_text)
    || sp->shares().formatMoney(acc.fraction(sec)).contains(m_text)
    || sp->value().formatMoney(acc.fraction(sec)).contains(m_text)
    || sp->number().contains(m_text))
      return !m_invertText;

    if(acc.name().contains(m_text))
      return !m_invertText;

    if(!sp->payeeId().isEmpty()) {
      const MyMoneyPayee& payee = file->payee(sp->payeeId());
      if(payee.name().contains(m_text))
        return !m_invertText;
    }
    return m_invertText;
  }
  return true;
}

bool MyMoneyTransactionFilter::matchAmount(const MyMoneySplit * const sp) const
{
  if(m_filterSet.singleFilter.amountFilter) {
    if(((sp->value().abs() < m_fromAmount) || sp->value().abs() > m_toAmount)
    && ((sp->shares().abs() < m_fromAmount) || sp->shares().abs() > m_toAmount))
      return false;
  }

  return true;
}

bool MyMoneyTransactionFilter::match(const MyMoneySplit * const sp) const
{
  return matchText(sp) && matchAmount(sp);
}

bool MyMoneyTransactionFilter::match(const MyMoneyTransaction& transaction)
{
  MyMoneyFile* file = MyMoneyFile::instance();
  TQValueList<MyMoneySplit>::ConstIterator it;

  m_matchingSplits.clear();

  // tqDebug("T: %s", transaction.id().data());
  // if no filter is set, we can savely return a match
  // if we should report all splits, then we collect them
  if(!m_filterSet.allFilter) {
    if(m_reportAllSplits) {
      m_matchingSplits = transaction.splits();
    }
    return true;
  }

  // perform checks on the MyMoneyTransaction object first

  // check the date range
  if(m_filterSet.singleFilter.dateFilter) {
    if(m_fromDate != TQDate()) {
      if(transaction.postDate() < m_fromDate)
        return false;
    }

    if(m_toDate != TQDate()) {
      if(transaction.postDate() > m_toDate)
        return false;
    }
  }

  // construct a local list of pointers to all splits and
  // remove the ones that do not match account and/or categories.

  TQPtrList<MyMoneySplit> matchingSplits;
  for(it = transaction.splits().begin(); it != transaction.splits().end(); ++it) {
    matchingSplits.append(&(*it));
  }

  bool categoryMatched = !m_filterSet.singleFilter.categoryFilter;
  bool accountMatched = !m_filterSet.singleFilter.accountFilter;
  bool isTransfer = true;

  // check the transaction's validity
  if(m_filterSet.singleFilter.validityFilter) {
    if(m_validity.count() > 0) {
      if(!m_validity.find(validTransaction(transaction)))
        return false;
    }
  }

  MyMoneySplit* sp;

  if(m_filterSet.singleFilter.accountFilter == 1
  || m_filterSet.singleFilter.categoryFilter == 1) {
    for(sp = matchingSplits.first(); sp != 0; ) {
      MyMoneySplit* removeSplit = sp;
      const MyMoneyAccount& acc = file->account(sp->accountId());
      if(m_considerCategory) {
        switch(acc.accountGroup()) {
          case MyMoneyAccount::Income:
          case MyMoneyAccount::Expense:
            isTransfer = false;
            // check if the split references one of the categories in the list
            if(m_filterSet.singleFilter.categoryFilter) {
              if(m_categories.count() > 0) {
                if(m_categories.find(sp->accountId().utf8())) {
                  categoryMatched = true;
                  removeSplit = 0;
                }
              } else {
                // we're looking for transactions with 'no' categories
                return false;
              }
            }
            break;

          default:
            // check if the split references one of the accounts in the list
            if(m_filterSet.singleFilter.accountFilter) {
              if(m_accounts.count() > 0) {
                if(m_accounts.find(sp->accountId().utf8())) {
                  accountMatched = true;
                  removeSplit = 0;
                }
              }
            } else
              removeSplit = 0;

            break;
        }

      } else {
        if(m_filterSet.singleFilter.accountFilter) {
          if(m_accounts.count() > 0) {
            if(m_accounts.find(sp->accountId().utf8())) {
              accountMatched = true;
              removeSplit = 0;
            }
          }
        } else
          removeSplit = 0;
      }

      sp = matchingSplits.next();
      if(removeSplit) {
        // tqDebug(" S: %s", (*it).id().data());
        matchingSplits.remove(removeSplit);
      }
    }
  }

  // check if we're looking for transactions without assigned category
  if(!categoryMatched && transaction.splitCount() == 1 && m_categories.count() == 0) {
    categoryMatched = true;
  }

  // if there's no category filter and the category did not
  // match, then we still want to see this transaction if it's
  // a transfer
  if(!categoryMatched && !m_filterSet.singleFilter.categoryFilter)
    categoryMatched = isTransfer;

  if(matchingSplits.count() == 0
  || !(accountMatched && categoryMatched))
    return false;

  FilterSet filterSet = m_filterSet;
  filterSet.singleFilter.dateFilter =
  filterSet.singleFilter.accountFilter =
  filterSet.singleFilter.categoryFilter = 0;

  // check if we still have something to do
  if(filterSet.allFilter != 0) {
    for(sp = matchingSplits.first(); sp != 0;) {
      MyMoneySplit* removeSplit = 0;
      removeSplit = (matchAmount(sp) && matchText(sp)) ? 0 : sp;

      const MyMoneyAccount& acc = file->account(sp->accountId());

      // Determine if this account is a category or an account
      bool isCategory = false;
      switch(acc.accountGroup()) {
        case MyMoneyAccount::Income:
        case MyMoneyAccount::Expense:
          isCategory = true;
        default:
          break;
      }

      if(!isCategory && !removeSplit) {
        // check the payee list
        if(!removeSplit && m_filterSet.singleFilter.payeeFilter) {
          if(m_payees.count() > 0) {
            if(sp->payeeId().isEmpty() || !m_payees.find(sp->payeeId().utf8()))
              removeSplit = sp;
          } else if(!sp->payeeId().isEmpty())
              removeSplit = sp;
        }

        // check the type list
        if(!removeSplit && m_filterSet.singleFilter.typeFilter) {
          if(m_types.count() > 0) {
            if(!m_types.find(splitType(transaction, *sp)))
              removeSplit = sp;
          }
        }

        // check the state list
        if(!removeSplit && m_filterSet.singleFilter.stateFilter) {
          if(m_states.count() > 0) {
            if(!m_states.find(splitState(*sp)))
              removeSplit = sp;
          }
        }

        if(!removeSplit && m_filterSet.singleFilter.nrFilter) {
          if(!m_fromNr.isEmpty()) {
            if(sp->number() < m_fromNr)
              removeSplit = sp;
          }
          if(!m_toNr.isEmpty()) {
            if(sp->number() > m_toNr)
              removeSplit = sp;
          }
        }
      } else if(m_filterSet.singleFilter.payeeFilter
      || m_filterSet.singleFilter.typeFilter
      || m_filterSet.singleFilter.stateFilter
      || m_filterSet.singleFilter.nrFilter)
        removeSplit = sp;

      sp = matchingSplits.next();
      if(removeSplit) {
        // tqDebug(" S: %s", (*it).id().data());
        matchingSplits.remove(removeSplit);
      }
    }
  }

  if(m_reportAllSplits == false && matchingSplits.count() != 0) {
    m_matchingSplits.append(transaction.splits()[0]);
  } else {
    for(sp = matchingSplits.first(); sp != 0; sp = matchingSplits.next()) {
      m_matchingSplits.append(*sp);
    }
  }
  // all filters passed, I guess we have a match
  // tqDebug("  C: %d", m_matchingSplits.count());
  return matchingSplits.count() != 0;
}

int MyMoneyTransactionFilter::splitState(const MyMoneySplit& split) const
{
  int rc = notReconciled;

  switch(split.reconcileFlag()) {
    default:
    case MyMoneySplit::NotReconciled:
      break;;

    case MyMoneySplit::Cleared:
      rc = cleared;
      break;

    case MyMoneySplit::Reconciled:
      rc = reconciled;
      break;

    case MyMoneySplit::Frozen:
      rc = frozen;
      break;
  }
  return rc;
}

int MyMoneyTransactionFilter::splitType(const MyMoneyTransaction& t, const MyMoneySplit& split) const
{
  MyMoneyFile* file = MyMoneyFile::instance();
  MyMoneyAccount a, b;
  a = file->account(split.accountId());
  if((a.accountGroup() == MyMoneyAccount::Income
  || a.accountGroup() == MyMoneyAccount::Expense))
    return allTypes;

  if(t.splitCount() == 2) {
    TQString ida, idb;
    ida = t.splits()[0].accountId();
    idb = t.splits()[1].accountId();

    a = file->account(ida);
    b = file->account(idb);
    if((a.accountGroup() != MyMoneyAccount::Expense
    && a.accountGroup() != MyMoneyAccount::Income)
    && (b.accountGroup() != MyMoneyAccount::Expense
    && b.accountGroup() != MyMoneyAccount::Income))
      return transfers;
  }

  if(split.value().isPositive())
    return deposits;

  return payments;
}

MyMoneyTransactionFilter::validityOptionE MyMoneyTransactionFilter::validTransaction(const MyMoneyTransaction& t) const
{
  TQValueList<MyMoneySplit>::ConstIterator it_s;
  MyMoneyMoney val;

  for(it_s = t.splits().begin(); it_s != t.splits().end(); ++it_s) {
    val += (*it_s).value();
  }
  return (val == MyMoneyMoney(0,1)) ? valid : invalid;
}

bool MyMoneyTransactionFilter::includesCategory( const TQString& cat ) const
{
  return (! m_filterSet.singleFilter.categoryFilter) || m_categories.find( cat.utf8() );
}

bool MyMoneyTransactionFilter::includesAccount( const TQString& acc ) const
{
  return (! m_filterSet.singleFilter.accountFilter) || m_accounts.find( acc.utf8() );
}

bool MyMoneyTransactionFilter::includesPayee( const TQString& pye ) const
{
  return (! m_filterSet.singleFilter.payeeFilter) || m_payees.find( pye.utf8() );
}

bool MyMoneyTransactionFilter::dateFilter( TQDate& from, TQDate& to ) const
{
  from = m_fromDate;
  to = m_toDate;
  return m_filterSet.singleFilter.dateFilter==1;
}

bool MyMoneyTransactionFilter::amountFilter( MyMoneyMoney& from, MyMoneyMoney& to ) const
{
  from = m_fromAmount;
  to = m_toAmount;
  return m_filterSet.singleFilter.amountFilter==1;
}

bool MyMoneyTransactionFilter::numberFilter( TQString& from, TQString& to ) const
{
  from = m_fromNr;
  to = m_toNr;
  return m_filterSet.singleFilter.nrFilter==1;
}

bool MyMoneyTransactionFilter::payees(TQStringList& list) const
{
  bool result = m_filterSet.singleFilter.payeeFilter;

  if ( result )
  {
    TQAsciiDictIterator<char> it_payee( m_payees );
    while ( it_payee.current() )
    {
      list += it_payee.currentKey();
      ++it_payee;
    }
  }
  return result;
}

bool MyMoneyTransactionFilter::accounts(TQStringList& list) const
{
  bool result = m_filterSet.singleFilter.accountFilter;

  if ( result )
  {
    TQAsciiDictIterator<char> it_account( m_accounts );
    while ( it_account.current() )
    {
      TQString account = it_account.currentKey();
      list += account;
      ++it_account;
    }
  }
  return result;
}

bool MyMoneyTransactionFilter::categories(TQStringList& list) const
{
  bool result = m_filterSet.singleFilter.categoryFilter;

  if ( result )
  {
    TQAsciiDictIterator<char> it_category( m_categories );
    while ( it_category.current() )
    {
      list += it_category.currentKey();
      ++it_category;
    }
  }
  return result;
}

bool MyMoneyTransactionFilter::types(TQValueList<int>& list) const
{
  bool result = m_filterSet.singleFilter.typeFilter;

  if ( result )
  {
    TQIntDictIterator<char> it_type( m_types );
    while ( it_type.current() )
    {
      list += it_type.currentKey();
      ++it_type;
    }
  }
  return result;
}

bool MyMoneyTransactionFilter::states(TQValueList<int>& list) const
{
  bool result = m_filterSet.singleFilter.stateFilter;

  if ( result )
  {
    TQIntDictIterator<char> it_state( m_states );
    while ( it_state.current() )
    {
      list += it_state.currentKey();
      ++it_state;
    }
  }
  return result;
}

bool MyMoneyTransactionFilter::firstType(int&i) const
{
  bool result = m_filterSet.singleFilter.typeFilter;

  if ( result )
  {
    TQIntDictIterator<char> it_type( m_types );
    if ( it_type.current() )
      i = it_type.currentKey();
  }
  return result;
}

bool MyMoneyTransactionFilter::firstState(int&i) const
{
  bool result = m_filterSet.singleFilter.stateFilter;

  if ( result )
  {
    TQIntDictIterator<char> it_state( m_states );
    if ( it_state.current() )
      i = it_state.currentKey();
  }
  return result;
}

bool MyMoneyTransactionFilter::textFilter(TQRegExp& exp) const
{
  exp = m_text;
  return m_filterSet.singleFilter.textFilter == 1;
}

void MyMoneyTransactionFilter::setDateFilter(dateOptionE range)
{
  TQDate from, to;
  if ( translateDateRange(range,from,to) )
    setDateFilter(from,to);
}

static int fiscalYearStartMonth = 1;
static int fiscalYearStartDay = 1;

void MyMoneyTransactionFilter::setFiscalYearStart(int firstMonth, int firstDay)
{
  fiscalYearStartMonth = firstMonth;
  fiscalYearStartDay = firstDay;
}

bool MyMoneyTransactionFilter::translateDateRange(dateOptionE id, TQDate& start, TQDate& end)
{
  bool rc = true;
  int yr, mon, day;
  yr = TQDate::currentDate().year();
  mon = TQDate::currentDate().month();
  day = TQDate::currentDate().day();
  TQDate tmp;

  switch(id) {
    case MyMoneyTransactionFilter::allDates:
      start = TQDate();
      end = TQDate();
      break;
    case MyMoneyTransactionFilter::asOfToday:
      start = TQDate();
      end =  TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::currentMonth:
      start = TQDate(yr,mon,1);
      end = TQDate(yr,mon,1).addMonths(1).addDays(-1);
      break;
    case MyMoneyTransactionFilter::currentYear:
      start = TQDate(yr,1,1);
      end = TQDate(yr,12,31);
      break;
    case MyMoneyTransactionFilter::monthToDate:
      start = TQDate(yr,mon,1);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::yearToDate:
      start = TQDate(yr,1,1);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::yearToMonth:
      start = TQDate(yr,1,1);
      end = TQDate(yr,mon,1).addDays(-1);
      break;
    case MyMoneyTransactionFilter::lastMonth:
      start = TQDate(yr,mon,1).addMonths(-1);
      end = TQDate(yr,mon,1).addDays(-1);
      break;
    case MyMoneyTransactionFilter::lastYear:
      start = TQDate(yr,1,1).addYears(-1);
      end = TQDate(yr,12,31).addYears(-1);
      break;
    case MyMoneyTransactionFilter::last7Days:
      start = TQDate::currentDate().addDays(-7);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::last30Days:
      start = TQDate::currentDate().addDays(-30);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::last3Months:
      start = TQDate::currentDate().addMonths(-3);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::last6Months:
      start = TQDate::currentDate().addMonths(-6);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::last11Months:
      start = TQDate(yr,mon,1).addMonths(-12);
      end = TQDate(yr,mon,1).addDays(-1);
      break;
    case MyMoneyTransactionFilter::last12Months:
      start = TQDate::currentDate().addMonths(-12);
      end = TQDate::currentDate();
      break;
    case MyMoneyTransactionFilter::next7Days:
      start = TQDate::currentDate();
      end = TQDate::currentDate().addDays(7);
      break;
    case MyMoneyTransactionFilter::next30Days:
      start = TQDate::currentDate();
      end = TQDate::currentDate().addDays(30);
      break;
    case MyMoneyTransactionFilter::next3Months:
      start = TQDate::currentDate();
      end = TQDate::currentDate().addMonths(3);
      break;
    case MyMoneyTransactionFilter::next6Months:
      start = TQDate::currentDate();
      end = TQDate::currentDate().addMonths(6);
      break;
    case MyMoneyTransactionFilter::next12Months:
      start = TQDate::currentDate();
      end = TQDate::currentDate().addMonths(12);
      break;
    case MyMoneyTransactionFilter::userDefined:
      start = TQDate();
      end = TQDate();
      break;
    case MyMoneyTransactionFilter::last3ToNext3Months:
      start = TQDate::currentDate().addMonths(-3);
      end = TQDate::currentDate().addMonths(3);
      break;
    case MyMoneyTransactionFilter::currentQuarter:
      start = TQDate(yr, mon - ((mon-1) % 3), 1);
      end = start.addMonths(3).addDays(-1);
      break;
    case MyMoneyTransactionFilter::lastQuarter:
      start = TQDate(yr, mon - ((mon-1) % 3), 1).addMonths(-3);
      end = start.addMonths(3).addDays(-1);
      break;
    case MyMoneyTransactionFilter::nextQuarter:
      start = TQDate(yr, mon - ((mon-1) % 3), 1).addMonths(3);
      end = start.addMonths(3).addDays(-1);
      break;
    case MyMoneyTransactionFilter::currentFiscalYear:
      start = TQDate(TQDate::currentDate().year(), fiscalYearStartMonth, fiscalYearStartDay);
      if(TQDate::currentDate() < start)
        start = start.addYears(-1);
      end = start.addYears(1).addDays(-1);
      break;
    case MyMoneyTransactionFilter::lastFiscalYear:
      start = TQDate(TQDate::currentDate().year(), fiscalYearStartMonth, fiscalYearStartDay);
      if(TQDate::currentDate() < start)
       start = start.addYears(-1);
      start = start.addYears(-1);
      end = start.addYears(1).addDays(-1);
      break;
    case MyMoneyTransactionFilter::today:
      start = TQDate::currentDate();
      end =  TQDate::currentDate();
      break;
    default:
      tqFatal("Unknown date identifier %d in MyMoneyTransactionFilter::translateDateRange()", id);
      rc = false;
      break;
  }
  return rc;
}

void MyMoneyTransactionFilter::removeReference(const TQString& id)
{
  if(m_accounts.find(id.utf8())) {
    tqDebug(TQString("Remove account '%1' from report").arg(id));
    m_accounts.remove(id.utf8());
  } else if(m_categories.find(id.utf8())) {
    tqDebug(TQString("Remove category '%1' from report").arg(id));
    m_categories.remove(id.utf8());
  } else if(m_payees.find(id.utf8())) {
    tqDebug(TQString("Remove payee '%1' from report").arg(id));
    m_payees.remove(id.utf8());
  }
}
