/** Copyright (c) 2020-2022 The Creators of Simphone

    class Login (LoginDialog): input secret key

    See the file COPYING.LESSER.txt for copying permission.
**/

#include "login.h"
#include "ui_login.h"

#include "qtfix.h"
#include "simcore.h"

static const char * countries[] = {
  "Afghanistan", "Algeria", "Angola", "Argentina", "Australia", "Azerbaijan", "Bangladesh", "Belgium",
  "Benin", "Bolivia", "Brazil", "Burundi", "Cambodia", "Cameroon", "Canada", "China",
  "Colombia", "Cuba", "Egypt", "Ethiopia", "Ghana", "Greece", "Guatemala", "Haiti",
  "Honduras", "Hungary", "India", "Iran", "Japan", "Jordan", "Kazakhstan", "Korea",
  "Madagascar", "Malawi", "Malaysia", "Mexico", "Morocco", "Mozambique", "Myanmar", "Nepal",
  "Nigeria", "Pakistan", "Peru", "Philippines", "Poland", "Portugal", "Romania", "Russia",
  "Rwanda", "Senegal", "Somalia", "Spain", "Sudan", "Tanzania", "Thailand", "Tunisia",
  "Turkey", "Uganda", "Ukraine", "Uzbekistan", "Venezuela", "Vietnam", "Zambia", "Zimbabwe"
};

static const int numbers[] = {
  1, 12, 23, 34, 45, 56, 67, 78,
  103, 114, 125, 136, 147, 158, 169, 171,
  205, 216, 227, 238, 249, 251, 262, 273,
  307, 318, 329, 331, 342, 353, 364, 375,
  409, 411, 422, 433, 444, 455, 466, 477,
  502, 513, 524, 535, 546, 557, 568, 579,
  604, 615, 626, 637, 648, 659, 661, 672,
  706, 717, 728, 739, 741, 752, 763, 774
};

Login::Login(QWidget * parent, const char * key)
  : Parent(parent), ui(new Ui::Login), m_password(!key), m_sorted(true), m_format(SimParam::get("ui.login.countries"))
{
  ui->setupUi(this);
  initLanguage(ui->actionEnglish, ui->actionFrench, ui->actionGerman);
  ui->menubar->adjustSize();
  ui->menubar->resize(width(), ui->menubar->height());
  //qtfix::adjustVerticalSize(ui->menubar);
  qtfix::fixPointSize(ui->loginButton, font().pointSize(), 15);
  qtfix::fixPointSize(ui->loginTable, font().pointSize());
  qtfix::fixCheckBoxIcon(ui->showKeyBox, font());

  for (unsigned i = 0; i < SIM_ARRAY_SIZE(m_sortIndex); i++) m_sortIndex[i] = i;

  if (m_password) {
    ui->loginButton->setText(tr(" Encrypt my key "));
    ui->menubar->hide();
  }

  setFormat();
  if (!ui->keyEdit->isEnabled()) ui->loginButton->setFocus();

  m_oldFont = ui->keyEdit->font();
  m_newFont = qtfix::createPasswordFont(m_oldFont.pointSize(), &m_fontId);
  if (SimParam::get("ui.login.showpass")) {
    ui->showKeyBox->setChecked(true);
  } else {
    ui->keyEdit->setFont(*m_newFont);
  }

  connect(ui->showKeyBox, SIGNAL(toggled(bool)), this, SLOT(onShowPassToggled(bool)));
  connect(ui->loginTable, SIGNAL(clicked(const QModelIndex &)), this, SLOT(onItemClicked(const QModelIndex &)));
  //setWindowFlags(Qt::MSWindowsFixedSizeDialogHint);

  ui->keyEdit->setPlainText(key);
  QTextCursor cursor = ui->keyEdit->textCursor();
  cursor.movePosition(QTextCursor::End);
  ui->keyEdit->setTextCursor(cursor);

  ui->keyEdit->installEventFilter(this);

  adjustToBiggerSize();
}

Login::~Login()
{
  ui->keyEdit->removeEventFilter(this);
  qtfix::removePasswordFont(m_fontId);
  delete m_newFont;
  delete ui;
}

void Login::setFormat()
{
  int cc = m_format == 2 ? 6 : m_format == 1 ? 8 : 4;

  if (m_format) {
    QPalette pal = ui->loginTable->palette();
    simtype versions = sim_list_versions();
    QString version = sim_table_get_pointer(versions, SIM_VERSION_BAD);
    sim_list_free(versions);

    if (!getRandom(0)) {
      ui->shuffleButton->setText(m_sorted ? tr("Shuffle") : tr("Sort"));
      ui->shuffleButton->show();
    } else {
      ui->shuffleButton->hide();
    }
    ui->label->hide();
    ui->keyLabel->hide();
    if (!version.isEmpty()) {
      ui->keyEdit->setEnabled(false);
      ui->countryLabelNames->hide();
      ui->countryLabelFlags->hide();
      ui->countryLabel->show();
    } else {
      ui->countryLabel->hide();
      if (m_format == 2) {
        ui->countryLabelFlags->hide();
        ui->countryLabelNames->show();
      } else {
        ui->countryLabelNames->hide();
        ui->countryLabelFlags->show();
      }
    }

    pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Window));
    pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Window));
    ui->loginTable->setPalette(pal);
    ui->loginTable->setColumnCount(cc);
    ui->loginTable->setRowCount(int(SIM_ARRAY_SIZE(countries)) / cc + (int(SIM_ARRAY_SIZE(countries)) % cc != 0));

    int indexes[SIM_ARRAY_SIZE(countries)];
    QStringList list;
    QString max;
    for (int i = 0; i < int(SIM_ARRAY_SIZE(countries)); i++) {
      list.append(qApp->translate("SimCountry", countries[i]).split(' ').join(""));
    }
    for (int i = 0; i < list.size(); i++) {
      int n = list.size();
      QString min;
      for (int j = 0; j < list.size(); j++) {
        if (min.isNull() || list[j].localeAwareCompare(min) < 0) {
          if (max.isNull() || list[j].localeAwareCompare(max) > 0) min = list[n = j];
        }
      }
      max = min;
      indexes[i] = n;
    }

    for (int i = 0; i < list.size(); i++) {
      int j = m_sortIndex[m_format & 2 ? indexes[i] : i];
      QString qs;
      QPixmap pixmap;
      if (j < list.size()) {
        QTableWidgetItem * item = new QTableWidgetItem(m_format & 2 ? list[j] : qs.sprintf("%03d", numbers[j]));
        if (m_format & 1) {
          pixmap.load(QString(":/") + (strcmp(countries[j], "Korea") ? countries[j] : "South Korea"));
          QVariant var(qtfix::fixPixmapSize(pixmap, QFontMetrics(ui->loginTable->font()).ascent(), true));
          item->setData(Qt::DecorationRole, var);
        }
        ui->loginTable->setItem(i / cc, i % cc, item);
      }
    }
    ui->loginTable->show();
    ui->loginTable->resizeColumnsToContents();
    ui->loginTable->resizeRowsToContents();
  } else {
    ui->shuffleButton->hide();
    ui->keyEdit->setEnabled(true);
    ui->countryLabel->hide();
    ui->countryLabelNames->hide();
    ui->countryLabelFlags->hide();
    ui->keyLabel->show();
    ui->loginTable->hide();
    //int width = width() - ui->horizontalSpacer_3->sizeHint().width() -  ui->horizontalSpacer_4->sizeHint().width();
    ui->label->setPixmap(QPixmap(":/welcome") /*.scaledToWidth(width() - 80, Qt::SmoothTransformation)*/);
    ui->label->show();
  }
}

QString Login::getKey() const
{
  return ui->keyEdit->toPlainText();
}

QString Login::translateKey(const QString & key)
{
  QStringList list = key.split(QRegExp("\\s|-"), QString::SkipEmptyParts);

  for (int i = 0; i < list.size(); i++) {
    for (int j = 0; j < int(SIM_ARRAY_SIZE(countries)); j++) {
      if (!qApp->translate("SimCountry", countries[j]).split(' ').join("").compare(list[i], Qt::CaseInsensitive)) {
        list[i] = countries[j];
      }
    }
  }
  return list.join('-');
}

void Login::changeEvent(QEvent * event)
{
  if (event->type() == QEvent::LanguageChange) {
    ui->retranslateUi(this);
    ui->label->setPixmap(QPixmap(":/welcome"));
    setFormat();
  }
  Parent::changeEvent(event);
}

void Login::onShowPassToggled(bool show)
{
  SimParam::set("ui.login.showpass", show, false);
  ui->keyEdit->setFont(show ? m_oldFont : *m_newFont);
  QTextCursor cursor = ui->keyEdit->textCursor();
  ui->keyEdit->selectAll();
  ui->keyEdit->setTextCursor(cursor);
  ui->keyEdit->setFocus();
}

void Login::onItemClicked(const QModelIndex & index)
{
  if (index.row() * ui->loginTable->columnCount() + index.column() < int(SIM_ARRAY_SIZE(countries))) {
    QVariant var = ui->loginTable->item(index.row(), index.column())->data(Qt::DisplayRole);

    ui->keyEdit->insertPlainText(var.toString() + "-");
  } else {
    ui->loginTable->selectionModel()->clearSelection();
  }
}

void Login::on_shuffleButton_clicked()
{
  m_sorted = !m_sorted;

  QList<int> list;
  for (unsigned i = 0; i < SIM_ARRAY_SIZE(m_sortIndex); i++) list.append(i);
  for (unsigned i = 0; i < SIM_ARRAY_SIZE(m_sortIndex); i++) {
    unsigned n = 0;
    if (!m_sorted) {
      do {
        n = unsigned(getRandom(SIM_ARRAY_SIZE(m_sortIndex) - 1));
        if (n >= SIM_ARRAY_SIZE(m_sortIndex)) n = 0;
      } while (n >= unsigned(list.size()));
    }
    m_sortIndex[i] = list.takeAt(n);
  }
  setFormat();
}

void Login::on_formatButton_clicked()
{
  SimParam::set("ui.login.countries", m_format = m_format ^ 3, false);
  setFormat();
}

void Login::on_loginButton_clicked()
{
  if (m_password) {
    QString qs = translateKey(getKey());
    int simres = sim_key_set_password_(qs.toUtf8().data(), SIM_PASSWORD_BIT_CHECK);

    if (simres == SIM_OK) simres = sim_key_set_password_(qs.toUtf8().data(), SIM_PASSWORD_BIT_OVERWRITE);
    if (simres != SIM_OK) {
      SimCore::execMessageBox(true, tr("Setting password not successful (%1)").arg(simres), SimCore::getError(simres));
      return;
    }
  }

  accept();
}

void Login::on_generateButton_clicked()
{
  done(2);
}

void Login::on_actionEnglish_triggered()
{
  Parent::on_actionEnglish_triggered(ui->actionEnglish, ui->actionFrench, ui->actionGerman);
}

void Login::on_actionFrench_triggered()
{
  Parent::on_actionFrench_triggered(ui->actionEnglish, ui->actionFrench, ui->actionGerman);
}

void Login::on_actionGerman_triggered()
{
  Parent::on_actionGerman_triggered(ui->actionEnglish, ui->actionFrench, ui->actionGerman);
}

bool Login::checkKey(QKeyEvent * event)
{
  if (!(event->modifiers() & (Qt::AltModifier | Qt::MetaModifier | Qt::ControlModifier))) {
    switch (event->key()) {
      case Qt::Key_Return:
      case Qt::Key_Enter:
        on_loginButton_clicked();
        return true;
      case Qt::Key_Escape:
      case Qt::Key_Backspace:
        QTextCursor cursor = ui->keyEdit->textCursor();

        if (cursor.atEnd() && ui->keyEdit->toPlainText().endsWith('-')) {
          cursor.clearSelection();
          if (cursor.movePosition(QTextCursor::PreviousWord, QTextCursor::KeepAnchor, 2)) {
            cursor.deleteChar();
            ui->keyEdit->setTextCursor(cursor);
            return true;
          }
        }
    }
  }

  return m_password ? false : Parent::checkKey(event);
}

void Login::keyPressEvent(QKeyEvent * event)
{
  if (!m_password) Parent::keyPressEvent(event);
}

qulonglong Login::getRandom(qulonglong max)
{
  qulonglong n = 0;
  return sim_random_get((simbyte *)&n, sizeof(n)) == SIM_OK ? n % (max + 1) : max + 1;
}
