/*
 * Kylin-video
 *
 * Copyright (C) 2021, Tianjin KYLIN Information Technology Co., Ltd.
 *
 * 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 3 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/>.
 *
 * Authors: Liu Cong <liucong1@kylinos.cn>
 *
 */

#include "setupshortcut.h"
#include "ui_setupshortcut.h"

#include <QLabel>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QScrollBar>
#include <QDebug>
#include <QKeyEvent>

#include "global/global.h"

using namespace Global;

QSet<QString> SetupShortcut::key_set;
QString regKeyString(QString key){
    if(key.endsWith("PgUp"))
        key.replace("PgUp", "Page Up");
    else if(key.endsWith("PgDown"))
        key.replace("PgDown", "Page Down");
    else if(key.endsWith("Return"))
        key.replace("Return", "Enter");
    else if(key.endsWith("空格"))
        key.replace("空格", "Space");
    else if(key.endsWith("{"))
        key.replace("{", "[");
    else if(key.endsWith("}"))
        key.replace("}", "]");
    else if(key.endsWith("~"))
        key.replace("~", "`");
    else if(key.endsWith("!"))
        key.replace("!", "1");
    else if(key.endsWith("@"))
        key.replace("@", "2");
    else if(key.endsWith("#"))
        key.replace("#", "3");
    else if(key.endsWith("$"))
        key.replace("$", "4");
    else if(key.endsWith("%"))
        key.replace("%", "5");
    else if(key.endsWith("^"))
        key.replace("^", "6");
    else if(key.endsWith("&"))
        key.replace("&", "7");
    else if(key.endsWith("*"))
        key.replace("*", "8");
    else if(key.endsWith("("))
        key.replace("(", "9");
    else if(key.endsWith(")"))
        key.replace(")", "0");
    else if(key.endsWith("_"))
        key.replace("_", "-");
    else if(key.endsWith("+")) {
        key.chop(1);
        key.append("=");
    }
    else if(key.endsWith("|"))
        key.replace("|", "\\");
    else if(key.endsWith(":"))
        key.replace(":", ";");
    else if(key.endsWith(":"))
        key.replace(":", ";");
    else if(key.endsWith("\""))
        key.replace("\"", "\'");
    else if(key.endsWith("<"))
        key.replace("<", ",");
    else if(key.endsWith(">"))
        key.replace(">", ".");
    else if(key.endsWith("?"))
        key.replace("?", "/");
    key.replace("+", " + ");
    return key;
}

SetupShortcut::SetupShortcut(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SetupShortcut)
{
    ui->setupUi(this);

    initListTitle();
    initFileShortCut();
    initPlayShortCut();
    initImageShortCut();
    initVolumeShortCut();
    initSubtitleShortCut();
    initOtherShortCut();

    ui->list_flie->verticalScrollBar()->setProperty("drawScrollBarGroove", false);
    ui->list_play->verticalScrollBar()->setProperty("drawScrollBarGroove", false);
    ui->list_image->verticalScrollBar()->setProperty("drawScrollBarGroove", false);
    ui->list_subtitle->verticalScrollBar()->setProperty("drawScrollBarGroove", false);
    ui->list_volume->verticalScrollBar()->setProperty("drawScrollBarGroove", false);
    ui->list_other->verticalScrollBar()->setProperty("drawScrollBarGroove", false);
}

SetupShortcut::~SetupShortcut()
{
    delete ui;
}

void SetupShortcut::setBlackTheme()
{
    for(int i=0; i<ui->list_flie->count(); i++)
        ((ShortCutItem*)ui->list_flie->itemWidget(ui->list_flie->item(i)))->setBlackTheme();
    for(int i=0; i<ui->list_play->count(); i++)
        ((ShortCutItem*)ui->list_play->itemWidget(ui->list_play->item(i)))->setBlackTheme();
    for(int i=0; i<ui->list_image->count(); i++)
        ((ShortCutItem*)ui->list_image->itemWidget(ui->list_image->item(i)))->setBlackTheme();
    for(int i=0; i<ui->list_volume->count(); i++)
        ((ShortCutItem*)ui->list_volume->itemWidget(ui->list_volume->item(i)))->setBlackTheme();
    for(int i=0; i<ui->list_subtitle->count(); i++)
        ((ShortCutItem*)ui->list_subtitle->itemWidget(ui->list_subtitle->item(i)))->setBlackTheme();
    for(int i=0; i<ui->list_other->count(); i++)
        ((ShortCutItem*)ui->list_other->itemWidget(ui->list_other->item(i)))->setBlackTheme();

    ui->list_title->setStyleSheet("QListWidget{background-color: rgba(1,1,1,0);border-radius:10px;}"
                                  "QListWidget::item{border-radius:12px;color:#8c8c8c;}"
                                  "QListWidget::item::selected{background-color:rgba(1,1,1,0);color:rgb(55,144,250);}"
                                  "QListWidget::item::hover{background-color:#333333;}");
}

void SetupShortcut::setLightTheme()
{
    for(int i=0; i<ui->list_flie->count(); i++)
        ((ShortCutItem*)ui->list_flie->itemWidget(ui->list_flie->item(i)))->setLightTheme();
    for(int i=0; i<ui->list_play->count(); i++)
        ((ShortCutItem*)ui->list_play->itemWidget(ui->list_play->item(i)))->setLightTheme();
    for(int i=0; i<ui->list_image->count(); i++)
        ((ShortCutItem*)ui->list_image->itemWidget(ui->list_image->item(i)))->setLightTheme();
    for(int i=0; i<ui->list_volume->count(); i++)
        ((ShortCutItem*)ui->list_volume->itemWidget(ui->list_volume->item(i)))->setLightTheme();
    for(int i=0; i<ui->list_subtitle->count(); i++)
        ((ShortCutItem*)ui->list_subtitle->itemWidget(ui->list_subtitle->item(i)))->setLightTheme();
    for(int i=0; i<ui->list_other->count(); i++)
        ((ShortCutItem*)ui->list_other->itemWidget(ui->list_other->item(i)))->setLightTheme();

    ui->list_title->setStyleSheet("QListWidget{background-color: rgba(1,1,1,0);border-radius:10px;}"
                                  "QListWidget::item{border-radius:12px;color:#8c8c8c;}"
                                  "QListWidget::item::selected{background-color:rgba(1,1,1,0);color:rgb(55,144,250);}"
                                  "QListWidget::item::hover{background-color:#f5f5f5;}");
}

void SetupShortcut::flushChange()
{
    for(std::pair<QString, QString> p : chg_map)
    {
        QString useless_key = gshortCut->resetShort(p.first, p.second);
        key_set.insert(regKeyString(p.second));
        key_set.remove(regKeyString(useless_key));
    }
    foreach (auto item, item_set) {
        item->flush();
    }
    chg_map.clear();
}

void SetupShortcut::clearChange()
{
    chg_map.clear();
    foreach (auto item, item_set) {
        item->reset();
    }
}

void SetupShortcut::setWidgetFont(QString family, int size)
{
    QFont f(family);
    f.setPointSize(size);
    foreach (auto item, item_set) {
        item->setWidgetFont(f);
    }

    ui->list_title->setFont(f);
}

void SetupShortcut::initListTitle()
{
    ui->list_title->setFlow(QListView::LeftToRight);
    ui->list_title->addItems(QStringList() <<
                             tr("file") <<
                             tr("play") <<
                             tr("image") <<
                             tr("audio") <<
                             tr("sub") <<
                             tr("other"));

    for(int i=0; i<ui->list_title->count(); i++)
    {
        QListWidgetItem *it = ui->list_title->item(i);
        it->setTextAlignment(Qt::AlignCenter);
        it->setSizeHint(QSize(60, 24));
    }
    ui->list_title->setCurrentRow(0);
    ui->list_title->setSpacing(3);

    ui->list_flie->setSpacing(10);
    ui->list_flie->setStyleSheet(ListWidgetStyle);
    ui->list_flie->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    ui->list_play->setSpacing(10);
    ui->list_play->setStyleSheet(ListWidgetStyle);
    ui->list_play->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    ui->list_image->setSpacing(10);
    ui->list_image->setStyleSheet(ListWidgetStyle);
    ui->list_image->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    ui->list_volume->setSpacing(10);
    ui->list_volume->setStyleSheet(ListWidgetStyle);
    ui->list_volume->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    ui->list_subtitle->setSpacing(10);
    ui->list_subtitle->setStyleSheet(ListWidgetStyle);
    ui->list_subtitle->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    ui->list_other->setSpacing(10);
    ui->list_other->setStyleSheet(ListWidgetStyle);
    ui->list_other->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);


    QFont f("Noto Sans CJK SC Regular");
    f.setPixelSize(14);
    ui->list_title->setFont(f);


    initConnect();
}

void SetupShortcut::initConnect()
{
    connect(ui->list_title, &QListWidget::currentRowChanged, ui->stackedWidget, &QStackedWidget::setCurrentIndex);
}

void SetupShortcut::initFileShortCut()
{
    // key item
    for(std::pair<void(*)(), QShortcut*> pair : gshortCut->get_short_map())
    {
        // 防止快捷键 new 失败导致崩溃
        if(pair.second == nullptr)
            continue;
        if(pair.second->objectName() == tr("open file") ||
            pair.second->objectName() == tr("open dir") ||
            pair.second->objectName() == tr("prev file") ||
            pair.second->objectName() == tr("next file"))
        {
            QString shortKey = regKeyString(pair.second->key().toString());
            key_set.insert(shortKey);
            QListWidgetItem *it = new QListWidgetItem;
            it->setSizeHint(QSize(400, 30));
            ShortCutItem *itemw = new ShortCutItem(pair.second->objectName(), shortKey, this);
            item_set.insert(itemw);
            connect(itemw, &ShortCutItem::sigKeyChange, this, &SetupShortcut::slotChangeKeyCache);
            ui->list_flie->addItem(it);
            ui->list_flie->setItemWidget(it, itemw);
        }
    }
}

void SetupShortcut::initPlayShortCut()
{
    // key item
    for(std::pair<void(*)(), QShortcut*> pair : gshortCut->get_short_map())
    {
        // 防止快捷键 new 失败导致崩溃
        if(pair.second == nullptr)
            continue;
        if(pair.second->objectName() == tr("play/pause") ||
                pair.second->objectName() == tr("speed up") ||
                pair.second->objectName() == tr("speed down") ||
                pair.second->objectName() == tr("speed normal") ||
                pair.second->objectName() == tr("forword") ||
                pair.second->objectName() == tr("backword") ||
                pair.second->objectName() == tr("forward 30s") ||
                pair.second->objectName() == tr("backword 30s") ||
                pair.second->objectName() == tr("insert bookmark") /*||
                pair.second->objectName() == tr("ib notes")*/)
        {
            QString shortKey = regKeyString(pair.second->key().toString());
            key_set.insert(shortKey);
            QListWidgetItem *it = new QListWidgetItem;
            it->setSizeHint(QSize(400, 30));
            ShortCutItem *itemw = new ShortCutItem(pair.second->objectName(), shortKey, this);
            item_set.insert(itemw);
            connect(itemw, &ShortCutItem::sigKeyChange, this, &SetupShortcut::slotChangeKeyCache);
            ui->list_play->addItem(it);
            ui->list_play->setItemWidget(it, itemw);
        }
    }
}

void SetupShortcut::initImageShortCut()
{
    // key item
    for(std::pair<void(*)(), QShortcut*> pair : gshortCut->get_short_map())
    {
        // 防止快捷键 new 失败导致崩溃
        if(pair.second == nullptr)
            continue;
        if(pair.second->objectName() == tr("fullscreen") ||
                pair.second->objectName() == tr("mini mode") ||       // mini模式先不做实现
                pair.second->objectName() == tr("to top") ||
                pair.second->objectName() == tr("screenshot") ||
//                pair.second->objectName() == tr("cut") ||             // 截取先不做实现
                pair.second->objectName() == tr("light up") ||
                pair.second->objectName() == tr("light down") ||
                pair.second->objectName() == tr("forward rotate") ||
                pair.second->objectName() == tr("backward rotate") ||
                pair.second->objectName() == tr("horizontal flip") ||
                pair.second->objectName() == tr("vertical flip") /*||*/
//                pair.second->objectName() == tr("image boost")        // 画质增强先不做实现
                )
        {
            QString shortKey = regKeyString(pair.second->key().toString());
            key_set.insert(shortKey);
            QListWidgetItem *it = new QListWidgetItem;
            it->setSizeHint(QSize(400, 30));
            ShortCutItem *itemw = new ShortCutItem(pair.second->objectName(), shortKey, this);
            item_set.insert(itemw);
            connect(itemw, &ShortCutItem::sigKeyChange, this, &SetupShortcut::slotChangeKeyCache);
            ui->list_image->addItem(it);
            ui->list_image->setItemWidget(it, itemw);
        }
    }
}

void SetupShortcut::initVolumeShortCut()
{
    // key item
    for(std::pair<void(*)(), QShortcut*> pair : gshortCut->get_short_map())
    {
        // 防止快捷键 new 失败导致崩溃
        if(pair.second == nullptr)
            continue;
        if(pair.second->objectName() == tr("volume up") ||
                pair.second->objectName() == tr("volume down") ||
                pair.second->objectName() == tr("mute") ||
                pair.second->objectName() == tr("audio next") ||
                pair.second->objectName() == tr("default channel") ||
                pair.second->objectName() == tr("left channel") ||
                pair.second->objectName() == tr("right channel"))
        {
            QString shortKey = regKeyString(pair.second->key().toString());
            key_set.insert(shortKey);
            QListWidgetItem *it = new QListWidgetItem;
            it->setSizeHint(QSize(400, 30));
            ShortCutItem *itemw = new ShortCutItem(pair.second->objectName(), shortKey, this);
            item_set.insert(itemw);
            connect(itemw, &ShortCutItem::sigKeyChange, this, &SetupShortcut::slotChangeKeyCache);
            ui->list_volume->addItem(it);
            ui->list_volume->setItemWidget(it, itemw);
        }
    }
}

void SetupShortcut::initSubtitleShortCut()
{
    // key item
    for(std::pair<void(*)(), QShortcut*> pair : gshortCut->get_short_map())
    {
        // 防止快捷键 new 失败导致崩溃
        if(pair.second == nullptr)
            continue;
        if(pair.second->objectName() == tr("sub load") ||
                pair.second->objectName() == tr("sub earlier") ||
                pair.second->objectName() == tr("sub later") ||
                pair.second->objectName() == tr("sub up") ||
                pair.second->objectName() == tr("sub down") ||
                pair.second->objectName() == tr("sub next"))
        {
            QString shortKey = regKeyString(pair.second->key().toString());
            key_set.insert(shortKey);
            QListWidgetItem *it = new QListWidgetItem;
            it->setSizeHint(QSize(400, 30));
            ShortCutItem *itemw = new ShortCutItem(pair.second->objectName(), shortKey, this);
            item_set.insert(itemw);
            connect(itemw, &ShortCutItem::sigKeyChange, this, &SetupShortcut::slotChangeKeyCache);
            ui->list_subtitle->addItem(it);
            ui->list_subtitle->setItemWidget(it, itemw);
        }
    }
}

void SetupShortcut::initOtherShortCut()
{
    // key item
    for(std::pair<void(*)(), QShortcut*> pair : gshortCut->get_short_map())
    {
        // 防止快捷键 new 失败导致崩溃
        if(pair.second == nullptr)
            continue;
        if(pair.second->objectName() == tr("play list") ||
                pair.second->objectName() == tr("setup"))
        {
            QString shortKey = regKeyString(pair.second->key().toString());
            key_set.insert(shortKey);
            QListWidgetItem *it = new QListWidgetItem;
            it->setSizeHint(QSize(400, 30));
            ShortCutItem *itemw = new ShortCutItem(pair.second->objectName(), shortKey, this);
            item_set.insert(itemw);
            connect(itemw, &ShortCutItem::sigKeyChange, this, &SetupShortcut::slotChangeKeyCache);
            ui->list_other->addItem(it);
            ui->list_other->setItemWidget(it, itemw);
        }
    }
}

/** **********************************************
 * 快捷键修改临时缓存
 * 说明：只是保存需要修改的哪些快捷键，如果设置窗口点击了
 *      确认按钮，才会真正的修改这些快捷键。
 * @param:name 修改快捷键的名字
 * @param:newKey 要修改的快捷键组合
 * @param:isConflict 是否有冲突 如果有冲突设置为空
 *************************************************/
void SetupShortcut::slotChangeKeyCache(QString name, QString newKey, bool isConflict)
{
    // 临时改变快捷键
    if (!isConflict)
        chg_map[name] = newKey;
}

ShortCutItem::ShortCutItem(QString name, QString key, QWidget *parent) :
    QWidget(parent),
    m_name(name),
    m_key(key),
    m_isConflict(false)
{
    setObjectName(name);
    m_name = name;
    lab_name = new QLabel;
    lab_name->setText(name);
    lab_name->setFixedWidth(130);

    QFont f("Noto Sans CJK SC Regular");
    f.setPixelSize(16);
    lab_name->setFont(f);

    le_key = new ShortEdit;
    le_key->setReadOnly(true);
    le_key->setText(key);
    le_key->setFixedSize(237, 30);

    /// 设置界面关闭的时候如果没有保存，需要刷新快捷键界面为打开时的快捷键。目前没做。
    connect(le_key, &ShortEdit::sigUpdateShort, [&](QString key){
        emit sigKeyChange(m_name, key, m_isConflict);
    });
    connect(le_key, &ShortEdit::textChanged, [&](QString tmpKey){
        if(tmpKey == m_key)
            setHotkeyConflict(false);
        else
            setHotkeyConflict(SetupShortcut::key_set.find(tmpKey) != SetupShortcut::key_set.end());
    });
    le_key->setCursor(Qt::PointingHandCursor);

    // 热键冲突标签
    lay_key = new QHBoxLayout(le_key);
    lab_conflict = new QLabel;
    lab_conflict->setText(tr("Hotkey conflict"));
    lab_conflict->setStyleSheet("color:#f44e50");
    lay_key->addStretch();
    lay_key->addWidget(lab_conflict);
    lay_key->setContentsMargins(0, 0, 8, 0);
    lab_conflict->hide();

    lay = new QHBoxLayout(this);
    lay->setContentsMargins(0, 0, 0, 0);

    lay->addWidget(lab_name);
    lay->addWidget(le_key);
    lay->addStretch();
}

ShortCutItem::~ShortCutItem()
{
    delete lab_conflict;
    lab_conflict = nullptr;
    delete lay_key;
    lay_key = nullptr;
    delete lab_name;
    lab_name = nullptr;
    delete le_key;
    le_key = nullptr;
    delete lay;
    lay = nullptr;
}

void ShortCutItem::setBlackTheme()
{
    le_key->setBlackTheme();
    lab_name->setStyleSheet("color:#d9d9d9;");
}

void ShortCutItem::setLightTheme()
{
    le_key->setLightTheme();
    lab_name->setStyleSheet("color:#262626;");
}

void ShortCutItem::setWidgetFont(QFont f)
{
    lab_name->setFont(f);
    lab_conflict->setFont(f);
    le_key->setFont(f);
}

void ShortCutItem::reset()
{
    le_key->setText(m_key);
}

void ShortCutItem::flush()
{
    if(!m_isConflict)
        m_key = le_key->text();
}

void ShortCutItem::setHotkeyConflict(bool isConflict)
{
    m_isConflict = isConflict;
    if(isConflict)
        lab_conflict->show();
    else
        lab_conflict->hide();
}

ShortEdit::~ShortEdit()
{

}

void ShortEdit::setBlackTheme()
{
    m_theme = STYLE_UKUI_BLACK;
    setStyleSheet("background-color:#404040;color:#d9d9d9;border:0px;border-radius:4px;");
}

void ShortEdit::setLightTheme()
{
    m_theme = STYLE_UKUI_DEFAULT;
    setStyleSheet("background-color:#f0f0f0;color:#262626;border:0px;border-radius:4px;");
}

void ShortEdit::setShortCut(QString s)
{
    m_start_text = s;
    setText(m_start_text);
}

ShortEdit::ShortEdit(QWidget *parent) :
    QLineEdit(parent)
{
    QFont f("Noto Sans CJK SC Regular");
    f.setPixelSize(14);
    setFont(f);
}

void ShortEdit::focusInEvent(QFocusEvent *e)
{
    if(m_theme == STYLE_UKUI_DEFAULT)
        setStyleSheet("QLineEdit{background-color:#f5f5f5;color:#262626;border:1px solid #3790fa;border-radius:4px;}");
    else
        setStyleSheet("QLineEdit{background-color:#333333;color:#d9d9d9;border:1px solid #296cd9;border-radius:4px;}");
}

void ShortEdit::focusOutEvent(QFocusEvent *e)
{
    if(m_theme == STYLE_UKUI_DEFAULT)
        setStyleSheet("QLineEdit{background-color:#f0f0f0;color:#262626;border:0px;border-radius:4px;}");
    else
        setStyleSheet("QLineEdit{background-color:#404040;color:#d9d9d9;border:0px;border-radius:4px;}");

    if(m_start_text != text())
    {
        emit sigUpdateShort(text());
        m_start_text = text();
    }
}

void ShortEdit::keyPressEvent(QKeyEvent *e)
{
    // 组合键不能单独去设置
    if (e->key() == Qt::Key_Meta || e->key() == Qt::Key_Shift || e->key() == Qt::Key_Alt || e->key() == Qt::Key_Control)
        return;
    QKeySequence qs(e->key());
    QString keyStr = regKeyString(qs.toString());
    if(e->modifiers() == Qt::ShiftModifier)
    {
        if(e->key() == 16777248)
        {
            setText("Shift");
            return;
        }
        // shift 组合键
        setText("Shift + " + keyStr);
    }
    else if(e->modifiers() == Qt::ControlModifier)
    {
        if(e->key() == 16777249)
        {
            setText("Ctrl");
            return;
        }
        // ctrl 组合键
        setText("Ctrl + " + keyStr);
    }
    else if(e->modifiers() == Qt::AltModifier)
    {
        if(e->key() == 16777251)
        {
            setText("Alt");
            return;
        }
        // ctrl 组合键
        setText("Alt + " + keyStr);
    }
    else if(e->modifiers() == (Qt::AltModifier|Qt::ControlModifier))
    {
        if(e->key() == 16777251 || e->key() == 16777249)
        {
            setText("Ctrl + Alt");
            return;
        }
        // ctrl+alt 组合键
        setText("Ctrl + Alt + " + keyStr);
    }
    else if(e->modifiers() == (Qt::AltModifier|Qt::ShiftModifier))
    {
        if(e->key() == 16777251 || e->key() == 16777248)
        {
            setText("Alt + Shift");
            return;
        }
        // ctrl+shift 组合键
        setText("Alt + Shift + " + keyStr);
    }
    else if(e->modifiers() == (Qt::ControlModifier|Qt::ShiftModifier))
    {
        if(e->key() == 16777249 || e->key() == 16777248)
        {
            setText("Ctrl + Shift");
            return;
        }
        // ctrl+shift 组合键
        setText("Ctrl + Shift + " + keyStr);
    }
    else
    {
        setText(keyStr);
    }
}
