#include "SH_ui_loader.h"
#include "rcc/rcc_wrap.h"

#include "button.h"
#include "slider.h"
#include "tabwidget.h"
#include "stackedwidget.h"
#include "scrollarea.h"
#include "qtimerwidget.h"
#include "clock.h"
#include "thermometer.h"
#include "light.h"
#include "switch.h"
#include "shs_graphic.h"
#include "touchbutton.h"
#include "touchbuttframe.h"
#include "touchslider.h"

#include "clineedit.h"
#include "ecombobox.h"
#include "evalspinbox.h"
#include "qpiconfigwidget.h"
#include "colorbutton.h"
#include "spinslider.h"
#include "iconedlabel.h"
#include "qpointedit.h"
#include "qrectedit.h"
#include "qipedit.h"
#include "graphic.h"
#include <QQuickWidget>
#include <QProcess>
#include <QStyleFactory>
//#include "sql_table_widget.h"

const QByteArray property_hidden = "hidden";


QString scaleCssFont(QString css, double scl) {
	if (css.isEmpty()) return css;
	int fi = css.indexOf("font", 0, Qt::CaseInsensitive); if (fi < 0) return css;
	int si = css.indexOf(':', fi); if (si < 0) return css;
	int ei = css.indexOf(';', si); if (ei < 0) return css;
	QString ret = css;
	QString fdesc = ret.mid(si + 1, ei - si - 1);
	ret.remove(si + 1, fdesc.size());
	fdesc.replace('\t', ' ').replace('\n', ' ').replace("  ", " ");
	QStringList fdc = fdesc.trimmed().split(" ");
	for (int i = 0; i < fdc.size(); ++i) {
		QString & s(fdc[i]);
		if (s.endsWith("pt") || s.endsWith("px")) {
			QString suff = s.right(2);
			s.chop(2);
			s = QString::number(qRound(s.toDouble() * scl)) + suff;
		}
	}
	qDebug() << fdesc << "->" << fdc.join(" ");
	ret.insert(si + 1, " " + fdc.join(" "));
	return ret;
}


SHSUiLoader::SHSUiLoader(): QUiLoader() {
	appevents = false;
}


QWidget * SHSUiLoader::load(QIODevice * device, QWidget * parentWidget, bool emit_appevents) {
	appevents = emit_appevents;
	loaded_widgets.clear();
	loaded_tree.clear();
	graphics.clear();
	variables_map.clear();
	QSet<QString> vars;
	QWidget * ret = QUiLoader::load(device, parentWidget);
	if (!ret) return 0;
	QStyle * s = QStyleFactory::create("Fusion");
	ret->setStyle(s);
	double app_scale = appScale();
	QFont default_font = QApplication::font();
	qDebug() << default_font << app_scale << RUNTIME->font_scale;
	foreach (QObject * o, loaded_widgets) {
		QWidget * w = qobject_cast<QWidget*>(o);
		if (!w) continue;
		w->setStyle(s);
		QFont f = w->font();
		if (f != default_font) {
			if (f.pointSizeF() > 0) {
				f.setPointSizeF(qCeil(f.pointSizeF() * RUNTIME->font_scale));
				w->setFont(f);
			}
		}
		w->setStyleSheet(scaleCssFont(w->styleSheet(), RUNTIME->font_scale));
		if (w->metaObject()->indexOfProperty("iconSize") >= 0) {
			QSize sz = w->property("iconSize").toSize();
			sz *= app_scale * RUNTIME->font_scale;
			w->setProperty("iconSize", sz);
		}
		SHSGraphic * g = qobject_cast<SHSGraphic*>(w);
		if (g) {
			graphics << g;
			QStringList vlist = g->variableNames();
			for (int i = 0; i < vlist.size(); ++i)
				variables_map[vlist[i]] << QPair<SHSGraphic*, int>(g, i);
			vars |= QList2QSet(vlist);
		}
		checkAppEvents();
	}
	graphic_variables = vars.values();
	return ret;
}


QWidget * SHSUiLoader::load(QByteArray data, QWidget * parentWidget, bool emit_appevents) {
	QBuffer buffer(&data);
	buffer.open(QIODevice::ReadOnly);
	return load(&buffer, parentWidget, emit_appevents);
}


void SHSUiLoader::adjust(QWidget * form) {
	if (!form) return;
	if (form->property("__adjusted__").toBool()) {
		//qDebug() << "ADJUST has been done";
		return;
	}
	form->setProperty("__adjusted__", true);
#ifdef MOBILE_VIEW
	QList<QSpinBox*> sl0 = form->findChildren<QSpinBox*>();
	QList<QDoubleSpinBox*> sl1 = form->findChildren<QDoubleSpinBox*>();
	QWidgetList sbl;
	foreach (QSpinBox * i, sl0) sbl << i;
	foreach (QDoubleSpinBox * i, sl1) sbl << i;
	//QStyle * fs = QStyleFactory::create("fusion");
	foreach (QWidget * s, sbl) {
		//qDebug() << "ADJUST" << s;
		//s->setStyle(fs);
		s->setMinimumHeight(s->sizeHint().height() + (s->fontMetrics().xHeight() * 2));
		//connect(s, SIGNAL(editingFinished()), QApplication::inputMethod(), SLOT(hide()));
	}
#endif
}


#define CREATE_WIDGET(a) if (className == #a) {w = new a(parent); w->setObjectName(name);}

QWidget * SHSUiLoader::createWidget(const QString & className, QWidget * parent, const QString & name) {
	QWidget * w = 0;
	//CREATE_WIDGET(SQLTableWidget);
	CREATE_WIDGET(CLineEdit);
	CREATE_WIDGET(EComboBox);
	CREATE_WIDGET(EvalSpinBox);
	CREATE_WIDGET(QPIConfigWidget);
	CREATE_WIDGET(ColorButton);
	CREATE_WIDGET(SpinSlider);
	CREATE_WIDGET(IconedLabel);
	CREATE_WIDGET(QPointEdit);
	CREATE_WIDGET(QRectEdit);
	CREATE_WIDGET(QIPEdit);
	CREATE_WIDGET(QTimerWidget);
	CREATE_WIDGET(Graphic);
	CREATE_WIDGET(SHSButton);
	CREATE_WIDGET(SHSSlider);
	CREATE_WIDGET(SHSTabWidget);
	CREATE_WIDGET(SHSStackedWidget);
	CREATE_WIDGET(SHSScrollArea);
	CREATE_WIDGET(SHSClock);
	CREATE_WIDGET(SHSThermometer);
	CREATE_WIDGET(SHSLight);
	CREATE_WIDGET(SHSSwitch);
	CREATE_WIDGET(SHSGraphic);
	CREATE_WIDGET(TouchButton);
	CREATE_WIDGET(TouchButtFrame);
	CREATE_WIDGET(TouchSlider);
	CREATE_WIDGET(QQuickWidget);
	if (!w) w = QUiLoader::createWidget(className, parent, name);
	if (w) {
		w->setProperty(property_hidden, false);
		w->installEventFilter(this);
		loaded_widgets << w;
		loaded_tree[parent] << w;
		//if (parent)
		//	w->setVisible(true);
	}
	checkAppEvents();
	return w;

}

#undef CREATE_WIDGET


QString SHSUiLoader::prepareUI(const QString & file, const QString & src) {
	QFile f(file);
	if (!f.open(QIODevice::ReadWrite)) return QString();
	QDir dir = QFileInfo(src).absoluteDir();
	QString brcp = dir.path() + "/" + QFileInfo(src).baseName() + ".rcc";
	QString fc = QString::fromUtf8(f.readAll()), rcn = QFileInfo(brcp).fileName();

	QStringList regexps = SHSUiLoader::iconsRegexpList();
	QSet<QString> rc_files;
	for (QString a: regexps) {
		QRegularExpression re(a);
		QRegularExpressionMatch rm = re.match(fc);
		while (rm.hasMatch()) {
			QFileInfo fi(rm.captured(1));
			QString srcname = dir.filePath(rm.captured(1)), newname;
			if (!srcname.startsWith(":")) {
				newname = QFileInfo(srcname).fileName();
				rc_files << newname;
				fc.replace(rm.capturedStart(1), rm.capturedLength(1), QString(":/%1").arg(newname));
			}
			rm = re.match(fc, rm.capturedStart() + (a.size() / 2));
		}
	}
	fc.replace("<iconset>", QString("<iconset resource=\"%1\">").arg(rcn));

	/*ii = fc.indexOf("<string>file://");
	while (ii >= 0) {
		int si = fc.indexOf(".qml</string>", ii);
		if (si > 0) {
//			qDebug() << fc.mid(ii+8, 8);
			QString st = fc.mid(ii+16, si - ii - 12);
			if (!isl.contains(st))
				isl << st;
			fc.replace(ii+8, 8, "qrc:/");
		} else break;
		ii = fc.indexOf("<string>file://", si);
	}*/
	//qDebug() << fc;
	f.resize(0);
	f.write(fc.toUtf8());
	f.close();

	f.setFileName(QFileInfo(file).absoluteDir().filePath("shs_rc.qrc"));
	f.remove();
	if (!f.open(QIODevice::ReadWrite)) return QString();
	f.write("<RCC>\n  <qresource prefix=\"/\">\n");
	for (QString i: rc_files) {
		//qDebug() << "rcc <<" << i;
		f.write(QString("    <file alias=\"%1\">%2</file>\n").arg(i, dir.absolutePath() + "/res/img/" + i).toUtf8());
		//f.write(QString("    <file>%1</file>\n").arg(i).toUtf8());
	}
	f.write("  </qresource>\n</RCC>\n");
	f.close();
	if (QFile::exists(brcp))
		QFile::remove(brcp);
	makeRcc(rcn, f.fileName(), brcp);
	//QProcess::execute("rcc", QStringList() << "-no-compress" << "-binary" << "--format-version" << "2" << "-name" << rcn << "-o" << brcp << f.fileName());
	f.remove();
	return brcp;
}


QStringList SHSUiLoader::iconsRegexpList() {
	QStringList anchors({"normaloff"  , "normalon"
						,"disabledoff", "disabledon"
						,"activeoff"  , "activeon"
						,"selectedoff", "selectedon"});
	QStringList regexps;
	for (QString a: anchors)
		regexps << QString("<%1>([^\\<]*)<\\/%1>").arg(a);
	regexps << QString(">([^\\<]*)<\\/iconset>");
	return regexps;
}


bool SHSUiLoader::eventFilter(QObject * o, QEvent * e) {
	if (e->type() == QEvent::DynamicPropertyChange) {
		if (((QDynamicPropertyChangeEvent*)e)->propertyName() == property_hidden) {
			auto * w = qobject_cast<QWidget*>(o);
			if (w) w->setHidden(o->property(property_hidden).toBool());
			//qDebug() << "set hidden" << o << o->property(property_hidden).toBool();
		}
		return true;
	}
	return QUiLoader::eventFilter(o, e);
}


void SHSUiLoader::checkAppEvents() {
	if (!appevents) return;
	if (etm.elapsed() < 40) return;
	etm.restart();
	QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
}
