/***************************************************************************
                          kqifprofileeditor.cpp  -  description
                             -------------------
    begin                : Tue Dec 24 2002
    copyright            : (C) 2002 by Thomas Baumgart
    email                : thb@net-bembel.de
 ***************************************************************************/

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

#include "mymoneyqifprofileeditor.h"

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

#include <QPushButton>
#include <QCheckBox>
#include <QListWidget>
#include <QTabWidget>
#include <QIcon>
#include <QInputDialog>

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

#include <KLocalizedString>
#include <kconfig.h>
#include <KConfigGroup>
#include <klineedit.h>
#include <kmessagebox.h>
#include <kcombobox.h>
#include <kurlrequester.h>
#include <khelpclient.h>
#include <KGuiItem>
#include <KStandardGuiItem>
#include <KSharedConfig>

// ----------------------------------------------------------------------------
// Project Includes
#include <icons/icons.h>

using namespace Icons;

MyMoneyQifProfileNameValidator::MyMoneyQifProfileNameValidator(QObject *o)
    : QValidator(o)
{
}

MyMoneyQifProfileNameValidator::~MyMoneyQifProfileNameValidator()
{
}

QValidator::State MyMoneyQifProfileNameValidator::validate(QString& name, int&) const
{
  KSharedConfigPtr config = KSharedConfig::openConfig();
  KConfigGroup grp = config->group("Profiles");
  QStringList list = grp.readEntry("profiles", QStringList());

  // invalid character?
  if (name.contains(",") != 0)
    return QValidator::Invalid;

  // would not work in this form (empty or existing name)
  if (name.isEmpty() || list.contains(name))
    return QValidator::Intermediate;

  // is OK
  return QValidator::Acceptable;
}

MyMoneyQifProfileEditor::MyMoneyQifProfileEditor(const bool edit, QWidget *parent)
    : QWidget(parent),
    m_inEdit(edit),
    m_isDirty(false),
    m_isAccepted(false),
    m_selectedAmountType(0)
{
  setupUi(this);
  loadWidgets();
  loadProfileListFromConfig();

  // load button icons
  KGuiItem::assign(m_resetButton, KStandardGuiItem::reset());
  KGuiItem::assign(m_deleteButton, KStandardGuiItem::del());
  KGuiItem::assign(m_helpButton, KStandardGuiItem::help());

  KGuiItem newButtenItem(i18nc("New profile", "&New"),
                         Icons::get(Icon::DocumentNew),
                         i18n("Create a new profile"),
                         i18n("Use this to create a new QIF import/export profile"));
  KGuiItem::assign(m_newButton, newButtenItem);

  connect(m_profileListBox, &QListWidget::currentTextChanged, this, &MyMoneyQifProfileEditor::slotLoadProfileFromConfig);
  connect(m_resetButton, &QAbstractButton::clicked, this, &MyMoneyQifProfileEditor::slotReset);
  connect(m_renameButton, &QAbstractButton::clicked, this, &MyMoneyQifProfileEditor::slotRename);
  connect(m_deleteButton, &QAbstractButton::clicked, this, &MyMoneyQifProfileEditor::slotDelete);
  connect(m_newButton, &QAbstractButton::clicked, this, &MyMoneyQifProfileEditor::slotNew);
  connect(m_helpButton, &QAbstractButton::clicked, this, &MyMoneyQifProfileEditor::slotHelp);

  connect(m_editDescription, &QLineEdit::textChanged, &m_profile, &MyMoneyQifProfile::setProfileDescription);
  connect(m_editType, &QLineEdit::textChanged, &m_profile, &MyMoneyQifProfile::setProfileType);
  connect(m_editOpeningBalance, &QLineEdit::textChanged, &m_profile, &MyMoneyQifProfile::setOpeningBalanceText);
  connect(m_editAccountDelimiter, &QLineEdit::textChanged, &m_profile, &MyMoneyQifProfile::setAccountDelimiter);
  connect(m_editVoidMark, &QLineEdit::textChanged, &m_profile, &MyMoneyQifProfile::setVoidMark);

  connect(m_editDateFormat, SIGNAL(highlighted(QString)), &m_profile, SLOT(setOutputDateFormat(QString)));
  connect(m_editApostrophe, SIGNAL(highlighted(QString)), &m_profile, SLOT(setApostropheFormat(QString)));

  connect(m_editAmounts, &QTreeWidget::itemSelectionChanged, this, &MyMoneyQifProfileEditor::slotAmountTypeSelected);
  connect(m_decimalBox, SIGNAL(activated(QString)), this, SLOT(slotDecimalChanged(QString)));
  connect(m_thousandsBox, SIGNAL(activated(QString)), this, SLOT(slotThousandsChanged(QString)));

  connect(m_editInputFilterLocation, &KUrlRequester::textChanged, &m_profile, &MyMoneyQifProfile::setFilterScriptImport);
  connect(m_editInputFilterLocation, &KUrlRequester::urlSelected, m_editInputFilterLocation, &KUrlRequester::setUrl);

  connect(m_editInputFilterFileType, &QLineEdit::textChanged, &m_profile, &MyMoneyQifProfile::setFilterFileType);

  connect(m_editOutputFilterLocation, &KUrlRequester::textChanged, &m_profile, &MyMoneyQifProfile::setFilterScriptExport);
  connect(m_editOutputFilterLocation, &KUrlRequester::urlSelected, m_editOutputFilterLocation, &KUrlRequester::setUrl);

  connect(m_attemptMatch, &QAbstractButton::toggled, &m_profile, &MyMoneyQifProfile::setAttemptMatchDuplicates);
}

MyMoneyQifProfileEditor::~MyMoneyQifProfileEditor()
{
  if (m_inEdit && m_isDirty && m_isAccepted) {
    KSharedConfigPtr config = KSharedConfig::openConfig();
    config->sync();
  } else {
    slotReset();
  }
  delete tabMoney;
  delete tabDate;
}

void MyMoneyQifProfileEditor::loadWidgets()
{
  if (m_inEdit)
    setWindowTitle(i18n("QIF Profile Editor"));
  else
    setWindowTitle(i18n("QIF Profile Selector"));

  m_editDateFormat->clear();
  m_editDateFormat->addItem("%d/%m/%yy");
  m_editDateFormat->addItem("%d/%mmm/%yy");
  m_editDateFormat->addItem("%d/%m/%yyyy");
  m_editDateFormat->addItem("%d/%mmm/%yyyy");
  m_editDateFormat->addItem("%d/%m%yy");
  m_editDateFormat->addItem("%d/%mmm%yy");
  m_editDateFormat->addItem("%d.%m.%yy");
  m_editDateFormat->addItem("%d.%m.%yyyy");
  m_editDateFormat->addItem("%m.%d.%yy");
  m_editDateFormat->addItem("%m.%d.%yyyy");
  m_editDateFormat->addItem("%m/%d/%yy");
  m_editDateFormat->addItem("%mmm/%d/%yy");
  m_editDateFormat->addItem("%m/%d/%yyyy");
  m_editDateFormat->addItem("%m-%d-%yyyy");
  m_editDateFormat->addItem("%mmm/%d/%yyyy");
  m_editDateFormat->addItem("%m%d%yy");
  m_editDateFormat->addItem("%mmm/%d%yy");
  m_editDateFormat->addItem("%yyyy-%mm-%dd");
  m_editDateFormat->addItem("%m/%d'%yyyy");

  m_editApostrophe->clear();
  m_editApostrophe->addItem("1900-1949");
  m_editApostrophe->addItem("1900-1999");
  m_editApostrophe->addItem("2000-2099");

  m_editAmounts->setColumnHidden(4, true);
  m_editAmounts->sortItems(4, Qt::AscendingOrder);

  m_decimalBox->addItem(" ");
  m_decimalBox->addItem(",");
  m_decimalBox->addItem(".");

  m_thousandsBox->addItem(" ");
  m_thousandsBox->addItem(",");
  m_thousandsBox->addItem(".");

  m_editDescription->setEnabled(m_inEdit);
  m_editType->setEnabled(m_inEdit);
  m_editDateFormat->setEnabled(m_inEdit);
  m_editApostrophe->setEnabled(m_inEdit);
  m_editAmounts->setEnabled(m_inEdit);
  m_decimalBox->setEnabled(m_inEdit);
  m_thousandsBox->setEnabled(m_inEdit);
  m_editOpeningBalance->setEnabled(m_inEdit);
  m_editAccountDelimiter->setEnabled(m_inEdit);
  m_editVoidMark->setEnabled(m_inEdit);
  m_editInputFilterLocation->setEnabled(m_inEdit);
  m_editOutputFilterLocation->setEnabled(m_inEdit);
  m_editInputFilterFileType->setEnabled(m_inEdit);

  if (!m_inEdit) {
    m_renameButton->hide();
    m_deleteButton->hide();
    m_resetButton->hide();
    m_newButton->hide();
  }
}

void MyMoneyQifProfileEditor::loadProfileListFromConfig()
{
  QFontMetrics fontMetrics(m_profileListBox->font());
  int w = 100;      // minimum is 100 pixels width for the list box

  if (m_profile.isDirty()) {
    m_profile.saveProfile();
    m_isDirty = true;
  }

  m_profileListBox->clear();

  QStringList list;
  KSharedConfigPtr config = KSharedConfig::openConfig();
  KConfigGroup grp = config->group("Profiles");
  list = grp.readEntry("profiles", QStringList());

  if (list.count() == 0) {
    m_profile.clear();
    m_profile.setProfileDescription(i18n("The default QIF profile"));
    addProfile("Default");

    grp = config->group("Profiles");
    list = grp.readEntry("profiles", QStringList());
  }

  list.sort();

  m_profileListBox->addItems(list);
  if (!list.isEmpty()) {
    m_profileListBox->item(0)->setSelected(true);
    slotLoadProfileFromConfig(list[0]);
  }
  for (int i = 0; i < list.count(); ++i) {
    int nw = fontMetrics.width(list[i]) + 10;
    w = qMax(w, nw);
  }
  w = qMin(w, 200);
  m_profileListBox->setMinimumWidth(w);
}

void MyMoneyQifProfileEditor::slotLoadProfileFromConfig(const QString& profile)
{
  QString profileName = profile;

  if (m_profile.isDirty()) {
    m_profile.saveProfile();
    m_isDirty = true;
  }

  if (m_profileListBox->findItems(profileName, Qt::MatchExactly | Qt::MatchCaseSensitive).empty()) {
    profileName = m_profileListBox->item(0)->text();
  }

  m_profile.loadProfile("Profile-" + profileName);

  QList<QListWidgetItem*> lbi = m_profileListBox->findItems(profileName, Qt::MatchExactly | Qt::MatchCaseSensitive);

  if (!lbi.empty()) {
    m_profileListBox->setCurrentItem(lbi.at(0));
  }
  showProfile();
}

void MyMoneyQifProfileEditor::showProfile()
{
  m_editDescription->setText(m_profile.profileDescription());
  m_editType->setText(m_profile.profileType());
  m_editOpeningBalance->setText(m_profile.openingBalanceText());
  m_editAccountDelimiter->setText(m_profile.accountDelimiter());
  m_editVoidMark->setText(m_profile.voidMark());
  m_editInputFilterLocation->setUrl(QUrl::fromLocalFile(m_profile.filterScriptImport()));
  m_editOutputFilterLocation->setUrl(QUrl::fromLocalFile(m_profile.filterScriptExport()));
  m_editInputFilterFileType->setText(m_profile.filterFileType());

  // load combo boxes
  int idx = m_editDateFormat->findText(m_profile.outputDateFormat());
  if (idx == -1)
    idx = 0;
  m_editDateFormat->setCurrentIndex(idx);

  idx = m_editApostrophe->findText(m_profile.apostropheFormat());
  if (idx == -1)
    idx = 0;
  m_editApostrophe->setCurrentIndex(idx);

  m_attemptMatch->setChecked(m_profile.attemptMatchDuplicates());

  QTreeWidgetItemIterator it(m_editAmounts);

  while (*it) {
    QChar key = (*it)->text(1)[0];
    (*it)->setText(2, m_profile.amountDecimal(key));
    (*it)->setTextAlignment(2, Qt::AlignCenter);
    (*it)->setText(3, m_profile.amountThousands(key));
    (*it)->setTextAlignment(3, Qt::AlignCenter);
    if (m_selectedAmountType == 0 && key == 'T' && m_inEdit) {
      (*it)->setSelected(true);
      slotAmountTypeSelected();
    } else if ((*it) == m_selectedAmountType) {
      (*it)->setSelected(true);
      slotAmountTypeSelected();
    }
    ++it;
  }
}

void MyMoneyQifProfileEditor::deleteProfile(const QString& name)
{
  KSharedConfigPtr config = KSharedConfig::openConfig();

  config->deleteGroup("Profile-" + name);

  KConfigGroup grp = config->group("Profiles");
  QStringList list = grp.readEntry("profiles", QStringList());
  list.removeAll(name);

  grp.writeEntry("profiles", list);
  m_isDirty = true;
}

void MyMoneyQifProfileEditor::addProfile(const QString& name)
{
  KSharedConfigPtr config = KSharedConfig::openConfig();
  KConfigGroup grp = config->group("Profiles");
  QStringList list = grp.readEntry("profiles", QStringList());

  list += name;
  list.sort();
  grp.writeEntry("profiles", list);

  m_profile.setProfileName("Profile-" + name);
  m_profile.saveProfile();

  m_isDirty = true;
}

void MyMoneyQifProfileEditor::slotReset()
{
  // first flush any changes
  m_profile.saveProfile();

  KSharedConfigPtr config = KSharedConfig::openConfig();
  config->reparseConfiguration();

  QString currentProfile = m_profile.profileName().mid(8);
  loadProfileListFromConfig();
  slotLoadProfileFromConfig(currentProfile);
  m_isDirty = false;
}

void MyMoneyQifProfileEditor::slotRename()
{
  bool ok;
  QString newName = enterName(ok);

  if (ok == true) {
    deleteProfile(m_profile.profileName().mid(8));
    addProfile(newName);
    loadProfileListFromConfig();
    slotLoadProfileFromConfig(newName);
  }
}

void MyMoneyQifProfileEditor::slotNew()
{
  bool ok;
  QString newName = enterName(ok);

  if (ok == true) {
    m_profile.clear();
    addProfile(newName);
    loadProfileListFromConfig();
    slotLoadProfileFromConfig(newName);
  }
}

const QString MyMoneyQifProfileEditor::enterName(bool& ok)
{
  MyMoneyQifProfileNameValidator val(this);
  QString rc;
  bool internalOk;

  do {
    rc = QInputDialog::getText(this, i18n("QIF Profile Editor"),
                               i18n("Enter new profile name"),
                               QLineEdit::Normal,
                               rc,
                               &internalOk);
    // if user pressed OK we check the name
    if (internalOk) {
      int pos = 0;
      if (val.validate(rc, pos) != MyMoneyQifProfileNameValidator::Acceptable) {
        QString errorMsg;
        if (rc.isEmpty()) {
          errorMsg = i18n("The profile name cannot be empty. Please provide a name or cancel.");
        } else {
          errorMsg = i18n("The name <b>%1</b> is already taken. Please change the name or cancel.", rc);
        }
        KMessageBox::sorry(this, errorMsg, i18n("QIF profile name problem"));
        continue;
      }
    }
    break;
  } while (true);

  ok = internalOk;
  return rc;
}

void MyMoneyQifProfileEditor::slotDelete()
{
  QString profile = m_profile.profileName().mid(8);

  if (KMessageBox::questionYesNo(this, i18n("Do you really want to delete profile '%1'?", profile)) == KMessageBox::Yes) {
    int idx = m_profileListBox->currentRow();
    m_profile.saveProfile();
    deleteProfile(profile);
    loadProfileListFromConfig();

    if (idx >= m_profileListBox->count())
      idx = m_profileListBox->count() - 1;

    m_profileListBox->setCurrentRow(idx);
    slotLoadProfileFromConfig(m_profileListBox->item(idx)->text());
  }
}

void MyMoneyQifProfileEditor::slotHelp()
{
  KHelpClient::invokeHelp("details.impexp.qifimp.profile");
}

void MyMoneyQifProfileEditor::slotAmountTypeSelected()
{
  QList<QTreeWidgetItem*> selectedItems = m_editAmounts->selectedItems();
  if (! selectedItems.empty()) {
    QTreeWidgetItem* item = selectedItems.at(0);
    m_decimalBox->setCurrentIndex(m_decimalBox->findText(item->text(2), Qt::MatchExactly));
    m_thousandsBox->setCurrentIndex(m_thousandsBox->findText(item->text(3), Qt::MatchExactly));
    m_selectedAmountType = item;
  }
}

void MyMoneyQifProfileEditor::slotDecimalChanged(const QString& val)
{
  if (m_selectedAmountType != 0) {
    QChar key = m_selectedAmountType->text(1)[0];
    m_profile.setAmountDecimal(key, val[0]);
    m_selectedAmountType->setText(2, val);
  }
}

void MyMoneyQifProfileEditor::slotThousandsChanged(const QString& val)
{
  if (m_selectedAmountType != 0) {
    QChar key = m_selectedAmountType->text(1)[0];
    m_profile.setAmountThousands(key, val[0]);
    m_selectedAmountType->setText(3, val);
  }
}

const QString MyMoneyQifProfileEditor::selectedProfile() const
{
  return m_profileListBox->currentItem()->text();
}
