#include <QKeyEvent>
#include <QLabel>
#include <QPainter>
#include <QSound>
#include <QSettings>
#include <QTimer>
#include <QGraphicsBlurEffect>
#include <QPixmapCache>
#include <QApplication>
#include <QEasingCurve>
#include "mainmenu.h"
#include "image.h"


const char *iconMap[] = {
	"slideshow",
	"photos",
	"music",
	"videos",
	"info",
	"settings",
	"shutdown"
};


const char *nameMap[] = {
	QT_TRANSLATE_NOOP("DPF", "    Slide Show"),
	QT_TRANSLATE_NOOP("DPF", "       Photos"),
	QT_TRANSLATE_NOOP("DPF", "        Music"),
	QT_TRANSLATE_NOOP("DPF", "      Videos"),
	QT_TRANSLATE_NOOP("DPF", "   Information"),
	QT_TRANSLATE_NOOP("DPF", "     Settings"),
	QT_TRANSLATE_NOOP("DPF", "    Shut Down")
};


const char *menuItems[] = {
	QT_TRANSLATE_NOOP("DPF", "Slide Show"),
	QT_TRANSLATE_NOOP("DPF", "Browse Photos"),
	QT_TRANSLATE_NOOP("DPF", "Browse Music"),
	QT_TRANSLATE_NOOP("DPF", "Browse Videos"),
	QT_TRANSLATE_NOOP("DPF", "Information"),
	QT_TRANSLATE_NOOP("DPF", "Settings"),
	QT_TRANSLATE_NOOP("DPF", "Shut Down")
};


const int menuSize = sizeof(menuItems) / sizeof(const char *);


QT_BEGIN_NAMESPACE
extern Q_WIDGETS_EXPORT void qt_blurImage(QPainter* p, QImage& blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0);
QT_END_NAMESPACE


QPixmap blurPixmap(const QPixmap& inPixmap)
{
	QImage srcImg = inPixmap.toImage(); //source image	
	QPixmap pxDst(srcImg.size());//blurred destination
	pxDst.fill(Qt::transparent);
	{
		QPainter painter(&pxDst);
		qt_blurImage(&painter, srcImg, 10, true, false);//blur radius: 2px
	}
	return pxDst;
}


static const int frames = 15;


class AnimatedIcon : public QWidget
{
public:
	AnimatedIcon(QWidget *p) : QWidget(p) {
		// nothing
	}
	~AnimatedIcon() {
		// nothing
	}
	template <typename F>
	void loadPixmp(std::string _name, QPixmap* _pix, F _loader)
	{
		if (!cache.find(_name.c_str(), _pix)) {
			*_pix = _loader(_name.c_str());
			cache.insert(_name.c_str(), *_pix);
		}
	}
	void setPixmaps(int _a, int _b) {
		std::string blurSuffix = "_blur";
		loadPixmp(iconMap[_a], &a, [](const char* _name) { return Image::icon(_name, 256); });
		loadPixmp(iconMap[_b], &b, [](const char* _name) { return Image::icon(_name, 256); });
		loadPixmp(iconMap[_a] + blurSuffix, &ablur, [this](const char* _name) { return blurPixmap(a); });
		loadPixmp(iconMap[_b] + blurSuffix, &bblur, [this](const char* _name) { return blurPixmap(b); });
	}
	void setFrame(int f, int d) {
		frame = f;
		dir = d;
	}
	void paintEvent(QPaintEvent *pe) {
		QPainter p(this);
		QTransform trans;

		// QEasingCurve curve((dir == 1) ? QEasingCurve::OutInBack : QEasingCurve::InOutBack);
		QEasingCurve curve((dir == 1) ? QEasingCurve::OutExpo: QEasingCurve::InExpo);
		float curveValue = curve.valueForProgress(frame / float(frames));
		float invCurveValue = 1.0 - curveValue;
		float scale = 1.0;
		float pos = invCurveValue * 200;

		// Draw icon 'a'
		trans.reset();
		scale = 0.5 + 0.5 * invCurveValue;
		trans.scale(scale, scale);
		p.setWorldTransform(trans);
		p.setOpacity(invCurveValue);
		p.drawPixmap(360 * (1.0 - scale) - 40 + pos, 0, a);
		p.resetTransform();

		// Draw icon 'a' reflected
		trans.reset();
		trans.scale(scale, -scale);
		p.setWorldTransform(trans);
		p.setOpacity(0.3 * invCurveValue);
		p.drawPixmap(360 * (1.0 - scale) - 40 + pos, -2.0 * a.height(), ablur);
		p.resetTransform();

		// Draw icon 'b'
		trans.reset();
		scale = 0.5 + 0.5 * curveValue;
		trans.scale(scale, scale);
		p.setWorldTransform(trans);
		p.setOpacity(curveValue);
		p.drawPixmap(700 * (1.0 - scale) + 160 + pos, 0, b);
		p.resetTransform();

		// Draw icon 'b' reflected
		trans.reset();
		trans.scale(scale, -scale);
		p.setWorldTransform(trans);
		p.setOpacity(0.3 * curveValue);
		p.drawPixmap(700 * (1.0 - scale) + 160 + pos, -2.0 * b.height(), bblur);
		p.resetTransform();
	}
	QPixmapCache cache;
	QPixmap a, b;
	QPixmap ablur, bblur;
	int frame, dir;
};


MainMenu::MainMenu(QWidget *parent) : Stage(parent)
{
	static const bool labelAbove = true;
	static const bool menuLeft = false;

	animateIcons = QSettings("dpf.ini", QSettings::IniFormat).value("AnimateIcons", true).toBool();

	curItem = 0;

	icon = new AnimatedIcon(this);
	icon->setFrame(0, 0);
	icon->setPixmaps(1,0);
	icon->setGeometry(menuLeft ? 320 : -70, labelAbove ? 150 : 80, 640, 600);
	icon->show();
	icon->setPixmaps(0, 0);
	icon->setFrame(0, 0);
	icon->update();

	item1 = new Text(this, menuLeft ? 432 : 82, labelAbove ? 52: 342, "", 40, QColor(0, 0, 0, 128));
	item1->setText(nameMap[curItem]);
	item2 = new Text(this, menuLeft ? 430 : 80, labelAbove ? 50 : 340, "", 40, QColor(255, 255, 255));
	item2->setText(nameMap[curItem]);

	items = new MenuItem * [menuSize];
	for (int i = 0; i < menuSize; i++)
		items[i] = new MenuItem(this, menuLeft ? 60 : 450, 80 + i * 50, menuItems[i]);
	items[curItem]->select();
	timerId = 0;
	frame = 0;

	QTimer::singleShot(0, this, SLOT(init()));

	QTimer* timer = new QTimer(this);
	timer->setTimerType(Qt::PreciseTimer);
	timer->setInterval(35);
	timer->callOnTimeout([this]() {
		if (animating)
		{
			frame += direction;
			icon->setFrame(frame, direction);
			//icon->update();
			//update();
			//qApp->processEvents();
			icon->repaint();

			if (frame >= frames || frame <= 0)
				animating = false;
			//killTimer(timerId);
		}
	});
	timer->start();

	//timerId = startTimer(20, Qt::PreciseTimer);
	animating = false;
}


MainMenu::~MainMenu()
{
	for (int i = 0; i < menuSize; i++)
		delete items[i];
	killTimer(timerId);
}


void MainMenu::init()
{
	changeBackground("any");
}


void MainMenu::changeBackground(QString backg)
{
	QSettings settings("dpf.ini", QSettings::IniFormat);
	QString background = settings.value("Background", "image").toString();
	bg->setPixmap(QPixmap("pics/" + background + "_bg0.png"));
}


void MainMenu::animate(int dir, int before, int now)
{
	direction = dir;
	//killTimer(timerId);
	animating = false;

	if (dir == -1)
		frame = frames - 1;// 19;
	else
		frame = 1;// 1;

	if (dir == -1) {
		item1->setText(nameMap[before]);
		item2->setText(nameMap[before]);
	} else {
		item1->setText(nameMap[now]);
		item2->setText(nameMap[now]);
	}
	
	icon->setPixmaps(before, now);
	icon->setFrame(frame, direction);
	//update();
	//qApp->processEvents();
	//icon->repaint();

	animating = true;
}


void MainMenu::timerEvent(QTimerEvent *te)
{
	if (animating)
	{
		frame += direction;
		icon->setFrame(frame, direction);
		icon->update();
		//icon->repaint();

		if (frame >= frames || frame <= 0)
			animating = false;
		//killTimer(timerId);
	}
}


void MainMenu::keyPressEvent(QKeyEvent *ke)
{
	int prevItem = curItem;
	if ( ke->key() == Qt::Key_Up ) {
		items[curItem]->unselect();
		curItem--;
		if (curItem < 0)
			curItem = menuSize - 1;
		if (curItem == 0)
			QSound::play("sounds/Prev.wav");
		else
			QSound::play("sounds/Next.wav");
		items[curItem]->select();
		animate(-1, curItem, prevItem);
		if (!animateIcons) {
			icon->setFrame(0, -1);
			icon->update();
			killTimer(timerId);
		}
	} else if ( ke->key() == Qt::Key_Down ) {
		items[curItem]->unselect();
		curItem++;
		if (curItem > (menuSize-1))
			curItem = 0;
		if (curItem == (menuSize-1))
			QSound::play("sounds/Prev.wav");
		else
			QSound::play("sounds/Next.wav");
		items[curItem]->select();
		animate(1, prevItem, curItem);
		if (!animateIcons) {
			icon->setFrame(frames, 1);
			icon->update();
			killTimer(timerId);
		}
		//	} else if ( ke->key() == Qt::Key_Select ) {
	} else if ( ke->key() == Qt::Key_Return ) {
		QSound::play("sounds/Select.wav");
		emit setStage(curItem);
	}
}

