/*
 * chatviewtheme_p.h
 * Copyright (C) 2017  Sergey Ilinykh
 *
 * 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 *
 */

#ifndef CHATVIEWTHEME_P_H
#define CHATVIEWTHEME_P_H

#include <QTimer>
#include <QScopedPointer>
#include <QPointer>
#ifdef WEBENGINE
# include <QWebEngineScript>
#else
#endif

#include "theme_p.h"
#include "chatviewtheme.h"

class QWebFrame;

class WebView;
class NetworkAccessManager;
class ChatViewThemeProvider;
class ChatViewThemePrivate;

class ChatViewJSLoader : public QObject
{
	Q_OBJECT

	ChatViewThemePrivate *theme;
	QString _loadError;
	QHash<QString, QObject*> _sessions;

	Q_PROPERTY(QString themeId READ themeId CONSTANT)
	Q_PROPERTY(QString isMuc READ isMuc CONSTANT)
	Q_PROPERTY(QString serverUrl READ serverUrl CONSTANT)

signals:
	void sessionHtmlReady(const QString &sessionId, const QString &html);

public:
	ChatViewJSLoader(Theme theme, QObject *parent = 0);
	const QString themeId() const;
	bool isMuc() const;
	QString serverUrl() const;
	void registerSession(ChatViewThemeSession *session);
	void unregisterSession(const QString &sessId);

private slots:
	void _callFinishLoadCalbacks();

public slots:
	void setMetaData(const QVariantMap &map);
	void finishThemeLoading();
	void errorThemeLoading(const QString &error);
	void setHtml(const QString &h);
	void setHttpResourcePath(const QString &relPath);

	// we don't need not text cache since binary data(images?)
	// most likely will be cached by webkit itself
	void toCache(const QString &name, const QVariant &data);

	/**
	 * @brief loads content to cache
	 * @param map(cache_key => file in theme)
	 */
	void saveFilesToCache(const QVariantMap &map);

	/**
	 * @brief That's about applying theme to certian session. So we register session's id in theme and allow theme
	 *        loader in theme's webview to init last parts of theme.
	 *        This is for cases when theme can't init itself fully w/o some knowledge about sesion.
	 * @param sessionId it's the same id as registered on internal web server
	 * @param props a list of proprties' names
	 * @return filled map prop=>value
	 */
	QVariantMap sessionProperties(const QString &sessionId, const QVariantList &props);
	void setCaseInsensitiveFS(bool state = true);
	void setPrepareSessionHtml(bool enabled = true);
	void setSessionHtml(const QString &sessionId, const QString &html);
	QVariantMap checkFilesExist(const QStringList &files, const QString baseDir = QString());
	QString getFileContents(const QString &name) const;
	QString getFileContentsFromAdapterDir(const QString &name) const;
	void setTransparent();
};


// JS Bridge object emedded by theme. Has any logic unrelted to contact itself
class ChatViewThemeJSUtil : public QObject {
	Q_OBJECT

	Theme theme;
	QString psiDefaultAvatarUrl;
	QStringList changedOptions;
	QTimer optChangeTimer;

#ifdef HAVE_QT5
	Q_PROPERTY(QString psiDefaultAvatarUrl MEMBER psiDefaultAvatarUrl CONSTANT)
#else
	Q_PROPERTY(QString psiDefaultAvatarUrl READ getPsiDefaultAvatarUrl CONSTANT)
	QString getPsiDefaultAvatarUrl() const { return psiDefaultAvatarUrl; }
#endif

signals:
	void optionsChanged(const QStringList &);

public:
	ChatViewThemeJSUtil(Theme theme, QObject *parent = 0);
	void putToCache(const QString &key, const QVariant &data);

public slots:
	QVariantMap loadFromCacheMulti(const QVariantList &list);
	QVariant cache(const QString &name) const;
	QString psiOption(const QString &option) const;
	QString psiOptions(const QStringList &options) const;
	QString colorOption(const QString &option) const;
	QString formatDate(const QDateTime &dt, const QString &format) const;
	QString strftime(const QDateTime &dt, const QString &format) const;
	void console(const QString &text) const;
	QString status2text(int status) const;
	QString hex2rgba(const QString &hex, float opacity);
private slots:
	void sendOptionsChanges();
	void optionsChanged(const QString &option);
};

class ChatViewThemePrivate : public ThemePrivate
{
public:
	QString html;
	QString httpRelPath;
	QScopedPointer<ChatViewJSLoader> jsLoader;
	QScopedPointer<ChatViewThemeJSUtil> jsUtil;// it's abslutely the same object for every theme.
	QPointer<WebView> wv;
	QMap<QString,QVariant> cache;
	bool prepareSessionHtml = false; // if html should be generated by JS for each session.
	bool transparentBackground = false;
	QPointer<NetworkAccessManager> nam;

#ifdef WEBENGINE
	QList<QWebEngineScript> scripts;
#else
	QStringList scripts;
#endif
	QList<std::function<void(bool)>> loadCallbacks;

#ifndef WEBENGINE
	QVariant evaluateFromFile(const QString fileName, QWebFrame *frame);
#endif

	friend class ChatViewThemeJSUtil;
#ifndef WEBENGINE
	friend class SessionRequestHandler;
#endif

	ChatViewThemePrivate(ChatViewThemeProvider *provider);

	bool exists();
	bool load(std::function<void(bool)> loadCallback);
	bool hasPreview() const;
	QWidget* previewWidget();

	bool isMuc() const;

	bool isTransparentBackground() const;
#ifndef WEBENGINE
	void embedSessionJsObject(ChatViewThemeSession *session);
#endif
	bool applyToSession(ChatViewThemeSession *session);

	QVariantMap loadFromCacheMulti(const QVariantList &list);
};

#endif // CHATVIEWTHEME_P_H
