/*
 * Copyright 2000-2002  Michael Edwardes <mte@users.sourceforge.net>
 * Copyright 2017       Ł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 "knewbankdlg.h"

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

#include <QPushButton>
#include <QTemporaryFile>
#include <QTimer>
#include <QDesktopServices>
#include <QRegularExpression>

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

#include <KMessageBox>
#include <KLineEdit>
#include <kguiutils.h>
#include <KLocalizedString>
#include <KIO/Scheduler>
#include <KIO/Job>
#include <KIOGui/KIO/FavIconRequestJob>

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

#include "ui_knewbankdlg.h"

#include "mymoneyinstitution.h"
#include "kmymoneyutils.h"
#include "icons.h"

#include <errno.h>

class KNewBankDlgPrivate
{
  Q_DISABLE_COPY(KNewBankDlgPrivate)

public:
  KNewBankDlgPrivate() :
    ui(new Ui::KNewBankDlg)
  {
    m_iconLoadTimer.setSingleShot(true);
  }

  ~KNewBankDlgPrivate()
  {
    delete ui;
  }

  Ui::KNewBankDlg*                  ui;
  MyMoneyInstitution                m_institution;
  QTimer                            m_iconLoadTimer;
  QPointer<KIO::FavIconRequestJob>  m_favIconJob;
  QIcon                             m_favIcon;
  QString                           m_iconName;
  QUrl                              m_url;
};

KNewBankDlg::KNewBankDlg(MyMoneyInstitution& institution, QWidget *parent) :
  QDialog(parent),
  d_ptr(new KNewBankDlgPrivate)
{
  Q_D(KNewBankDlg);
  d->ui->setupUi(this);
  d->m_institution = institution;
  setModal(true);

  d->ui->nameEdit->setFocus();
  d->ui->nameEdit->setText(institution.name());
  d->ui->cityEdit->setText(institution.city());
  d->ui->streetEdit->setText(institution.street());
  d->ui->postcodeEdit->setText(institution.postcode());
  d->ui->telephoneEdit->setText(institution.telephone());
  d->ui->sortCodeEdit->setText(institution.sortcode());
  d->ui->bicEdit->setText(institution.value(QStringLiteral("bic")));
  d->ui->urlEdit->setText(institution.value(QStringLiteral("url")));

  if (!institution.value(QStringLiteral("icon")).isEmpty()) {
    d->m_favIcon = Icons::loadIconFromApplicationCache(institution.value(QStringLiteral("icon")));
  }
  if (!d->m_favIcon.isNull()) {
    d->ui->iconButton->setEnabled(true);
    d->ui->iconButton->setIcon(d->m_favIcon);
  }

  d->ui->messageWidget->hide();

  connect(d->ui->buttonBox, &QDialogButtonBox::accepted, this, &KNewBankDlg::okClicked);
  connect(d->ui->buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
  connect(d->ui->nameEdit, &QLineEdit::textChanged, this, &KNewBankDlg::institutionNameChanged);
  connect(d->ui->urlEdit, &QLineEdit::textChanged, this, &KNewBankDlg::slotUrlChanged);
  connect(&d->m_iconLoadTimer, &QTimer::timeout, this, &KNewBankDlg::slotLoadIcon);
  connect(d->ui->iconButton, &QToolButton::pressed, this,
          [=] {
            QUrl url;
            url.setUrl(QString::fromLatin1("https://%1/").arg(d->ui->urlEdit->text()));
            QDesktopServices::openUrl(url);
          });

  institutionNameChanged(d->ui->nameEdit->text());
  slotUrlChanged(d->ui->urlEdit->text());

  auto requiredFields = new KMandatoryFieldGroup(this);
  requiredFields->setOkButton(d->ui->buttonBox->button(QDialogButtonBox::Ok)); // button to be enabled when all fields present
  requiredFields->add(d->ui->nameEdit);
}

void KNewBankDlg::institutionNameChanged(const QString &_text)
{
  Q_D(KNewBankDlg);
  d->ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!_text.isEmpty());
}

KNewBankDlg::~KNewBankDlg()
{
  Q_D(KNewBankDlg);
  delete d;
}

void KNewBankDlg::okClicked()
{
  Q_D(KNewBankDlg);
  if (d->ui->nameEdit->text().isEmpty()) {
    KMessageBox::information(this, i18n("The institution name field is empty.  Please enter the name."), i18n("Adding New Institution"));
    d->ui->nameEdit->setFocus();
    return;
  }

  d->m_institution.setName(d->ui->nameEdit->text());
  d->m_institution.setTown(d->ui->cityEdit->text());
  d->m_institution.setStreet(d->ui->streetEdit->text());
  d->m_institution.setPostcode(d->ui->postcodeEdit->text());
  d->m_institution.setTelephone(d->ui->telephoneEdit->text());
  d->m_institution.setSortcode(d->ui->sortCodeEdit->text());
  d->m_institution.setValue(QStringLiteral("bic"), d->ui->bicEdit->text());
  d->m_institution.setValue(QStringLiteral("url"), d->ui->urlEdit->text());
  d->m_institution.deletePair(QStringLiteral("icon"));

  if (d->ui->iconButton->isEnabled()) {
    d->m_institution.setValue(QStringLiteral("icon"), d->m_iconName);
    Icons::storeIconInApplicationCache(d->m_iconName, d->m_favIcon);
  }
  accept();
}

const MyMoneyInstitution& KNewBankDlg::institution()
{
  Q_D(KNewBankDlg);
  return d->m_institution;
}

void KNewBankDlg::newInstitution(MyMoneyInstitution& institution)
{
  institution.clearId();
  QPointer<KNewBankDlg> dlg = new KNewBankDlg(institution);
  if (dlg->exec() == QDialog::Accepted && dlg != 0) {
    institution = dlg->institution();
    KMyMoneyUtils::newInstitution(institution);
  }
  delete dlg;
}

void KNewBankDlg::slotUrlChanged(const QString& newUrl)
{
  Q_D(KNewBankDlg);

  // remove a possible leading protocol since we only provide https for now
  QRegularExpression protocol(QStringLiteral("^[a-zA-Z]+://(?<url>.*)"), QRegularExpression::CaseInsensitiveOption);
  QRegularExpressionMatch matcher = protocol.match(newUrl);
  if (matcher.hasMatch()) {
    d->ui->urlEdit->setText(matcher.captured(QStringLiteral("url")));
    d->ui->messageWidget->setText(QLatin1String("The protocol part has been removed by KMyMoney because it is fixed to https."));
    d->ui->messageWidget->setMessageType(KMessageWidget::Information);
    d->ui->messageWidget->animatedShow();
  }
  d->m_iconLoadTimer.start(200);
}

void KNewBankDlg::slotLoadIcon()
{
  Q_D(KNewBankDlg);

  // if currently a check is running, retry later
  if (d->m_favIconJob) {
    d->m_iconLoadTimer.start(200);
    return;
  }

  const auto path = d->ui->urlEdit->text();
  QRegularExpression urlRe(QStringLiteral("^(.*\\.)?[^\\.]{2,}\\.[a-z]{2,}"), QRegularExpression::CaseInsensitiveOption);
  QRegularExpressionMatch matcher = urlRe.match(path);
  d->ui->iconButton->setEnabled(false);

  if (matcher.hasMatch()) {
    d->ui->iconButton->setEnabled(true);
    d->m_url = QUrl(QString::fromLatin1("https://%1").arg(path));
    KIO::Scheduler::checkSlaveOnHold(true);
    d->m_favIconJob = new KIO::FavIconRequestJob(d->m_url);
    connect(d->m_favIconJob, &KIO::FavIconRequestJob::result, this, &KNewBankDlg::slotIconLoaded);
    // we force to end the job after 1 second to avoid blocking this mechanism in case the thing fails
    QTimer::singleShot(1000, this, &KNewBankDlg::killIconLoad);
  }
}

void KNewBankDlg::killIconLoad()
{
  Q_D(KNewBankDlg);
  if (d->m_favIconJob) {
    d->m_favIconJob->kill();
    d->m_favIconJob->deleteLater();
  }
}

void KNewBankDlg::slotIconLoaded(KJob* job)
{
  Q_D(KNewBankDlg);

  switch(job->error()) {
    case ECONNREFUSED:
      // There is an answer from the server, but no favicon. In case we
      // already have one, we keep it
      d->ui->iconButton->setEnabled(true);
      d->m_favIcon = Icons::get(Icons::Icon::ViewBank);
      d->m_iconName = QStringLiteral("enum:ViewBank");
      break;
    case 0:
      // There is an answer from the server, and the favicon is found
      d->ui->iconButton->setEnabled(true);
      d->m_favIcon = QIcon(dynamic_cast<KIO::FavIconRequestJob*>(job)->iconFile());
      d->m_iconName = QStringLiteral("favicon:%1").arg(d->m_url.host());
      break;
    default:
      // There is problem with the URL from
      qDebug() << "KIO::FavIconRequestJob error" << job->error();
      // intentional fall through

    case EALREADY:    // invalid URL, no server response
      d->ui->iconButton->setEnabled(false);
      d->m_favIcon = QIcon();
      d->m_iconName.clear();
      break;
  }
  d->ui->iconButton->setIcon(d->m_favIcon);
}
