#include <QDebug>
#include <QRegularExpression>
#include "script_analyzer.h"
#include "SH_runtime.h"
#include "SH_plugins_manager.h"


QSet<QString> ScriptAnalyzer::getUsedPlugins(const QString & full_script) {
	if (!RUNTIME->plugins_manager) return {};
	auto pl = RUNTIME->plugins_manager->localInterface().getPlugins(SHPluginBase::Script);
	QSet<QString> ret;
	PIMap<QString, QString> all_plugins;
	for (const auto & p: pl) {
		if (!p.plugin) continue;
		if (!all_plugins.contains(p.plugin->name()))
			all_plugins[p.plugin->name()] = p.manifest.name;
	}
	QString script = full_script;
	ScriptAnalyzer::removeStrings(script);
	ScriptAnalyzer::removeComments(script);

	auto it = all_plugins.makeIterator();
	while (it.next()) {
		auto pattern = QRegularExpression("\\b" + it.key() + "\\b");
		auto matchIterator = pattern.globalMatch(script);
		if (matchIterator.hasNext()) {
			//qDebug() << "found" << it.key() << "->" << it.value();
			ret << it.value();
		}
	}

	return ret;
}


void ScriptAnalyzer::removeStrings(QString & full_script) {
	if (full_script.size() <= 2) return;
	for (auto cs: {"\"", "'", "`"}) {
		auto ranges = ScriptAnalyzer::findRanges(full_script, cs);
		for (int i = ranges.size() - 1; i >= 0; --i)
			full_script.remove(ranges[i].first, ranges[i].second);
	}
}


void ScriptAnalyzer::removeComments(QString & full_script) {
	if (full_script.size() <= 2) return;
	auto ranges = ScriptAnalyzer::findRanges(full_script, "/*", "*/");
	removeRanges(full_script, ranges);
	auto expression = QRegularExpression("//[^\\n]*");
	auto matchIterator = expression.globalMatch(full_script);
	ranges.clear();
	while (matchIterator.hasNext()) {
		auto match = matchIterator.next();
		ranges << qMakePair(match.capturedStart(), match.capturedLength());
	}
	removeRanges(full_script, ranges);
}


QList<QPair<int, int> > ScriptAnalyzer::findRanges(const QString & full_script, const QString & start_str, const QString & end_str_v) {
	QList<QPair<int, int> > ret;
	QString end_str = end_str_v;
	if (end_str.isEmpty()) end_str = start_str;
	int end_add = end_str.size() - 1;
	int si = full_script.indexOf(start_str), ei = 0, end = false;
	while (si >= 0) {
		bool esc = false;
		if (!end) {
			if (si > 0)
				esc = full_script[si - 1].toLatin1() == '\\';
			if (esc) {
				si = full_script.indexOf(start_str, si + 1);
				continue;
			}
			end = true;
			ei = si;
			continue;
		} else {
			esc = true;
			while (esc && ei >= 0) {
				ei = full_script.indexOf(end_str, ei + 1);
				if (ei > 0)
					esc = full_script[ei - 1].toLatin1() == '\\';
				else
					esc = false;
			}
			if (ei < 0) break;
		}
		end = false;
		ret << qMakePair(si, ei - si + 1 + end_add);
		si = full_script.indexOf(start_str, ei + 1);
	}
	return ret;
}


void ScriptAnalyzer::removeRanges(QString & full_script, const QList<QPair<int, int> > & ranges) {
	for (int i = ranges.size() - 1; i >= 0; --i)
		full_script.remove(ranges[i].first, ranges[i].second);
}
