/*
 * mainwindow.cpp - plugin
 * Copyright (C) 2010  Evgeny Khryukin
 *
 * 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 <https://www.gnu.org/licenses/>.
 *
 */

#include "mainwindow.h"

#include <QFileDialog>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QTextCodec>
#endif
#include <QTextStream>

using namespace Chess;

SelectFigure::SelectFigure(const QString &player, QWidget *parent) : QWidget(parent)
{
    setAttribute(Qt::WA_DeleteOnClose);
    setWindowModality(Qt::WindowModal);
    setFixedSize(62, 62);
    setStyleSheet("QPushButton { background-color: #e9edff;}"
                  "QPushButton:hover { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e9edff, "
                  "stop: 1 black)}");
    QGridLayout *layout = new QGridLayout(this);
    tb_queen            = new QPushButton(this);
    tb_castle           = new QPushButton(this);
    tb_knight           = new QPushButton(this);
    tb_bishop           = new QPushButton(this);
    tb_queen->setFixedSize(25, 25);
    tb_queen->setObjectName("queen");
    tb_castle->setFixedSize(25, 25);
    tb_castle->setObjectName("rook");
    tb_knight->setFixedSize(25, 25);
    tb_knight->setObjectName("knight");
    tb_bishop->setFixedSize(25, 25);
    tb_bishop->setObjectName("bishop");
    if (player == "white") {
        tb_queen->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_queen.png")
                                    .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
        tb_castle->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_castle.png")
                                     .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
        tb_knight->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_knight.png")
                                     .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
        tb_bishop->setIcon(QIcon(QPixmap(":/chessplugin/figures/white_bishop.png")
                                     .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
    } else {
        tb_queen->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_queen.png")
                                    .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
        tb_castle->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_castle.png")
                                     .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
        tb_knight->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_knight.png")
                                     .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
        tb_bishop->setIcon(QIcon(QPixmap(":/chessplugin/figures/black_bishop.png")
                                     .scaled(22, 22, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
    }

    layout->addWidget(tb_queen, 0, 0);
    layout->addWidget(tb_castle, 1, 0);
    layout->addWidget(tb_knight, 0, 1);
    layout->addWidget(tb_bishop, 1, 1);

    connect(tb_queen, &QPushButton::clicked, this, &SelectFigure::figureSelected);
    connect(tb_castle, &QPushButton::clicked, this, &SelectFigure::figureSelected);
    connect(tb_knight, &QPushButton::clicked, this, &SelectFigure::figureSelected);
    connect(tb_bishop, &QPushButton::clicked, this, &SelectFigure::figureSelected);
}

void SelectFigure::figureSelected()
{
    QString objectName = sender()->objectName();
    emit    newFigure(objectName);
    close();
}

//-------------------------
//----ChessWindow----------
//-------------------------
ChessWindow::ChessWindow(Figure::GameType type, bool enableSound_, QWidget *parent) :
    QMainWindow(parent), enabledSound(enableSound_), movesCount(0)
{
    ui_.setupUi(this);
    setAttribute(Qt::WA_DeleteOnClose);
    setFixedSize(610, 555);
    setWindowIcon(QIcon(QPixmap(":/chessplugin/figures/Chess.png")));
    setStyleSheet("QMainWindow *{background-color: #ffffe7; color: black; }"
                  "QMenu  {background-color: #ffa231;}"
                  "QMenu::item { background-color: #ffa231; padding: 1px; padding-right: 5px; padding-left: 18px; }"
                  "QMenu::item:selected:!disabled {background-color: #ffeeaf; border: 1px solid #74440e; }"
                  "QMenu::item:disabled {color: #646464; }"
                  "QMenu::separator { height: 2px; background: yellow;}"
                  "QMenu::item:checked { background-color: #ffeeaf;}"
                  "QPushButton { background-color: #e9edff;}"
                  "QPushButton:hover { background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #e9edff, "
                  "stop: 1 black)}");

    model_ = new BoardModel(type, this);
    model_->reset();
    ui_.tv_board->setModel(model_);
    if (type == Figure::WhitePlayer)
        ui_.tv_board->setCurrentIndex(model_->kingIndex());
    else
        ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex()));

    ui_.te_moves->setText(tr("    White    Black\n"));

    connect(model_, &BoardModel::move, this, &ChessWindow::move);
    connect(model_, &BoardModel::move, this, &ChessWindow::addMove);
    connect(model_, &BoardModel::figureKilled, this, &ChessWindow::figureKilled);
    connect(model_, &BoardModel::needNewFigure, this, &ChessWindow::needNewFigure);

    createMenu();
}

void ChessWindow::closeEvent(QCloseEvent *e)
{
    e->ignore();
    emit closeBoard();
}

void ChessWindow::moveRequest(int oldX, int oldY, int newX, int newY, const QString &figure)
{
    bool b = model_->moveRequested(oldX, oldY, newX, newY);
    ui_.tv_board->viewport()->update();
    if (!b)
        emit error();
    else {
        emit moveAccepted();
        addMove(oldX, oldY, newX, newY);
    }
    if (!figure.isEmpty())
        model_->updateFigure(model_->index(7 - newY, newX), figure); // 7- - for compatibility with tkabber

    int state = model_->checkGameState();
    if (state == 2)
        emit lose();
    else if (state == 1)
        emit draw();
}

void ChessWindow::addMove(int oldX, int oldY, int newX, int newY)
{
    Figure *f = nullptr;
    if (model_->gameType_ == Figure::WhitePlayer) { // for compatibility with tkabber
        oldY = 7 - oldY;
        newY = 7 - newY;
        f    = model_->findFigure(model_->index(newY, newX));
    } else if (model_->gameType_ == Figure::BlackPlayer) {
        f    = model_->findFigure(model_->index(7 - newY, newX));
        oldX = 7 - oldX;
        newX = 7 - newX;
    }

    QString type = " ";
    if (f)
        type = f->typeString();

    QString text       = ui_.te_moves->toPlainText();
    int     moveNumber = movesCount + 2;
    if (moveNumber & 1) {
        text += QString("   ") + type[0] + model_->headerData(oldX, Qt::Horizontal).toString().toLower()
            + model_->headerData(oldY, Qt::Vertical).toString() + "-"
            + model_->headerData(newX, Qt::Horizontal).toString().toLower()
            + model_->headerData(newY, Qt::Vertical).toString() + "\n";
    } else {
        text += QString::number(moveNumber / 2) + ". " + type[0]
            + model_->headerData(oldX, Qt::Horizontal).toString().toLower()
            + model_->headerData(oldY, Qt::Vertical).toString() + "-"
            + model_->headerData(newX, Qt::Horizontal).toString().toLower()
            + model_->headerData(newY, Qt::Vertical).toString();
    }

    ui_.te_moves->setText(text);
    QTextCursor cur = ui_.te_moves->textCursor();
    cur.setPosition(text.length());
    ui_.te_moves->setTextCursor(cur);
    movesCount++;
}

void ChessWindow::createMenu()
{
    QMenuBar *menuBar = ui_.menubar;
    menuBar->setStyleSheet(
        "QMenuBar::item {background-color: #ffffe7; border-radius: 1px; border: 1px solid #74440e; color: black;"
        "spacing: 10px; padding: 1px 4px; background: transparent; }"
        "QMenuBar::item:selected { background-color: #ffeeaf; color: black;  }"
        "QMenuBar::item:pressed { background: #ffeeaf; color: black;  }");

    QAction *loadAction  = new QAction(tr("Load game"), menuBar);
    QAction *saveAction  = new QAction(tr("Save game"), menuBar);
    QAction *quitAction  = new QAction(tr("Quit"), menuBar);
    loseAction           = new QAction(tr("Resign"), menuBar);
    QAction *soundAction = new QAction(tr("Enable sound"), menuBar);
    soundAction->setCheckable(true);
    soundAction->setChecked(enabledSound);

    QMenu *fileMenu = menuBar->addMenu(tr("File"));
    QMenu *gameMenu = menuBar->addMenu(tr("Game"));

    fileMenu->addAction(loadAction);
    fileMenu->addAction(saveAction);
    fileMenu->addSeparator();
    fileMenu->addAction(quitAction);
    gameMenu->addAction(loseAction);
    gameMenu->addSeparator();
    gameMenu->addAction(soundAction);

    // TODO: update after stopping support of Ubuntu Xenial:
    connect(loadAction, SIGNAL(triggered()), this, SLOT(load()));

    connect(saveAction, &QAction::triggered, this, &ChessWindow::save);
    connect(quitAction, &QAction::triggered, this, &ChessWindow::close, Qt::QueuedConnection);
    connect(loseAction, &QAction::triggered, this, &ChessWindow::lose);
    connect(soundAction, &QAction::triggered, this, &ChessWindow::toggleEnableSound);
}

void ChessWindow::load()
{
    QString fileName = QFileDialog::getOpenFileName(nullptr, tr("Load game"), "", tr("*.chs"));
    if (fileName.isEmpty())
        return;

    QFile file(fileName);
    if (file.open(QIODevice::ReadOnly)) {
        QTextStream in(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        in.setCodec("UTF-8");
#else
        in.setEncoding(QStringConverter::Utf8);
#endif
        QString settings = in.readAll();
        model_->loadSettings(settings);
        if (model_->gameType_ == Figure::WhitePlayer)
            ui_.tv_board->setCurrentIndex(model_->kingIndex());
        else
            ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex()));

        emit load(settings);
        ui_.te_moves->setText(tr("  White     Black\n"));
        movesCount = 0;
    }
}

void ChessWindow::loadRequest(const QString &settings)
{
    model_->loadSettings(settings, false);
    if (model_->gameType_ == Figure::WhitePlayer)
        ui_.tv_board->setCurrentIndex(model_->kingIndex());
    else
        ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex()));

    ui_.te_moves->setText(tr("  White     Black\n"));
    movesCount = 0;
}

void ChessWindow::save()
{
    QString fileName = QFileDialog::getSaveFileName(nullptr, tr("Save game"), "", tr("*.chs"));
    if (fileName.isEmpty())
        return;
    if (fileName.right(4) != ".chs")
        fileName.append(".chs");

    QFile file(fileName);
    if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
        QTextStream out(&file);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
        out.setCodec("UTF-8");
#else
        out.setEncoding(QStringConverter::Utf8);
#endif
        out.setGenerateByteOrderMark(false);
        out << model_->saveString();
    }
}

void ChessWindow::figureKilled(Figure *figure)
{
    QPixmap pix   = figure->getPixmap().scaled(24, 24, Qt::KeepAspectRatio, Qt::SmoothTransformation);
    QLabel *label = new QLabel;
    label->setFixedSize(24, 24);
    label->setPixmap(pix);
    if (figure->gameType() == Figure::WhitePlayer) {
        ui_.white_layout->addWidget(label);
        if (!model_->myMove)
            ui_.tv_board->setCurrentIndex(model_->kingIndex());
    } else {
        ui_.black_layout->addWidget(label);
        if (!model_->myMove)
            ui_.tv_board->setCurrentIndex(model_->invert(model_->kingIndex()));
    }
}

void ChessWindow::needNewFigure(QModelIndex index, const QString &player)
{
    tmpIndex_ = index;
    if (model_->gameType_ == Figure::BlackPlayer)
        index = model_->invert(index);

    SelectFigure *sf  = new SelectFigure(player, this);
    QPoint        pos = ui_.tv_board->pos();
    pos.setX(pos.x() + index.column() * 50 + 4);
    pos.setY(pos.y() + index.row() * 50 + 25);
    sf->move(pos);
    connect(sf, &SelectFigure::newFigure, this, &ChessWindow::newFigure);
    sf->show();
}

void ChessWindow::newFigure(QString figure) { model_->updateFigure(tmpIndex_, figure); }

void ChessWindow::youWin()
{
    model_->gameState_ = 2;
    model_->updateView();
    loseAction->setEnabled(false);
}

void ChessWindow::youLose()
{
    model_->gameState_ = 3;
    model_->updateView();
}

void ChessWindow::youDraw()
{
    model_->gameState_ = 1;
    model_->updateView();
}
