/***************************************************************************
                          kcurrencycalculator.cpp  -  description
                             -------------------
    begin                : Thu Apr 8 2004
    copyright            : (C) 2000-2004 by Michael Edwardes
    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.                                   *
 *                                                                         *
 ***************************************************************************/

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

#include <tqlabel.h>
#include <tqradiobutton.h>
#include <tqcheckbox.h>
#include <tqwidgetstack.h>
#include <tqgroupbox.h>

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

#include <klocale.h>
#include <kpushbutton.h>
#include <kcombobox.h>
#include <kstdguiitem.h>

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

#include "kcurrencycalculator.h"

#include <kmymoney/kmymoneyedit.h>
#include <kmymoney/kmymoneydateinput.h>
#include <kmymoney/kmymoneycurrencyselector.h>
#include <kmymoney/mymoneyprice.h>
#include <kmymoney/mymoneytransaction.h>
#include <kmymoney/kmymoneyglobalsettings.h>

#include "../kmymoneyutils.h"

bool KCurrencyCalculator::setupSplitPrice(MyMoneyMoney& shares, const MyMoneyTransaction& t, const MyMoneySplit& s, const TQMap<TQString, MyMoneyMoney>& priceInfo, TQWidget* parentWidget)
{
  bool rc = true;
  MyMoneyFile* file = MyMoneyFile::instance();

  if(!s.value().isZero()) {
    MyMoneyAccount cat = file->account(s.accountId());
    MyMoneySecurity toCurrency;
    toCurrency = file->security(cat.currencyId());
    // determine the fraction required for this category/account
    int fract = cat.fraction(toCurrency);

    if(cat.currencyId() != t.commodity()) {

      MyMoneySecurity fromCurrency;
      MyMoneyMoney fromValue, toValue;
      fromCurrency = file->security(t.commodity());
      // display only positive values to the user
      fromValue = s.value().abs();

      // if we had a price info in the beginning, we use it here
      if(priceInfo.find(cat.currencyId()) != priceInfo.end()) {
        toValue = (fromValue * priceInfo[cat.currencyId()]).convert(fract);
      }

      // if the shares are still 0, we need to change that
      if(toValue.isZero()) {
        MyMoneyPrice price = file->price(fromCurrency.id(), toCurrency.id());
        // if the price is valid calculate the shares. If it is invalid
        // assume a conversion rate of 1.0
        if(price.isValid()) {
          toValue = (price.rate(toCurrency.id()) * fromValue).convert(fract);
        } else {
          toValue = fromValue;
        }
      }

      // now present all that to the user
      KCurrencyCalculator calc(fromCurrency,
                              toCurrency,
                              fromValue,
                              toValue,
                              t.postDate(),
                              fract,
                              parentWidget, "currencyCalculator");

      if(calc.exec() == TQDialog::Rejected) {
        rc = false;
      } else
        shares = (s.value() * calc.price()).convert(fract);

    } else {
      shares = s.value().convert(fract);
    }
  } else
    shares = s.value();

  return rc;
}

KCurrencyCalculator::KCurrencyCalculator(const MyMoneySecurity& from, const MyMoneySecurity& to, const MyMoneyMoney& value, const MyMoneyMoney& shares, const TQDate& date, const signed64 resultFraction, TQWidget *parent, const char *name ) :
  KCurrencyCalculatorDecl(parent, name),
  m_fromCurrency(from),
  m_toCurrency(to),
  m_result(shares.abs()),
  m_value(value.abs()),
  m_resultFraction(resultFraction)
{
  MyMoneyFile* file = MyMoneyFile::instance();

  m_dateFrame->hide();
  if(date.isValid())
    m_dateEdit->setDate(date);
  else
    m_dateEdit->setDate(TQDate::currentDate());

  m_fromCurrencyText->setText(m_fromCurrency.isCurrency() ? m_fromCurrency.id() : m_fromCurrency.tradingSymbol());
  m_toCurrencyText->setText(m_toCurrency.isCurrency() ? m_toCurrency.id() : m_toCurrency.tradingSymbol());

  m_fromAmount->setText(m_value.formatMoney("", MyMoneyMoney::denomToPrec(m_fromCurrency.smallestAccountFraction())));

  m_dateText->setText(TDEGlobal::locale()->formatDate(date, true));

  m_fromType->setText(KMyMoneyUtils::securityTypeToString(m_fromCurrency.securityType()));
  m_toType->setText(KMyMoneyUtils::securityTypeToString(m_toCurrency.securityType()));

  // load button icons
  m_cancelButton->setGuiItem(KStdGuiItem::cancel());
  m_okButton->setGuiItem(KStdGuiItem::ok());

  m_updateButton->setChecked(KMyMoneyGlobalSettings::priceHistoryUpdate());

  // setup initial result
  if(m_result == MyMoneyMoney() && !m_value.isZero()) {
    MyMoneyPrice pr = file->price(m_fromCurrency.id(), m_toCurrency.id(), date);
    if(pr.isValid()) {
      m_result = m_value * pr.rate(m_fromCurrency.id());
    }
  }

  // fill in initial values
  m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
  m_toAmount->setPrecision(MyMoneyMoney::denomToPrec(m_resultFraction));

  m_conversionRate->setPrecision(KMyMoneyGlobalSettings::pricePrecision());

  connect(m_amountButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSetToAmount()));
  connect(m_rateButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(slotSetExchangeRate()));

  connect(m_toAmount, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateResult(const TQString&)));
  connect(m_conversionRate, TQT_SIGNAL(valueChanged(const TQString&)), this, TQT_SLOT(slotUpdateRate(const TQString&)));
  connect(m_cancelButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(reject()));
  connect(m_okButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(accept()));

  // use this as the default
  m_amountButton->animateClick();
  slotUpdateResult(m_toAmount->text());

  // If the from security is not a currency, we only allow entering a price
  if(!m_fromCurrency.isCurrency()) {
    m_rateButton->animateClick();
    m_amountButton->hide();
    m_toAmount->hide();
  }
  m_okButton->setFocus();
}

KCurrencyCalculator::~KCurrencyCalculator()
{
}

void KCurrencyCalculator::setupPriceEditor(void)
{
  m_dateFrame->show();
  m_amountDateFrame->hide();
  m_updateButton->setChecked(true);
  m_updateButton->hide();
}

void KCurrencyCalculator::slotSetToAmount(void)
{
  m_rateButton->setChecked(false);
  m_toAmount->setEnabled(true);
  m_conversionRate->setEnabled(false);
}

void KCurrencyCalculator::slotSetExchangeRate(void)
{
  m_amountButton->setChecked(false);
  m_toAmount->setEnabled(false);
  m_conversionRate->setEnabled(true);
}

void KCurrencyCalculator::slotUpdateResult(const TQString& /*txt*/)
{
  MyMoneyMoney result = m_toAmount->value();
  MyMoneyMoney price(0, 1);

  if(result.isNegative()) {
    m_toAmount->setValue(-result);
    slotUpdateResult(TQString());
    return;
  }

  if(!result.isZero()) {
    price = result / m_value;

    m_conversionRate->loadText(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
    m_result = (m_value * price).convert(m_resultFraction);
    m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
  }
  updateExample(price);
}

void KCurrencyCalculator::slotUpdateRate(const TQString& /*txt*/)
{
  MyMoneyMoney price = m_conversionRate->value();

  if(price.isNegative()) {
    m_conversionRate->setValue(-price);
    slotUpdateRate(TQString());
    return;
  }

  if(!price.isZero()) {
    m_conversionRate->loadText(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()));
    m_result = (m_value * price).convert(m_resultFraction);
    m_toAmount->loadText(m_result.formatMoney("", MyMoneyMoney::denomToPrec(m_resultFraction)));
  }
  updateExample(price);
}

void KCurrencyCalculator::updateExample(const MyMoneyMoney& price)
{
  TQString msg;
  if(price.isZero()) {
    msg = TQString("1 %1 = ? %2").arg(m_fromCurrency.tradingSymbol())
                                .arg(m_toCurrency.tradingSymbol());
    if(m_fromCurrency.isCurrency()) {
      msg += TQString("\n");
      msg += TQString("1 %1 = ? %2").arg(m_toCurrency.tradingSymbol())
                                     .arg(m_fromCurrency.tradingSymbol());
    }
  } else {
    msg = TQString("1 %1 = %2 %3").arg(m_fromCurrency.tradingSymbol())
                                 .arg(price.formatMoney("", KMyMoneyGlobalSettings::pricePrecision()))
                                 .arg(m_toCurrency.tradingSymbol());
    if(m_fromCurrency.isCurrency()) {
      msg += TQString("\n");
      msg += TQString("1 %1 = %2 %3").arg(m_toCurrency.tradingSymbol())
                                    .arg((MyMoneyMoney(1,1)/price).formatMoney("", KMyMoneyGlobalSettings::pricePrecision()))
                                    .arg(m_fromCurrency.tradingSymbol());
    }
  }
  m_conversionExample->setText(msg);
  m_okButton->setEnabled(!price.isZero());
}

void KCurrencyCalculator::accept(void)
{
  if(m_conversionRate->isEnabled())
    slotUpdateRate(TQString());
  else
    slotUpdateResult(TQString());

  if(m_updateButton->isChecked()) {
    MyMoneyPrice pr = MyMoneyFile::instance()->price(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date());
    if(!pr.isValid()
    || pr.date() != m_dateEdit->date()
    || (pr.date() == m_dateEdit->date() && pr.rate(m_fromCurrency.id()) != price())) {
      pr = MyMoneyPrice(m_fromCurrency.id(), m_toCurrency.id(), m_dateEdit->date(), price(), i18n("User"));
      MyMoneyFileTransaction ft;
      try {
        MyMoneyFile::instance()->addPrice(pr);
        ft.commit();
      } catch(MyMoneyException *e) {
        tqDebug("Cannot add price");
        delete e;
      }
    }
  }

  // remember setting for next round
  KMyMoneyGlobalSettings::setPriceHistoryUpdate(m_updateButton->isChecked());

  KCurrencyCalculatorDecl::accept();
}

const MyMoneyMoney KCurrencyCalculator::price(void) const
{
  // This should fix https://bugs.kde.org/show_bug.cgi?id=205254 but
  // I am not sure about any side effects when dealing with multi-
  // currency transactions.
  //
  // The following line is the original version of this code
  // which causes some rounding issues (see the above bug entry)
  // return m_result / m_value;
  return m_conversionRate->value();
}


#include "kcurrencycalculator.moc"