/***************************************************************************
                          ksplittransactiondlg.cpp  -  description
                             -------------------
    begin                : Thu Jan 10 2002
    copyright            : (C) 2000-2002 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.                                   *
 *                                                                         *
 ***************************************************************************/

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

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

#include <tqpushbutton.h>
#include <tqlabel.h>
#include <tqtable.h>
#include <tqtimer.h>
#include <tqptrlist.h>
#include <tqbuttongroup.h>
#include <tqradiobutton.h>
#include <tqcursor.h>

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

#include <tdeglobal.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <tdemessagebox.h>
#include <kpushbutton.h>
#include <kactivelabel.h>
#include <kstdguiitem.h>
#include <tdeapplication.h>

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

#include "ksplittransactiondlg.h"
#include <kmymoney/kmymoneyedit.h>
#include <kmymoney/kmymoneylineedit.h>
#include <kmymoney/mymoneyfile.h>

#include "kmymoneysplittable.h"
#include "../dialogs/ksplitcorrectiondlg.h"

KSplitTransactionDlg::KSplitTransactionDlg(const MyMoneyTransaction& t,
                                           const MyMoneySplit& s,
                                           const MyMoneyAccount& acc,
                                           const bool amountValid,
                                           const bool deposit,
                                           const MyMoneyMoney& calculatedValue,
                                           const TQMap<TQString, MyMoneyMoney>& priceInfo,
                                           TQWidget* parent, const char* name) :
  KSplitTransactionDlgDecl(parent, name, true),
  m_account(acc),
  m_split(s),
  m_precision(2),
  m_amountValid(amountValid),
  m_isDeposit(deposit),
  m_calculatedValue(calculatedValue)
{
  // add icons to buttons
  TDEIconLoader *il = TDEGlobal::iconLoader();

  KGuiItem clearButtenItem( i18n( "Clear &All" ),
                    TQIconSet(il->loadIcon("edittrash", TDEIcon::Small, TDEIcon::SizeSmall)),
                    i18n("Clear all splits"),
                    i18n("Use this to clear all splits of this transaction"));
  clearAllBtn->setGuiItem(clearButtenItem);


  KGuiItem mergeButtenItem( i18n( "&Merge" ),
                             TQIconSet(il->loadIcon("math_sum", TDEIcon::Small, TDEIcon::SizeSmall)),
                                      "", "");
  mergeBtn->setGuiItem(mergeButtenItem);

  // make finish the default
  finishBtn->setDefault(true);

  // setup the focus
  cancelBtn->setFocusPolicy(TQWidget::NoFocus);
  finishBtn->setFocusPolicy(TQWidget::NoFocus);
  clearAllBtn->setFocusPolicy(TQWidget::NoFocus);

  // connect signals with slots
  connect(transactionsTable, TQ_SIGNAL(transactionChanged(const MyMoneyTransaction&)),
          this, TQ_SLOT(slotSetTransaction(const MyMoneyTransaction&)));
  connect(transactionsTable, TQ_SIGNAL(createCategory(const TQString&, TQString&)), this, TQ_SLOT(slotCreateCategory(const TQString&, TQString&)));
  connect(transactionsTable, TQ_SIGNAL(objectCreation(bool)), this, TQ_SIGNAL(objectCreation(bool)));

  connect(transactionsTable, TQ_SIGNAL(returnPressed()), this, TQ_SLOT(accept()));
  connect(transactionsTable, TQ_SIGNAL(escapePressed()), this, TQ_SLOT(reject()));

  connect(cancelBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(reject()));
  connect(finishBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(accept()));
  connect(clearAllBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotClearAllSplits()));
  connect(mergeBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotMergeSplits()));
  connect(clearZeroBtn, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotClearUnusedSplits()));

  // setup the precision
  try {
    MyMoneySecurity currency = MyMoneyFile::instance()->currency(t.commodity());
    m_precision = MyMoneyMoney::denomToPrec(m_account.fraction(currency));
  } catch(MyMoneyException *e) {
    delete e;
  }

  slotSetTransaction(t);

  // pass on those vars
  transactionsTable->setup(priceInfo);

  TQSize size(width(), height());
  kapp->config()->setGroup("SplitTransactionEditor");
  size = kapp->config()->readSizeEntry("Geometry", &size);
  size.setHeight(size.height()-1);
  TQDialog::resize( size.expandedTo(minimumSizeHint()) );

  // Trick: it seems, that the initial sizing of the dialog does
  // not work correctly. At least, the columns do not get displayed
  // correct. Reason: the return value of transactionsTable->visibleWidth()
  // is incorrect. If the widget is visible, resizing works correctly.
  // So, we let the dialog show up and resize it then. It's not really
  // clean, but the only way I got the damned thing working.
  TQTimer::singleShot( 10, this, TQ_SLOT(initSize()) );
}

KSplitTransactionDlg::~KSplitTransactionDlg()
{
  kapp->config()->setGroup("SplitTransactionEditor");
  kapp->config()->writeEntry("Geometry", size());
}

int KSplitTransactionDlg::exec(void)
{
  // for deposits, we invert the sign of all splits.
  // don't forget to revert when we're done ;-)
  if(m_isDeposit) {
    for(unsigned i = 0; i < m_transaction.splits().count(); ++i) {
      MyMoneySplit split = m_transaction.splits()[i];
      split.setValue(-split.value());
      split.setShares(-split.shares());
      m_transaction.modifySplit(split);
    }
  }

  int rc;
  do {
    transactionsTable->setFocus();

    // initialize the display
    transactionsTable->setTransaction(m_transaction, m_split, m_account);
    updateSums();

    rc = KSplitTransactionDlgDecl::exec();

    if(rc == TQDialog::Accepted) {
      if(!diffAmount().isZero()) {
        KSplitCorrectionDlgDecl* corrDlg = new KSplitCorrectionDlgDecl(this, 0, true);

        // add icons to buttons
        corrDlg->okBtn->setGuiItem(KStdGuiItem::ok());
        corrDlg->cancelBtn->setGuiItem(KStdGuiItem::cancel());

        MyMoneySplit split = m_transaction.splits()[0];
        TQString total = (-split.value()).formatMoney("", m_precision);
        TQString sums = splitsValue().formatMoney("", m_precision);
        TQString diff = diffAmount().formatMoney("", m_precision);

        // now modify the text items of the dialog to contain the correct values
        TQString q = i18n("The total amount of this transaction is %1 while "
                                "the sum of the splits is %2. The remaining %3 are "
                                "unassigned.")
                    .arg(total)
                    .arg(sums)
                    .arg(diff);
        corrDlg->explanation->setText(q);

        q = i18n("Change &total amount of transaction to %1.").arg(sums);
        corrDlg->changeBtn->setText(q);

        q = i18n("&Distribute difference of %1 among all splits.").arg(diff);
        corrDlg->distributeBtn->setText(q);
        // FIXME remove the following line once distribution among
        //       all splits is implemented
        corrDlg->distributeBtn->hide();


        // if we have only two splits left, we don't allow leaving sth. unassigned.
        if(m_transaction.splitCount() < 3) {
          q = i18n("&Leave total amount of transaction at %1.").arg(total);
        } else {
          q = i18n("&Leave %1 unassigned.").arg(diff);
        }
        corrDlg->leaveBtn->setText(q);

        if((rc = corrDlg->exec()) == TQDialog::Accepted) {
          TQButton* button = corrDlg->buttonGroup->selected();
          if(button != 0) {
            switch(corrDlg->buttonGroup->id(button)) {
              case 0:       // continue to edit
                rc = TQDialog::Rejected;
                break;

              case 1:       // modify total
                split.setValue(-splitsValue());
                split.setShares(-splitsValue());
                m_transaction.modifySplit(split);
                break;

              case 2:       // distribute difference
                tqDebug("distribution of difference not yet supported in KSplitTransactionDlg::slotFinishClicked()");
                break;

              case 3:       // leave unassigned
                break;
            }
          }
        }
        delete corrDlg;
      }
    } else
      break;

  } while(rc != TQDialog::Accepted);

  // for deposits, we inverted the sign of all splits.
  // now we revert it back, so that things are left correct
  if(m_isDeposit) {
    for(unsigned i = 0; i < m_transaction.splits().count(); ++i) {
      MyMoneySplit split = m_transaction.splits()[i];
      split.setValue(-split.value());
      split.setShares(-split.shares());
      m_transaction.modifySplit(split);
    }
  }

  return rc;
}

void KSplitTransactionDlg::initSize(void)
{
  TQDialog::resize(width(), height()+1);
}

void KSplitTransactionDlg::accept()
{
  transactionsTable->slotCancelEdit();
  KSplitTransactionDlgDecl::accept();
}

void KSplitTransactionDlg::reject()
{
  // cancel any edit activity in the split register
  transactionsTable->slotCancelEdit();
  KSplitTransactionDlgDecl::reject();
}

void KSplitTransactionDlg::slotClearAllSplits(void)
{
  transactionsTable->slotEndEdit();
  int answer;
  answer = KMessageBox::warningContinueCancel (this,
     i18n("You are about to delete all splits of this transaction. "
          "Do you really want to continue?"),
     i18n("KMyMoney"),
     i18n("Continue")
     );

  if(answer == KMessageBox::Continue) {
    transactionsTable->slotCancelEdit();
    TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
    TQValueList<MyMoneySplit>::ConstIterator it;

    // clear all but the one referencing the account
    for(it = list.begin(); it != list.end(); ++it) {
      m_transaction.removeSplit(*it);
    }

    transactionsTable->setTransaction(m_transaction, m_split, m_account);
    slotSetTransaction(m_transaction);
  }
}

void KSplitTransactionDlg::slotClearUnusedSplits(void)
{
  transactionsTable->slotEndEdit();

  TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
  TQValueList<MyMoneySplit>::ConstIterator it;

  try {
    // remove all splits that don't have a value assigned
    for(it = list.begin(); it != list.end(); ++it) {
      if((*it).shares().isZero()) {
        m_transaction.removeSplit(*it);
      }
    }

    transactionsTable->setTransaction(m_transaction, m_split, m_account);
    slotSetTransaction(m_transaction);
  } catch(MyMoneyException* e) {
    delete e;
  }
}

void KSplitTransactionDlg::slotMergeSplits(void)
{
  transactionsTable->slotEndEdit();

  TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
  TQValueList<MyMoneySplit>::ConstIterator it;

  try {
    // collect all splits, merge them if needed and remove from transaction
    TQValueList<MyMoneySplit> splits;
    for(it = list.begin(); it != list.end(); ++it) {
      TQValueList<MyMoneySplit>::iterator it_s;
      for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
        if((*it_s).accountId() == (*it).accountId()
        && (*it_s).memo().isEmpty() && (*it).memo().isEmpty())
          break;
      }
      if(it_s != splits.end()) {
        (*it_s).setShares((*it).shares() + (*it_s).shares());
        (*it_s).setValue((*it).value() + (*it_s).value());
      } else {
        splits << *it;
      }
      m_transaction.removeSplit(*it);
    }

    // now add them back to the transaction
    TQValueList<MyMoneySplit>::iterator it_s;
    for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
      (*it_s).clearId();
      m_transaction.addSplit(*it_s);
    }

    transactionsTable->setTransaction(m_transaction, m_split, m_account);
    slotSetTransaction(m_transaction);
  } catch(MyMoneyException* e) {
    delete e;
  }
}

void KSplitTransactionDlg::slotSetTransaction(const MyMoneyTransaction& t)
{
  transactionsTable->slotCancelEdit();

  m_transaction = t;
  TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
  TQValueList<MyMoneySplit>::ConstIterator it;

  // check if we can merge splits or not, have zero splits or not
  TQMap<TQString, int> splits;
  bool haveZeroSplit = false;
  for(it = list.begin(); it != list.end(); ++it) {
    splits[(*it).accountId()]++;
    if(((*it).id() != m_split.id()) && ((*it).shares().isZero()))
      haveZeroSplit = true;
  }
  TQMap<TQString, int>::const_iterator it_s;
  for(it_s = splits.begin(); it_s != splits.end(); ++it_s) {
    if((*it_s) > 1)
      break;
  }
  mergeBtn->setDisabled(it_s == splits.end());
  clearZeroBtn->setEnabled(haveZeroSplit);

  updateSums();
}

void KSplitTransactionDlg::updateSums(void)
{
  MyMoneyMoney splits(splitsValue());

  if(m_amountValid == false) {
    m_split.setValue(-splits);
    m_transaction.modifySplit(m_split);
  }

  splitSum->setText("<b>" + splits.formatMoney("", m_precision) + " ");
  splitUnassigned->setText("<b>" + diffAmount().formatMoney("", m_precision) + " ");
  transactionAmount->setText("<b>" + (-m_split.value()).formatMoney("", m_precision) + " ");
}

MyMoneyMoney KSplitTransactionDlg::splitsValue(void)
{
  MyMoneyMoney splitsValue(m_calculatedValue);
  TQValueList<MyMoneySplit> list = transactionsTable->getSplits(m_transaction);
  TQValueList<MyMoneySplit>::ConstIterator it;

  // calculate the current sum of all split parts
  for(it = list.begin(); it != list.end(); ++it) {
    if((*it).value() != MyMoneyMoney::autoCalc)
      splitsValue += (*it).value();
  }

  return splitsValue;
}

MyMoneyMoney KSplitTransactionDlg::diffAmount(void)
{
  MyMoneyMoney diff(0);

  // if there is an amount specified in the transaction, we need to calculate the
  // difference, otherwise we display the difference as 0 and display the same sum.
  if(m_amountValid) {
    MyMoneySplit split = m_transaction.splits()[0];

    diff = -(splitsValue() + split.value());
  }
  return diff;
}

void KSplitTransactionDlg::slotCreateCategory(const TQString& name, TQString& id)
{
  MyMoneyAccount acc, parent;
  acc.setName(name);

  if(m_isDeposit)
    parent = MyMoneyFile::instance()->income();
  else
    parent = MyMoneyFile::instance()->expense();

  // TODO extract possible first part of a hierarchy and check if it is one
  // of our top categories. If so, remove it and select the parent
  // according to this information.

  emit createCategory(acc, parent);

  // return id
  id = acc.id();
}

#include "ksplittransactiondlg.moc"
