/***************************************************************************
                          pivottable.h
                             -------------------
    begin                : Sat May 22 2004
    copyright            : (C) 2004-2005 by Ace Jones
    email                : <ace.j@hotpop.com>
                           Thomas Baumgart <ipwizard@users.sourceforge.net>
                           Alvaro Soliverez <asoliverez@gmail.com>
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/

#ifndef PIVOTTABLE_H
#define PIVOTTABLE_H

// ----------------------------------------------------------------------------
// QT Includes
#include <tqmap.h>
#include <tqvaluelist.h>

// ----------------------------------------------------------------------------
// KDE Includes

// ----------------------------------------------------------------------------
// Project Includes
#include "kreportchartview.h"
#include "../mymoney/mymoneyfile.h"
#include "../mymoney/mymoneyreport.h"
#include "reporttable.h"
#include "pivotgrid.h"
#include "reportaccount.h"

namespace reports {

/**
  * Calculates a 'pivot table' of information about the transaction database.
  * Based on pivot tables in MS Excel, and implemented as 'Data Pilot' in
  * OpenOffice.Org Calc.
  *
  *              | Month,etc
  * -------------+------------
  * Expense Type | Sum(Value)
  *   Category   |
  *
  * This is a middle-layer class, between the UI and the engine.  The
  * MyMoneyReport class holds only the CONFIGURATION parameters.  This
  * class actually does the work of retrieving the data from the engine
  * and formatting it for the user.
  *
  * @author Ace Jones
  *
  * @short
**/
class PivotTable : public ReportTable
{
public:
  /**
    * Create a Pivot table style report
    *
    * @param _config_f The configuration parameters for this report
    */
    PivotTable( const MyMoneyReport& _config_f );

  /**
    * virtual Destructur
    */
    virtual ~PivotTable() {}

  /**
    * Render the report to an HTML stream.
    *
    * @return TQString HTML string representing the report
    */
    TQString renderHTML( void ) const;
  /**
    * Render the report to a comma-separated-values stream.
    *
    * @return TQString CSV string representing the report
    */
    TQString renderCSV( void ) const;

  /**
    * Render the report to a graphical chart
    *
    * @param view The KReportChartView into which to draw the chart.
    */
    void drawChart( KReportChartView& view ) const;

  /**
    * Dump the report's HTML to a file
    *
    * @param file The filename to dump into
    * @param context unused, but provided for interface compatibility
    */
    void dump( const TQString& file, const TQString& context=TQString()) const;

  /**
    * Returns the grid generated by the report
    *
    */
    PivotGrid grid(void) {return m_grid;}

protected:
  void init(void);    // used for debugging the constructor

private:

    PivotGrid m_grid;

    TQStringList m_columnHeadings;
    unsigned m_numColumns;
    TQDate m_beginDate;
    TQDate m_endDate;
    bool m_runningSumsCalculated;

    /**
      * For budget-vs-actual reports only, maps each account to the account which holds
      * the budget for it.  If an account is not contained in this map, it is not included
      * in the budget.
      */
    TQMap<TQString, TQString> m_budgetMap;

    /**
      * This list contains the types of PivotGridRows that are going to be shown in the report
      */
    TQValueList<ERowType> m_rowTypeList;

    /**
     * This list contains the i18n headers for the column types
     */
    TQValueList<TQString> m_columnTypeHeaderList;

    MyMoneyReport m_config_f;

    /**
      * This method returns the formatted value of @a amount with
      * a possible @a currencySymbol added and @a prec fractional digits.
      * @a currencySymbol defaults to be empty and @a prec defaults to 2.
      *
      * If @a amount is negative the formatted value is enclosed in an
      * HTML font tag to modify the color to reflect the user settings for
      * negtive numbers.
      *
      * Example: 1.23 is returned as '1.23' whereas -1.23 is returned as
      *          @verbatim <font color="rgb($red,$green,$blue)">-1.23</font>@endverbatim
      *          with $red, $green and $blue being the actual value for the
      *          chosen color.
      */
    TQString coloredAmount(const MyMoneyMoney& amount, const TQString& currencySymbol = TQString(), int prec = 2 ) const;

protected:
  /**
    * Creates a row in the grid if it doesn't already exist
    *
    * Downsteam assignment functions will assume that this row already
    * exists, so this function creates a row of the needed length populated
    * with zeros.
    *
    * @param outergroup The outer row group
    * @param row The row itself
    * @param recursive Whether to also recursively create rows for our parent accounts
    */
    void createRow( const TQString& outergroup, const ReportAccount& row, bool recursive );

  /**
    * Assigns a value into the grid
    *
    * Adds the given value to the value which already exists at the specified grid position
    *
    * @param outergroup The outer row group
    * @param row The row itself
    * @param column The column
    * @param value The value to be added in
    * @param budget Whether this is a budget value (@p true) or an actual
    *               value (@p false). Defaults to @p false.
    * @param stockSplit Wheter this is a stock split (@p true) or an actual
    *                   value (@p false). Defaults to @p false.
    */
    inline void assignCell( const TQString& outergroup, const ReportAccount& row, unsigned column, MyMoneyMoney value, bool budget = false, bool stockSplit = false );

  /**
    * Create a row for each included account. This is used when
    * the config parameter isIncludingUnusedAccount() is true
    */
    void createAccountRows(void);

  /**
    * Record the opening balances of all qualifying accounts into the grid.
    *
    * For accounts opened before the report period, places the balance into the '0' column.
    * For those opened during the report period, places the balance into the appropriate column
    * for the month when it was opened.
    */
    void calculateOpeningBalances( void );

  /**
    * Calculate budget mapping
    *
    * For budget-vs-actual reports, this creates a mapping between each account
    * in the user's hierarchy and the account where the budget is held for it.
    * This is needed because the user can budget on a given account for that
    * account and all its descendants.  Also if NO budget is placed on the
    * account or any of its parents, the account is not included in the map.
    */
    void calculateBudgetMapping( void );

  /**
    * Calculate the running sums.
    *
    * After calling this method, each cell of the report will contain the running sum of all
    * the cells in its row in this and earlier columns.
    *
    * For example, consider a row with these values:
    *   01 02 03 04 05 06 07 08 09 10
    *
    * After calling this function, the row will look like this:
    *   01 03 06 10 15 21 28 36 45 55
    */
    void calculateRunningSums( void );
    void calculateRunningSums( PivotInnerGroup::iterator& it_row);

   /**
     * This method calculates the difference between a @a budgeted and an @a
     * actual amount. The calculation is based on the type of the
      * @a repAccount. The difference value is calculated as follows:
     *
     * If @a repAccount is of type MyMoneyAccount::Income
     *
     * @code
     *      diff = actual - budgeted
     * @endcode
     *
     * If @a repAccount is of type MyMoneyAccount::Expense
     *
     * @code
     *      diff = budgeted - actual
     * @endcode
     *
     * In all other cases, 0 is returned.
     */
    void calculateBudgetDiff(void);

  /**
    * This method calculates forecast for a report
    */
    void calculateForecast(void);

    /**
     * This method inserts units to be used to display prices
     */
    void fillBasePriceUnit(ERowType rowType);

  /**
    * This method calculates moving average for a report
    */
    void calculateMovingAverage(void);

  /**
    * Calculate the row and column totals
    *
    * This function will set the m_total members of all the TGrid objects.  Be sure the values are
    * all converted to the base currency first!!
    *
    */
    void calculateTotals( void );

  /**
    * Convert each value in the grid to the base currency
    *
    */
    void convertToBaseCurrency( void );

  /**
    * Convert each value in the grid to the account/category's deep currency
    *
    * See AccountDescriptor::deepCurrencyPrice() for a description of 'deep' currency
    *
    */
    void convertToDeepCurrency( void );

  /**
    * Turn month-long columns into larger time periods if needed
    *
    * For example, consider a row with these values:
    *   01 02 03 04 05 06 07 08 09 10
    *
    * If the column pitch is 3 (i.e. quarterly), after calling this function,
    * the row will look like this:
    *   06 15 26 10
    */
    void collapseColumns(void);

  /**
    * Determine the proper column headings based on the time periods covered by each column
    *
    */
    void calculateColumnHeadings(void);

  /**
    * Helper methods for collapseColumns
    *
    */
    void accumulateColumn(unsigned destcolumn, unsigned sourcecolumn);
    void clearColumn(unsigned column);

  /**
    * Calculate the column of a given date.  This is the absolute column in a
    * hypothetical report that covers all of known time.  In reality an actual
    * report will be a subset of that.
    *
    * @param _date The date
    */
    unsigned columnValue(const TQDate& _date) const;

  /**
    * Calculate the date of the last day covered by a given column.
    *
    * @param column The column
    */
    TQDate columnDate(int column) const;

  /**
    * Returns the balance of a given cell. Throws an exception once calculateRunningSums() has been run.
    */
    MyMoneyMoney cellBalance(const TQString& outergroup, const ReportAccount& _row, unsigned column, bool budget);

   /**
     * Draws a PivotGridRowSet in a chart for the given ERowType
     */
    unsigned drawChartRowSet(unsigned rowNum, const bool seriesTotals, const bool accountSeries, KDChartTableData& data, const PivotGridRowSet& rowSet, const ERowType rowType ) const;

   /**
     * Loads m_rowTypeList with the list of PivotGridRow types that the reporttable
     * should show
     */
    void loadRowTypeList(void);

   /**
     * If not in expert mode, include all subaccounts for each selected
     * investment account
     */
    void includeInvestmentSubAccounts(void);
};


}
#endif
// PIVOTTABLE_H
// vim:cin:si:ai:et:ts=2:sw=2:
