#include "virtual_keyboard.h"

#include "ui_virtual_keyboard.h"
#include "virtual_keyboard_layout.h"
#include "virtual_keyboard_layout_page.h"

#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStyle>
#include <QStyleFactory>
#include <pibase.h>
#include <picout.h>
#include <piliterals_time.h>


VirtualKeyboard::VirtualKeyboard(QWidget * parent): QWidget(parent) {
	ui = new Ui::VirtualKeyboard();
	ui->setupUi(this);
	ui->stackedPages->setStyle(QStyleFactory::create("Fusion"));
	connect(qApp, &QApplication::focusChanged, this, [this](QWidget * old, QWidget * now) {
		if (watched) {
			watched->removeEventFilter(this);
			watched = nullptr;
		}
		if (!now || !layout) {
			setKeyboardVisible(false);
			return;
		}
		if (!now->inputMethodQuery(Qt::ImCursorPosition).isValid()) {
			setKeyboardVisible(false);
			return;
		}
		watched  = now;
		auto imh = Qt::InputMethodHints(watched->inputMethodQuery(Qt::ImHints).toInt());
		layout->setDefaultPage();
		setKeyboardVisible(true);
		layout->applyHints(imh);
		watched->installEventFilter(this);
	});
	hide();
}


VirtualKeyboard::~VirtualKeyboard() {
	if (watched) {
		watched->removeEventFilter(this);
		watched = nullptr;
	}
	destroy();
	delete ui;
}


void VirtualKeyboard::init(QString layout_path) {
	destroy();
	QFile f(layout_path);
	if (!f.open(QIODevice::ReadOnly)) return;
	QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
	layout            = new VirtualKeyboardLayout(doc.object());
	auto pages        = layout->getPages();
	for (auto p: pages)
		ui->stackedPages->addWidget(p);
	connect(layout, &VirtualKeyboardLayout::gotoPageRequest, this, [this](QString pagename) {
		auto page = layout->getPageByName(pagename);
		if (!page) return;
		ui->stackedPages->setCurrentWidget(page);
		layout->setCurrentPage(page);
	});
	connect(layout, &VirtualKeyboardLayout::hideRequest, this, [this]() { setKeyboardVisible(false); });
	layout->setDefaultPage();
	// piCout << pages.size();
	adjust();
}


bool VirtualKeyboard::eventFilter(QObject * o, QEvent * e) {
	if (e->type() == QEvent::MouseButtonPress) setKeyboardVisible(true);
	return QWidget::eventFilter(o, e);
}


void VirtualKeyboard::changeEvent(QEvent * e) {
	QWidget::changeEvent(e);
	switch (e->type()) {
	case QEvent::LanguageChange: ui->retranslateUi(this); break;
	case QEvent::Show: ui->retranslateUi(this); break;
	default: break;
	}
}


void VirtualKeyboard::resizeEvent(QResizeEvent * e) {
	if (prev_width == width()) return;
	prev_width = width();
	adjust();
}


void VirtualKeyboard::showEvent(QShowEvent * e) {
	if (first_show) {
		first_show = false;
		if (layout_path_.isEmpty()) init(":/virtual_keyboard/default.json");
	}
	QWidget::showEvent(e);
}


void VirtualKeyboard::destroy() {
	piDeleteSafety(layout);
	while (ui->stackedPages->count() > 0)
		delete ui->stackedPages->widget(0);
}


void VirtualKeyboard::adjust() {
	if (!layout) return;
	auto pages = layout->getPages();
	int cols   = 0;
	for (auto p: pages)
		cols = piMaxi(cols, p->buttonColumns());
	if (cols < 1) return;
	int spacing = style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing, nullptr, this);
	int m[4]    = {0, 0, 0, 0};
	ui->verticalLayout->getContentsMargins(&m[0], &m[1], &m[2], &m[3]);
	int pixel_width = width() - spacing * (cols - 1) - m[0] * 2;
	int bw          = piMaxi(2, pixel_width / cols);
	ui->stackedPages->setStyleSheet(QString("font:%1px").arg(bw / 2));
	for (auto p: pages)
		p->setButtonsSize(bw);
	// piCout << cols << spacing << bw;
}


void VirtualKeyboard::setKeyboardVisible(bool yes) {
	if (always_visible || !isEnabled()) return;
	if (yes) {
		stopIndexedTimer(0);
		setVisible(true);
	} else
		startIndexedTimer(0, 10_Hz, [this] {
			if (QApplication::mouseButtons() != 0) return;
			stopIndexedTimer(0);
			setVisible(false);
		});
}


void VirtualKeyboard::setLayoutPath(const QString & path) {
	layout_path_ = path;
	init(layout_path_);
}


void VirtualKeyboard::setAlwaysVisible(bool yes) {
	always_visible = yes;
	if (yes) show();
}


void VirtualKeyboard::setEnabled(bool yes) {
	if (!yes) hide();
	QWidget::setEnabled(yes);
}


void VirtualKeyboard::setDisabled(bool yes) {
	if (yes) hide();
	QWidget::setDisabled(yes);
}
