/*
 * Copyright 2006-2018  Thomas Baumgart <tbaumgart@kde.org>
 * Copyright 2017-2018  Łukasz Wojniłowicz <lukasz.wojnilowicz@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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "investtransaction.h"
#include "investtransaction_p.h"

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

#include <QString>
#include <QWidget>
#include <QList>
#include <QPushButton>

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

#include <KLocalizedString>

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

#include "kmymoneypayeecombo.h"
#include "transaction.h"

#include "mymoneyutils.h"
#include "mymoneytransaction.h"
#include "mymoneysplit.h"
#include "mymoneyfile.h"
#include "register.h"
#include "transactionform.h"
#include "kmymoneylineedit.h"
#include "kmymoneyedit.h"
#include "kmymoneycombo.h"
#include "investtransactioneditor.h"
#include "kmymoneyutils.h"

#include "kmymoneysettings.h"
#include "widgetenums.h"

using namespace eWidgets;
using namespace KMyMoneyRegister;
using namespace KMyMoneyTransactionForm;

InvestTransaction::InvestTransaction(Register *parent, const MyMoneyTransaction& transaction, const MyMoneySplit& split, int uniqueId) :
  Transaction(*new InvestTransactionPrivate, parent, transaction, split, uniqueId)
{
  Q_D(InvestTransaction);
#ifndef KMM_DESIGNER
  // dissect the transaction into its type, splits, currency, security etc.
  KMyMoneyUtils::dissectTransaction(d->m_transaction, d->m_split,
                                    d->m_assetAccountSplit,
                                    d->m_feeSplits,
                                    d->m_interestSplits,
                                    d->m_security,
                                    d->m_currency,
                                    d->m_transactionType);
#endif

  QList<MyMoneySplit>::ConstIterator it_s;
  for (it_s = d->m_feeSplits.constBegin(); it_s != d->m_feeSplits.constEnd(); ++it_s) {
    d->m_feeAmount += (*it_s).value();
  }
  for (it_s = d->m_interestSplits.constBegin(); it_s != d->m_interestSplits.constEnd(); ++it_s) {
    d->m_interestAmount += (*it_s).value();
  }

  // check the count of the fee splits and setup the text
  switch (d->m_feeSplits.count()) {
    case 0:
      break;

    case 1:
      d->m_feeCategory = MyMoneyFile::instance()->accountToCategory(d->m_feeSplits[0].accountId());
      break;

    default:
      d->m_feeCategory = i18nc("Split transaction (category replacement)", "Split transaction");
      break;
  }

  // check the count of the interest splits and setup the text
  switch (d->m_interestSplits.count()) {
    case 0:
      break;

    case 1:
      d->m_interestCategory = MyMoneyFile::instance()->accountToCategory(d->m_interestSplits[0].accountId());
      break;

    default:
      d->m_interestCategory = i18nc("Split transaction (category replacement)", "Split transaction");
      break;
  }

  d->m_rowsForm = 7;

  // setup initial size
  setNumRowsRegister(numRowsRegister(KMyMoneySettings::showRegisterDetailed()));

  emit parent->itemAdded(this);
}

InvestTransaction::~InvestTransaction()
{
}

const QString InvestTransaction::sortSecurity() const
{
  Q_D(const InvestTransaction);
  return d->m_security.name();
}

const char* InvestTransaction::className()
{
  return "InvestTransaction";
}

void InvestTransaction::setupForm(TransactionForm* form)
{
  Transaction::setupForm(form);
  form->setSpan(5, 1, 2, 1);
}

void InvestTransaction::activity(QString& txt, eMyMoney::Split::InvestmentTransactionType type) const
{
  switch (type) {
    case eMyMoney::Split::InvestmentTransactionType::AddShares:
      txt = i18nc("Add securities/shares/bonds", "Add shares");
      break;
    case eMyMoney::Split::InvestmentTransactionType::RemoveShares:
      txt = i18nc("Remove securities/shares/bonds", "Remove shares");
      break;
    case eMyMoney::Split::InvestmentTransactionType::BuyShares:
      txt = i18nc("Buy securities/shares/bonds", "Buy shares");
      break;
    case eMyMoney::Split::InvestmentTransactionType::SellShares:
      txt = i18nc("Sell securities/shares/bonds", "Sell shares");
      break;
    case eMyMoney::Split::InvestmentTransactionType::Dividend:
      txt = i18n("Dividend");
      break;
    case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend:
      txt = i18n("Reinvest Dividend");
      break;
    case eMyMoney::Split::InvestmentTransactionType::Yield:
      txt = i18n("Yield");
      break;
    case eMyMoney::Split::InvestmentTransactionType::SplitShares:
      txt = i18nc("Split securities/shares/bonds", "Split shares");
      break;
    case eMyMoney::Split::InvestmentTransactionType::InterestIncome:
      txt = i18n("Interest Income");
      break;
    default:
      txt = i18nc("Unknown investment activity", "Unknown");
      break;
  }
}

bool InvestTransaction::formCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* /* painter */)
{
  Q_D(InvestTransaction);
  bool fieldEditable = false;

  switch (row) {
    case 0:
      switch (col) {
        case (int)eTransactionForm::Column::Label1:
          align |= Qt::AlignLeft;
          txt = i18n("Activity");
          break;

        case (int)eTransactionForm::Column::Value1:
          align |= Qt::AlignLeft;
          fieldEditable = true;
          activity(txt, d->m_transactionType);
          break;

        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          txt = i18n("Date");
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          fieldEditable = true;
          if (!d->m_transaction.id().isEmpty())
            txt = QLocale().toString(d->m_transaction.postDate(), QLocale::ShortFormat);
          break;
      }
      break;

    case 1:
      switch (col) {
        case (int)eTransactionForm::Column::Label1:
          align |= Qt::AlignLeft;
          txt = i18n("Security");
          break;

        case (int)eTransactionForm::Column::Value1:
          align |= Qt::AlignLeft;
          fieldEditable = true;
          if (d->m_account.isInvest())
            txt = d->m_security.name();
          break;

        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          if (haveShares()) {
            txt = i18n("Shares");
          } else if (haveSplitRatio()) {
            txt = i18n("Ratio");
          }
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          if ((fieldEditable = haveShares()) == true) {
            txt = d->m_split.shares().abs().formatMoney(QString(), MyMoneyMoney::denomToPrec(d->m_security.smallestAccountFraction()));
          } else if (haveSplitRatio()) {
            txt = QString("1 / %1").arg(d->m_split.shares().abs().formatMoney(QString(), -1));
          }
          break;
      }
      break;

    case 2:
      switch (col) {
        case (int)eTransactionForm::Column::Label1:
          align |= Qt::AlignLeft;
          if (haveAssetAccount())
            txt = i18n("Account");
          break;

        case (int)eTransactionForm::Column::Value1:
          align |= Qt::AlignLeft;
          if ((fieldEditable = haveAssetAccount()) == true) {
            txt = MyMoneyFile::instance()->accountToCategory(d->m_assetAccountSplit.accountId());
          }
          break;

        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          if (havePrice())
            txt = i18n("Price/share");
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          if ((fieldEditable = havePrice()) == true && !d->m_split.shares().isZero()) {
            txt = d->m_split.price().formatMoney(QString(), d->m_security.pricePrecision());
          }
          break;
      }
      break;

    case 3:
      switch (col) {
        case (int)eTransactionForm::Column::Label1:
          align |= Qt::AlignLeft;
          if (haveFees())
            txt = i18n("Fees");
          break;

        case (int)eTransactionForm::Column::Value1:
          align |= Qt::AlignLeft;
          if ((fieldEditable = haveFees()) == true) {
            txt = d->m_feeCategory;
          }
          break;

        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          if (haveFees() && !d->m_feeCategory.isEmpty())
            txt = i18n("Fee Amount");
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          if (haveFees()) {
            if ((fieldEditable = !d->m_feeCategory.isEmpty()) == true) {
              txt = MyMoneyUtils::formatMoney(d->m_feeAmount, d->m_currency);
            }
          }
          break;
      }
      break;

    case 4:
      switch (col) {
        case (int)eTransactionForm::Column::Label1:
          align |= Qt::AlignLeft;
          if (haveInterest())
            txt = i18n("Interest");
          break;

        case (int)eTransactionForm::Column::Value1:
          align |= Qt::AlignLeft;
          if ((fieldEditable = haveInterest()) == true) {
            txt = d->m_interestCategory;
          }
          break;

        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          if (haveInterest() && !d->m_interestCategory.isEmpty())
            txt = i18n("Interest");
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          if (haveInterest()) {
            if ((fieldEditable = !d->m_interestCategory.isEmpty()) == true) {
              txt = MyMoneyUtils::formatMoney(-d->m_interestAmount, d->m_currency);
            }
          }
          break;
      }
      break;

    case 5:
      switch (col) {
        case (int)eTransactionForm::Column::Label1:
          align |= Qt::AlignLeft;
          txt = i18n("Memo");
          break;

        case (int)eTransactionForm::Column::Value1:
          align &= ~Qt::AlignVCenter;
          align |= Qt::AlignTop;
          align |= Qt::AlignLeft;
          fieldEditable = true;
          if (!d->m_transaction.id().isEmpty())
            txt = d->m_split.memo().section('\n', 0, 2);
          break;

        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          if (haveAmount())
            txt = i18nc("Total balance", "Total");
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          if ((fieldEditable = haveAmount()) == true) {
            txt = d->m_assetAccountSplit.value().abs()
                .formatMoney(d->m_currency.tradingSymbol(), MyMoneyMoney::denomToPrec(d->m_currency.smallestAccountFraction()));
          }
      }
      break;

    case 6:
      switch (col) {
        case (int)eTransactionForm::Column::Label2:
          align |= Qt::AlignLeft;
          txt = i18n("Status");
          break;

        case (int)eTransactionForm::Column::Value2:
          align |= Qt::AlignRight;
          fieldEditable = true;
          txt = reconcileState();
          break;
      }
  }

  return fieldEditable;
}

void InvestTransaction::registerCellText(QString& txt, Qt::Alignment& align, int row, int col, QPainter* /* painter */)
{
  Q_D(InvestTransaction);
  switch (row) {
    case 0:
      switch (col) {
        case (int)eTransaction::Column::Date:
          align |= Qt::AlignLeft;
          txt = QLocale().toString(d->m_transaction.postDate(), QLocale::ShortFormat);
          break;

        case (int)eTransaction::Column::Detail:
          align |= Qt::AlignLeft;
          activity(txt, d->m_transactionType);
          break;

        case (int)eTransaction::Column::Security:
          align |= Qt::AlignLeft;
          if (d->m_account.isInvest())
            txt = d->m_security.name();
          break;

        case (int)eTransaction::Column::ReconcileFlag:
          align |= Qt::AlignHCenter;
          txt = reconcileState(false);
          break;

        case (int)eTransaction::Column::Quantity:
          align |= Qt::AlignRight;
          if (haveShares())
            txt = d->m_split.shares().abs().formatMoney(QString(), MyMoneyMoney::denomToPrec(d->m_security.smallestAccountFraction()));
          else if (haveSplitRatio()) {
            txt = QString("1 / %1").arg(d->m_split.shares().abs().formatMoney(QString(), -1));
          }
          break;

        case (int)eTransaction::Column::Price:
          align |= Qt::AlignRight;
          if (havePrice() && !d->m_split.shares().isZero()) {
            txt = d->m_split.price().formatMoney(d->m_currency.tradingSymbol(), d->m_security.pricePrecision());
          }
          break;

        case (int)eTransaction::Column::Value:
          align |= Qt::AlignRight;
          if (haveAmount()) {
            txt = MyMoneyUtils::formatMoney(d->m_assetAccountSplit.value().abs(), d->m_currency);

          } else if (haveInterest()) {
            txt = MyMoneyUtils::formatMoney(-d->m_interestAmount, d->m_currency);
          }
          break;

        case (int)eTransaction::Column::Balance:
          align |= Qt::AlignRight;
          if (d->m_showBalance)
            txt = d->m_balance.formatMoney(QString(), MyMoneyMoney::denomToPrec(d->m_security.smallestAccountFraction()));
          else
            txt = "----";
          break;

        default:
          break;
      }
      break;

    case 1:
      switch (col) {
        case (int)eTransaction::Column::Detail:
          align |= Qt::AlignLeft;
          if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty()) {
            txt = MyMoneyFile::instance()->accountToCategory(d->m_assetAccountSplit.accountId());
          } else if (haveInterest() && d->m_interestSplits.count()) {
            txt = d->m_interestCategory;
          } else if (haveFees() && d->m_feeSplits.count()) {
            txt = d->m_feeCategory;
          } else
            singleLineMemo(txt, d->m_split);
          break;

        case (int)eTransaction::Column::Quantity:
          align |= Qt::AlignRight;
          if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty()) {
            // txt = m_interestAmount.abs().formatMoney(m_currency);
          } else if (haveInterest() && d->m_interestSplits.count()) {
            txt = MyMoneyUtils::formatMoney(-d->m_interestAmount, d->m_currency);
          } else if (haveFees() && d->m_feeSplits.count()) {
            txt = MyMoneyUtils::formatMoney(d->m_feeAmount, d->m_currency);
          }
          break;

        default:
          break;
      }
      break;

    case 2:
      switch (col) {
        case (int)eTransaction::Column::Detail:
          align |= Qt::AlignLeft;
          if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty()
              && haveInterest() && d->m_interestSplits.count()) {
            txt = d->m_interestCategory;
          } else if (haveFees() && d->m_feeSplits.count()) {
            txt = d->m_feeCategory;
          } else
            singleLineMemo(txt, d->m_split);
          break;

        case (int)eTransaction::Column::Quantity:
          align |= Qt::AlignRight;
          if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty()
              && haveInterest() && d->m_interestSplits.count()) {
            txt = MyMoneyUtils::formatMoney(-d->m_interestAmount, d->m_currency);
          } else if (haveFees() && d->m_feeSplits.count()) {
            txt = MyMoneyUtils::formatMoney(d->m_feeAmount, d->m_currency);
          }
          break;

        default:
          break;
      }
      break;

    case 3:
      switch (col) {
        case (int)eTransaction::Column::Detail:
          align |= Qt::AlignLeft;
          if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty()
              && haveInterest() && d->m_interestSplits.count()
              && haveFees() && d->m_feeSplits.count()) {
            txt = d->m_feeCategory;
          } else
            singleLineMemo(txt, d->m_split);
          break;

        case (int)eTransaction::Column::Quantity:
          align |= Qt::AlignRight;
          if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty()
              && haveInterest() && d->m_interestSplits.count()
              && haveFees() && d->m_feeSplits.count()) {
            txt = MyMoneyUtils::formatMoney(d->m_feeAmount, d->m_currency);
          }
          break;

        default:
          break;
      }
      break;

    case 4:
      switch (col) {
        case (int)eTransaction::Column::Detail:
          align |= Qt::AlignLeft;
          singleLineMemo(txt, d->m_split);
          break;

        default:
          break;
      }
      break;
  }
}

int InvestTransaction::registerColWidth(int col, const QFontMetrics& cellFontMetrics)
{
  Q_D(InvestTransaction);
  QString txt;
  MyMoneyMoney amount;
  int nw = 0;

  // for now just check all rows in that column
  for (int row = 0; row < d->m_rowsRegister; ++row) {
    int w;
    Transaction::registerCellText(txt, row, col);
    w = cellFontMetrics.width(txt + "  ");
    nw = qMax(nw, w);
  }

  // TODO the optimized way would be to base the size on the contents of a single row
  //      as we do it in StdTransaction::registerColWidth()
#if 0
  switch (col) {
    default:
      break;

    case PriceColumn:
      if (havePrice()) {
        txt = (m_split.value() / m_split.shares()).formatMoney(QString(), KMyMoneySettings::pricePrecision());
        nw = cellFontMetrics.width(txt + "  ");
      }
      break;
  }
#endif
  return nw;
}

void InvestTransaction::loadTab(KMyMoneyTransactionForm::TransactionForm* /* form */)
{
}

int InvestTransaction::numColsForm() const
{
  return 4;
}

void InvestTransaction::arrangeWidgetsInForm(QMap<QString, QWidget*>& editWidgets)
{
  Q_D(InvestTransaction);
  if (!d->m_form || !d->m_parent)
    return;

  setupFormPalette(editWidgets);

  // arrange the edit widgets
  arrangeWidget(d->m_form, 0, (int)eTransactionForm::Column::Value1, editWidgets["activity"]);
  arrangeWidget(d->m_form, 0, (int)eTransactionForm::Column::Value2, editWidgets["postdate"]);
  arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Value1, editWidgets["security"]);
  arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Value2, editWidgets["shares"]);
  arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Value1, editWidgets["asset-account"]);
  arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Value2, editWidgets["price"]);
  arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Value1, editWidgets["fee-account"]->parentWidget());
  arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Value2, editWidgets["fee-amount"]);
  arrangeWidget(d->m_form, 4, (int)eTransactionForm::Column::Value1, editWidgets["interest-account"]->parentWidget());
  arrangeWidget(d->m_form, 4, (int)eTransactionForm::Column::Value2, editWidgets["interest-amount"]);
  arrangeWidget(d->m_form, 5, (int)eTransactionForm::Column::Value1, editWidgets["memo"]);
  arrangeWidget(d->m_form, 5, (int)eTransactionForm::Column::Value2, editWidgets["total"]);
  arrangeWidget(d->m_form, 6, (int)eTransactionForm::Column::Value2, editWidgets["status"]);

  // arrange dynamic labels
  arrangeWidget(d->m_form, 0, (int)eTransactionForm::Column::Label1, editWidgets["activity-label"]);
  arrangeWidget(d->m_form, 0, (int)eTransactionForm::Column::Label2, editWidgets["postdate-label"]);
  arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Label1, editWidgets["security-label"]);
  arrangeWidget(d->m_form, 1, (int)eTransactionForm::Column::Label2, editWidgets["shares-label"]);
  arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Label1, editWidgets["asset-label"]);
  arrangeWidget(d->m_form, 2, (int)eTransactionForm::Column::Label2, editWidgets["price-label"]);
  arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Label1, editWidgets["fee-label"]);
  arrangeWidget(d->m_form, 3, (int)eTransactionForm::Column::Label2, editWidgets["fee-amount-label"]);
  arrangeWidget(d->m_form, 4, (int)eTransactionForm::Column::Label1, editWidgets["interest-label"]);
  arrangeWidget(d->m_form, 4, (int)eTransactionForm::Column::Label2, editWidgets["interest-amount-label"]);
  arrangeWidget(d->m_form, 5, (int)eTransactionForm::Column::Label1, editWidgets["memo-label"]);
  arrangeWidget(d->m_form, 5, (int)eTransactionForm::Column::Label2, editWidgets["total-label"]);
  arrangeWidget(d->m_form, 6, (int)eTransactionForm::Column::Label2, editWidgets["status-label"]);

  // get rid of the hints. we don't need them for the form
  QMap<QString, QWidget*>::iterator it;
  for (it = editWidgets.begin(); it != editWidgets.end(); ++it) {
    KMyMoneyCombo* combo = dynamic_cast<KMyMoneyCombo*>(*it);
    KMyMoneyLineEdit* lineedit = dynamic_cast<KMyMoneyLineEdit*>(*it);
    KMyMoneyEdit* edit = dynamic_cast<KMyMoneyEdit*>(*it);
    KMyMoneyPayeeCombo* payee = dynamic_cast<KMyMoneyPayeeCombo*>(*it);
    if (combo)
      combo->setPlaceholderText(QString());
    if (edit)
      edit->setPlaceholderText(QString());
    if (lineedit)
      lineedit->setPlaceholderText(QString());
    if (payee)
      payee->setPlaceholderText(QString());
  }
}

void InvestTransaction::tabOrderInForm(QWidgetList& tabOrderWidgets) const
{
  Q_D(const InvestTransaction);
  // activity
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(0, (int)eTransactionForm::Column::Value1)));

  // date
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(0, (int)eTransactionForm::Column::Value2)));

  // security
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(1, (int)eTransactionForm::Column::Value1)));

  // shares
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(1, (int)eTransactionForm::Column::Value2)));

  // account
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(2, (int)eTransactionForm::Column::Value1)));

  // price
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(2, (int)eTransactionForm::Column::Value2)));

  // make sure to have the fee category field and the split button as separate tab order widgets
  // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
  // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
  // go haywire when someone changes the KMyMoneyCategory object ...
  QWidget* w = d->m_form->cellWidget(3, (int)eTransactionForm::Column::Value1);
  tabOrderWidgets.append(focusWidget(w));
  w = w->findChild<QPushButton*>("splitButton");
  if (w)
    tabOrderWidgets.append(w);

  // fee amount
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(3, (int)eTransactionForm::Column::Value2)));

  // the same applies for the interest categories
  w = d->m_form->cellWidget(4, (int)eTransactionForm::Column::Value1);
  tabOrderWidgets.append(focusWidget(w));
  w = w->findChild<QPushButton*>("splitButton");
  if (w)
    tabOrderWidgets.append(w);

  // interest amount
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(4, (int)eTransactionForm::Column::Value2)));

  // memo
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(5, (int)eTransactionForm::Column::Value1)));

  // state
  tabOrderWidgets.append(focusWidget(d->m_form->cellWidget(6, (int)eTransactionForm::Column::Value2)));
}

void InvestTransaction::arrangeWidgetsInRegister(QMap<QString, QWidget*>& editWidgets)
{
  Q_D(InvestTransaction);
  if (!d->m_parent)
    return;

  setupRegisterPalette(editWidgets);

  arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Date, editWidgets["postdate"]);
  arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Security, editWidgets["security"]);
  arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Detail, editWidgets["activity"]);
  arrangeWidget(d->m_parent, d->m_startRow + 1, (int)eTransaction::Column::Detail, editWidgets["asset-account"]);
  arrangeWidget(d->m_parent, d->m_startRow + 2, (int)eTransaction::Column::Detail, editWidgets["interest-account"]->parentWidget());
  arrangeWidget(d->m_parent, d->m_startRow + 3, (int)eTransaction::Column::Detail, editWidgets["fee-account"]->parentWidget());
  arrangeWidget(d->m_parent, d->m_startRow + 4, (int)eTransaction::Column::Detail, editWidgets["memo"]);
  arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Quantity, editWidgets["shares"]);
  arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Price, editWidgets["price"]);
  arrangeWidget(d->m_parent, d->m_startRow + 2, (int)eTransaction::Column::Quantity, editWidgets["interest-amount"]);
  arrangeWidget(d->m_parent, d->m_startRow + 3, (int)eTransaction::Column::Quantity, editWidgets["fee-amount"]);
  arrangeWidget(d->m_parent, d->m_startRow + 0, (int)eTransaction::Column::Value, editWidgets["total"]);
  arrangeWidget(d->m_parent, d->m_startRow + 1, (int)eTransaction::Column::Date, editWidgets["status"]);

  // increase the height of the row containing the memo widget
  d->m_parent->setRowHeight(d->m_startRow + 4, d->m_parent->rowHeightHint() * 3);
}

void InvestTransaction::tabOrderInRegister(QWidgetList& tabOrderWidgets) const
{
  Q_D(const InvestTransaction);
  QWidget* w;

  // date
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Date)));
  // security
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Security)));
  // activity
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Detail)));
  // shares
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Quantity)));
  // price
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 0, (int)eTransaction::Column::Price)));
  // asset account
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 1, (int)eTransaction::Column::Detail)));

  // make sure to have the category fields and the split button as separate tab order widgets
  // ok, we have to have some internal knowledge about the KMyMoneyCategory object, but
  // it's one of our own widgets, so we actually don't care. Just make sure, that we don't
  // go haywire when someone changes the KMyMoneyCategory object ...
  w = d->m_parent->cellWidget(d->m_startRow + 2, (int)eTransaction::Column::Detail);    // interest account
  tabOrderWidgets.append(focusWidget(w));
  w = w->findChild<QPushButton*>("splitButton");
  if (w)
    tabOrderWidgets.append(w);

  // interest amount
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 2, (int)eTransaction::Column::Quantity)));

  w = d->m_parent->cellWidget(d->m_startRow + 3, (int)eTransaction::Column::Detail);    // fee account
  tabOrderWidgets.append(focusWidget(w));
  w = w->findChild<QPushButton*>("splitButton");
  if (w)
    tabOrderWidgets.append(w);

  // fee amount
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 3, (int)eTransaction::Column::Quantity)));

  // memo
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 4, (int)eTransaction::Column::Detail)));

  // status
  tabOrderWidgets.append(focusWidget(d->m_parent->cellWidget(d->m_startRow + 1, (int)eTransaction::Column::Date)));
}

eRegister::Action InvestTransaction::actionType() const
{
  return eRegister::Action::None;
}

int InvestTransaction::numRowsRegister(bool expanded) const
{
  Q_D(const InvestTransaction);
  int numRows = 1;
  if (expanded) {
    if (!d->m_inEdit) {
      if (haveAssetAccount() && !d->m_assetAccountSplit.accountId().isEmpty())
        ++numRows;
      if (haveInterest() && d->m_interestSplits.count())
        ++numRows;
      if (haveFees() && d->m_feeSplits.count())
        ++numRows;
      if (!d->m_split.memo().isEmpty())
        ++numRows;
    } else
      numRows = 5;
  }
  return numRows;
}

bool InvestTransaction::haveShares() const
{
  Q_D(const InvestTransaction);
  auto rc = true;
  switch (d->m_transactionType) {
    case eMyMoney::Split::InvestmentTransactionType::Dividend:
    case eMyMoney::Split::InvestmentTransactionType::Yield:
    case eMyMoney::Split::InvestmentTransactionType::SplitShares:
    case eMyMoney::Split::InvestmentTransactionType::InterestIncome:
      rc = false;
      break;

    default:
      break;
  }
  return rc;
}

bool InvestTransaction::haveFees() const
{
  Q_D(const InvestTransaction);
  auto rc = true;
  switch (d->m_transactionType) {
    case eMyMoney::Split::InvestmentTransactionType::AddShares:
    case eMyMoney::Split::InvestmentTransactionType::RemoveShares:
    case eMyMoney::Split::InvestmentTransactionType::SplitShares:
      rc = false;
      break;

    default:
      break;
  }
  return rc;
}

bool InvestTransaction::haveInterest() const
{
  Q_D(const InvestTransaction);
  auto rc = false;
  switch (d->m_transactionType) {
    case eMyMoney::Split::InvestmentTransactionType::BuyShares:
    case eMyMoney::Split::InvestmentTransactionType::SellShares:
    case eMyMoney::Split::InvestmentTransactionType::Dividend:
    case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend:
    case eMyMoney::Split::InvestmentTransactionType::Yield:
    case eMyMoney::Split::InvestmentTransactionType::InterestIncome:
      rc = true;
      break;

    default:
      break;
  }
  return rc;
}

bool InvestTransaction::havePrice() const
{
  Q_D(const InvestTransaction);
  auto rc = false;
  switch (d->m_transactionType) {
    case eMyMoney::Split::InvestmentTransactionType::BuyShares:
    case eMyMoney::Split::InvestmentTransactionType::SellShares:
    case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend:
      rc = true;
      break;

    default:
      break;
  }
  return rc;
}

bool InvestTransaction::haveAmount() const
{
  Q_D(const InvestTransaction);
  auto rc = false;
  switch (d->m_transactionType) {
    case eMyMoney::Split::InvestmentTransactionType::BuyShares:
    case eMyMoney::Split::InvestmentTransactionType::SellShares:
    case eMyMoney::Split::InvestmentTransactionType::Dividend:
    case eMyMoney::Split::InvestmentTransactionType::Yield:
    case eMyMoney::Split::InvestmentTransactionType::InterestIncome:
      rc = true;
      break;

    default:
      break;
  }
  return rc;
}

bool InvestTransaction::haveAssetAccount() const
{
  Q_D(const InvestTransaction);
  auto rc = true;
  switch (d->m_transactionType) {
    case eMyMoney::Split::InvestmentTransactionType::AddShares:
    case eMyMoney::Split::InvestmentTransactionType::RemoveShares:
    case eMyMoney::Split::InvestmentTransactionType::SplitShares:
    case eMyMoney::Split::InvestmentTransactionType::ReinvestDividend:
      rc = false;
      break;

    default:
      break;
  }
  return rc;
}

bool InvestTransaction::haveSplitRatio() const
{
  Q_D(const InvestTransaction);
  return d->m_transactionType == eMyMoney::Split::InvestmentTransactionType::SplitShares;
}

void InvestTransaction::splits(MyMoneySplit& assetAccountSplit, QList<MyMoneySplit>& interestSplits, QList<MyMoneySplit>& feeSplits) const
{
  Q_D(const InvestTransaction);
  assetAccountSplit = d->m_assetAccountSplit;
  interestSplits = d->m_interestSplits;
  feeSplits = d->m_feeSplits;
}

int InvestTransaction::numRowsRegister() const
{
  return RegisterItem::numRowsRegister();
}

TransactionEditor* InvestTransaction::createEditor(TransactionEditorContainer* regForm, const KMyMoneyRegister::SelectedTransactions& list, const QDate& lastPostDate)
{
#ifndef KMM_DESIGNER
  Q_D(InvestTransaction);
  d->m_inRegisterEdit = regForm == d->m_parent;
  return new InvestTransactionEditor(regForm, this, list, lastPostDate);
#else
  return NULL;
#endif
}

