/***************************************************************************
                          reportaccount.cpp
                             -------------------
    begin                : Mon May 17 2004
    copyright            : (C) 2004-2005 by Ace Jones
    email                : <ace.j@hotpop.com>
                           Thomas Baumgart <ipwizard@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.                                   *
 *                                                                         *
 ***************************************************************************/

// ----------------------------------------------------------------------------
// QT Includes

// ----------------------------------------------------------------------------
// KDE Includes
// This is just needed for i18n().  Once I figure out how to handle i18n
// without using this macro directly, I'll be freed of KDE dependency.  This
// is a minor problem because we use these terms when rendering to HTML,
// and a more major problem because we need it to translate account types
// (e.g. MyMoneyAccount::Checkings) into their text representation.  We also
// use that text representation in the core data structure of the report. (Ace)

#include <tdelocale.h>

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

#include "../mymoney/mymoneyfile.h"
#include "../mymoney/mymoneysecurity.h"
#include "reportdebug.h"
#include "reportaccount.h"

namespace reports {

ReportAccount::ReportAccount( void )
{
}

ReportAccount::ReportAccount( const ReportAccount& copy ):
  MyMoneyAccount( copy ), m_nameHierarchy( copy.m_nameHierarchy )
{
  // NOTE: I implemented the copy constructor solely for debugging reasons

  DEBUG_ENTER(__PRETTY_FUNCTION__);
}

ReportAccount::ReportAccount( const TQString& accountid ):
  MyMoneyAccount( MyMoneyFile::instance()->account(accountid) )
{
  DEBUG_ENTER(__PRETTY_FUNCTION__);
  DEBUG_OUTPUT(TQString("Account %1").arg(accountid));
  calculateAccountHierarchy();
}

ReportAccount::ReportAccount( const MyMoneyAccount& account ):
  MyMoneyAccount( account )
{
  DEBUG_ENTER(__PRETTY_FUNCTION__);
  DEBUG_OUTPUT(TQString("Account %1").arg(account.id()));
  calculateAccountHierarchy();
}

void ReportAccount::calculateAccountHierarchy( void )
{
  DEBUG_ENTER(__PRETTY_FUNCTION__);

  MyMoneyFile* file = MyMoneyFile::instance();
  TQString resultid = id();
  TQString parentid = parentAccountId();

#ifdef DEBUG_HIDE_SENSITIVE
  m_nameHierarchy.prepend(file->account(resultid).id());
#else
  m_nameHierarchy.prepend(file->account(resultid).name());
#endif
  while (!file->isStandardAccount(parentid))
  {
    // take on the identity of our parent
    resultid = parentid;

    // and try again
    parentid = file->account(resultid).parentAccountId();
#ifdef DEBUG_HIDE_SENSITIVE
    m_nameHierarchy.prepend(file->account(resultid).id());
#else
    m_nameHierarchy.prepend(file->account(resultid).name());
#endif
  }
}

MyMoneyMoney ReportAccount::deepCurrencyPrice( const TQDate& date ) const
{
  DEBUG_ENTER(__PRETTY_FUNCTION__);

  MyMoneyMoney result(1, 1);
  MyMoneyFile* file = MyMoneyFile::instance();

  MyMoneySecurity undersecurity = file->security( currencyId() );
  if ( ! undersecurity.isCurrency() )
  {
    MyMoneyPrice price = file->price(undersecurity.id(),undersecurity.tradingCurrency(),date);
    if ( price.isValid() )
    {
      result = price.rate(undersecurity.tradingCurrency());

      DEBUG_OUTPUT(TQString("Converting under %1 to deep %2, price on %3 is %4")
        .arg(undersecurity.name())
        .arg(file->security(undersecurity.tradingCurrency()).name())
        .arg(date.toString())
        .arg(result.toDouble()));
    }
    else
    {
      DEBUG_OUTPUT(TQString("No price to convert under %1 to deep %2 on %3")
        .arg(undersecurity.name())
        .arg(file->security(undersecurity.tradingCurrency()).name())
        .arg(date.toString()));
    }
  }

  return result;
}

MyMoneyMoney ReportAccount::baseCurrencyPrice( const TQDate& date ) const
{
  // Note that whether or not the user chooses to convert to base currency, all the values
  // for a given account/category are converted to the currency for THAT account/category
  // The "Convert to base currency" tells the report to convert from the account/category
  // currency to the file's base currency.
  //
  // An example where this matters is if Category 'C' and account 'U' are in USD, but
  // Account 'J' is in JPY.  Say there are two transactions, one is US$100 from U to C,
  // the other is JPY10,000 from J to C.  Given a JPY price of USD$0.01, this means
  // C will show a balance of $200 NO MATTER WHAT the user chooses for 'convert to base
  // currency.  This confused me for a while, which is why I wrote this comment.
  //    --acejones

  DEBUG_ENTER(__PRETTY_FUNCTION__);

  MyMoneyMoney result(1, 1);
  MyMoneyFile* file = MyMoneyFile::instance();

  if(isForeignCurrency())
  {
    result = foreignCurrencyPrice(file->baseCurrency().id(), date);
  }

  return result;
}

MyMoneyMoney ReportAccount::foreignCurrencyPrice( const TQString foreignCurrency, const TQDate& date ) const
{
  DEBUG_ENTER(__PRETTY_FUNCTION__);

  MyMoneyPrice price;
  MyMoneyMoney result(1, 1);
  MyMoneyFile* file = MyMoneyFile::instance();
  MyMoneySecurity security = file->security(foreignCurrency);

  //check whether it is a currency or a commodity. In the latter case case, get the trading currency
  TQString tradingCurrency;
  if(security.isCurrency()) {
    tradingCurrency = foreignCurrency;
  } else {
    tradingCurrency = security.tradingCurrency();
  }

  //It makes no sense to get the price if both currencies are the same
  if(currency().id() != tradingCurrency) {
    price = file->price(currency().id(), tradingCurrency, date);

    if(price.isValid())
    {
      result = price.rate(tradingCurrency);
      DEBUG_OUTPUT(TQString("Converting deep %1 to currency %2, price on %3 is %4")
          .arg(file->currency(currency().id()).name())
          .arg(file->currency(foreignCurrency).name())
          .arg(date.toString())
          .arg(result.toDouble()));
    }
    else
    {
      DEBUG_OUTPUT(TQString("No price to convert deep %1 to currency %2 on %3")
          .arg(file->currency(currency().id()).name())
          .arg(file->currency(foreignCurrency).name())
          .arg(date.toString()));
    }
  }
  return result;
}

/**
  * Fetch the trading currency of this account's currency
  *
  * @return The account's currency trading currency
  */
MyMoneySecurity ReportAccount::currency( void ) const
{
  MyMoneyFile* file = MyMoneyFile::instance();

  // First, get the deep currency
  MyMoneySecurity deepcurrency = file->security( currencyId() );
  if ( ! deepcurrency.isCurrency() )
    deepcurrency = file->security( deepcurrency.tradingCurrency() );

  // Return the deep currency's ID
  return deepcurrency;
}

/**
  * Determine if this account's deep currency is different from the file's
  * base currency
  *
  * @return bool True if this account is in a foreign currency
  */
bool ReportAccount::isForeignCurrency( void ) const
{
  return ( currency().id() != MyMoneyFile::instance()->baseCurrency().id() );
}

bool ReportAccount::operator<(const ReportAccount& second) const
{
//   DEBUG_ENTER(__PRETTY_FUNCTION__);

  bool result = false;
  bool haveresult = false;
  TQStringList::const_iterator it_first = m_nameHierarchy.begin();
  TQStringList::const_iterator it_second = second.m_nameHierarchy.begin();
  while ( it_first != m_nameHierarchy.end() )
  {
    // The first string is longer than the second, but otherwise identical
    if ( it_second == second.m_nameHierarchy.end() )
    {
      result = false;
      haveresult = true;
      break;
    }

    if ( (*it_first) < (*it_second) )
    {
      result = true;
      haveresult = true;
      break;
    }
    else if ( (*it_first) > (*it_second) )
    {
      result = false;
      haveresult = true;
      break;
    }

    ++it_first;
    ++it_second;
  }

  // The second string is longer than the first, but otherwise identical
  if ( !haveresult && ( it_second != second.m_nameHierarchy.end() ) )
    result = true;

//   DEBUG_OUTPUT(TQString("%1 < %2 is %3").arg(debugName(),second.debugName()).arg(result));
  return result;
}

/**
  * The name of only this account.  No matter how deep the hierarchy, this
  * method only returns the last name in the list, which is the engine name]
  * of this account.
  *
  * @return TQString The account's name
  */
TQString ReportAccount::name( void ) const
{
  return m_nameHierarchy.back();
}

// MyMoneyAccount:fullHierarchyDebug()
TQString ReportAccount::debugName( void ) const
{
  return m_nameHierarchy.join("|");
}

// MyMoneyAccount:fullHierarchy()
TQString ReportAccount::fullName( void ) const
{
  return m_nameHierarchy.join(": ");
}

// MyMoneyAccount:isTopCategory()
bool ReportAccount::isTopLevel( void ) const
{
  return ( m_nameHierarchy.size() == 1 );
}

// MyMoneyAccount:hierarchyDepth()
unsigned ReportAccount::hierarchyDepth( void ) const
{
  return ( m_nameHierarchy.size() );
}

ReportAccount ReportAccount::parent( void ) const
{
  return ReportAccount( parentAccountId() );
}

ReportAccount ReportAccount::topParent( void ) const
{
  DEBUG_ENTER(__PRETTY_FUNCTION__);

  MyMoneyFile* file = MyMoneyFile::instance();
  TQString resultid = id();
  TQString parentid = parentAccountId();

  while (!file->isStandardAccount(parentid))
  {
    // take on the identity of our parent
    resultid = parentid;

    // and try again
    parentid = file->account(resultid).parentAccountId();
  }

  return ReportAccount( resultid );
}

TQString ReportAccount::topParentName( void ) const
{
  return m_nameHierarchy.first();
}

bool ReportAccount::isLiquidAsset( void ) const
{
  return accountType() == MyMoneyAccount::Cash ||
      accountType() == MyMoneyAccount::Checkings ||
      accountType() == MyMoneyAccount::Savings;
}


bool ReportAccount::isLiquidLiability( void ) const
{
  return accountType() == MyMoneyAccount::CreditCard;

}




}  // end namespace reports