#include "sqlitehelper.h"
#include <QMessageBox>
#include "globalvariables.h"
#include "MyButton.h"
#include <Windows.h>
#include <ShObjIdl.h>
#include <PropKey.h>
#include <ShlObj.h>
#include <QtXml/QtXml>
#include <QtSvg/QtSvg>
#include "navbar.h"
#include "netio.h"
#include "config.h"
#ifdef _DEBUG
#pragma comment (lib,"Qt5Xmld.lib")
#else
#pragma comment (lib,"Qt5Xml.lib")
#endif
#pragma comment (lib,"Shell32.lib")
#if _MSC_VER >=1936
#include <filesystem>
namespace fs = std::filesystem;
#else
#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
#endif
SQLiteHelper::SQLiteHelper(QObject *parent)
	: QObject(parent)
{
	if (QSqlDatabase::contains("qt_sql_default_connection"))
	{
		db = QSqlDatabase::database("qt_sql_default_connection");
	}
	else
	{
		db = QSqlDatabase::addDatabase("QSQLITE");
		db.setDatabaseName("OfficeAssistant.db");
	}
	if (!db.open())
	{
		QMessageBox::critical(nullptr, QString::fromLocal8Bit("提示"), QString::fromLocal8Bit("无法打开数据库"));
		exit_manager.exit(1);
	}
}

SQLiteHelper::~SQLiteHelper()
{
	db.close();
}

bool SQLiteHelper::update_software()
{
	HKEY hKeyUninstall = nullptr;
	QMap<QString, Record> records;
	QList<QString> paths;
	/*QSqlQuery query;
	QString sql = "select * from kmd_menu;";
	query.exec(sql);
	while(query.next())
	{
		Record record;
		record.id = query.value("id").toInt();
		record.sort = query.value("sort").toInt();
		record.app_id = query.value("app_id").toString();
		record.locked = query.value("locked").toBool();
		record.type = query.value("type").toString();
		record.category_id = query.value("category_id").toString();
		record.name = query.value("name").toString();
		record.orig_name = query.value("orig_name").toString();
		record.version = query.value("version").toString();
		record.dev = query.value("dev").toString();
		record.create_time = query.value("create_time").toLongLong();
		record.use_time = query.value("use_time").toLongLong();
		record.op = query.value("op").toString();
		record.func = query.value("func").toString();
		record.path = query.value("path").toString();
		record.url = query.value("url").toString();
		QStringList path_list = record.path.split("\\");
		path_list.removeLast();
		QString path;
		for(auto str : path_list)
		{
			path.append(str);
			path.append("\\");
		}
		path.remove(path.length() - 1, 1);
		records.insert(path, record);
	}*/
	//开始菜单中已安装软件列表
	WCHAR path[MAX_PATH];
	HRESULT hr = SHGetFolderPathW(nullptr, CSIDL_COMMON_PROGRAMS, nullptr, 0, path);//获取ProgramData中开始菜单的路径
	std::wstring path_str(path);
	
	for(auto file : fs::directory_iterator(path_str))
	{
		Record record;
		if(fs::is_regular_file(file))
		{
			if(file.path().extension().wstring()==L".lnk")
			{
				HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
				if (SUCCEEDED(hr))
				{
					IShellItem* pShellItem;
					hr = SHCreateItemFromParsingName(file.path().wstring().c_str(), nullptr, IID_PPV_ARGS(&pShellItem));
					if (SUCCEEDED(hr))
					{
						IPersistFile* pPersistFile;
						hr = pShellItem->QueryInterface(IID_PPV_ARGS(&pPersistFile));
						if (SUCCEEDED(hr))
						{
							WCHAR szTargetPath[MAX_PATH];
							LPOLESTR pszTargetPath = szTargetPath;
							hr = pPersistFile->Load(nullptr, STGM_READ);
							if (SUCCEEDED(hr))
							{
								hr = pPersistFile->GetCurFile(&pszTargetPath);
								if (SUCCEEDED(hr))
								{
									paths<<QString::fromWCharArray(szTargetPath);
								}
								else
								{
									pPersistFile->Release();
									pShellItem->Release();
									CoUninitialize();
									return false;
								}
							}else
							{
								pPersistFile->Release();
								pShellItem->Release();
								CoUninitialize();
								return false;
							}
							pPersistFile->Release();
						}else
						{
							pShellItem->Release();
							pShellItem->Release();
							CoUninitialize();
							return false;
						}
						pShellItem->Release();
					}else
					{
						CoUninitialize();
						return false;
					}
					CoUninitialize();
					

				}
			}
		}
	}
	for(int i=0;i<sizeof(path)/sizeof(wchar_t);i++)
	{
		path[i] = 0;
	}
	hr = SHGetFolderPathW(nullptr, CSIDL_PROGRAMS, nullptr, 0, path);//获取用户文件夹中开始菜单的路径
	path_str.clear();
	path_str = std::wstring(path);
	for (auto file : fs::directory_iterator(path_str))
	{
		Record record;
		if (fs::is_regular_file(file))
		{
			if (file.path().extension().wstring() == L".lnk")
			{
				HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
				if (SUCCEEDED(hr))
				{
					IShellItem* pShellItem;
					hr = SHCreateItemFromParsingName(file.path().wstring().c_str(), nullptr, IID_PPV_ARGS(&pShellItem));
					if (SUCCEEDED(hr))
					{
						IPersistFile* pPersistFile;
						hr = pShellItem->QueryInterface(IID_PPV_ARGS(&pPersistFile));
						if (SUCCEEDED(hr))
						{
							WCHAR szTargetPath[MAX_PATH];
							LPOLESTR pszTargetPath = szTargetPath;
							hr = pPersistFile->Load(nullptr, STGM_READ);
							if (SUCCEEDED(hr))
							{
								hr = pPersistFile->GetCurFile(&pszTargetPath);
								if (SUCCEEDED(hr))
								{
									paths << QString::fromWCharArray(szTargetPath);
								}
								else
								{
									pPersistFile->Release();
									pShellItem->Release();
									CoUninitialize();
									return false;
								}
							}
							else
							{
								pPersistFile->Release();
								pShellItem->Release();
								CoUninitialize();
								return false;
							}
							pPersistFile->Release();
						}
						else
						{
							pShellItem->Release();
							pShellItem->Release();
							CoUninitialize();
							return false;
						}
						pShellItem->Release();
					}
					else
					{
						CoUninitialize();
						return false;
					}
					CoUninitialize();
				}
			}
		}
	}
	// 打开注册表中的已安装软件列表
	QHash<QString, Record> reg_records;
	HKEY hKey;
	if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
		L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall",
		0, KEY_READ, &hKey) == ERROR_SUCCESS)
	{
		// 枚举该列表下所有子键
		for (DWORD i = 0; ; i++)
		{
			WCHAR szSubKey[MAX_PATH] = { 0 };
			DWORD dwSize = MAX_PATH;
			if (RegEnumKeyExW(hKey, i, szSubKey, &dwSize, NULL, NULL, NULL, NULL)
				== ERROR_SUCCESS)
			{
				// 读取软件属性值
				HKEY hSubKey;
				if (RegOpenKeyExW(hKey, szSubKey, 0, KEY_READ, &hSubKey) == ERROR_SUCCESS)
				{
					Record record;
					WCHAR szProductPath[MAX_PATH] = { 0 };
					WCHAR buffer[MAX_PATH] = { 0 };
					DWORD buffer_num;
					dwSize = MAX_PATH * sizeof(WCHAR);
					//安装文件夹
					if (RegQueryValueExW(hSubKey, L"InstallLocation", NULL, NULL,
						(LPBYTE)szProductPath, &dwSize) != ERROR_SUCCESS)
					{
						RegCloseKey(hSubKey);
						RegCloseKey(hKey);
						return false;
					}
					QString path = QString::fromWCharArray(szProductPath);
					//软件名
					if (RegQueryValueExW(hSubKey, L"DisplayName", NULL, NULL,
						(LPBYTE)buffer, &dwSize) != ERROR_SUCCESS)
					{
						RegCloseKey(hSubKey);
						RegCloseKey(hKey);
						return false;
					}
					record.name = QString::fromWCharArray(buffer);
					record.orig_name = QString::fromWCharArray(buffer);
					//图标
					if (RegQueryValueExW(hSubKey, L"DisplayIcon", NULL, NULL,
						(LPBYTE)buffer, &dwSize) != ERROR_SUCCESS)
					{
						RegCloseKey(hSubKey);
						RegCloseKey(hKey);
						return false;
					}
					record.logo = QString::fromWCharArray(buffer);
					//主版本号
					if (RegQueryValueExW(hSubKey, L"VersionMajor", NULL, NULL,
						(LPBYTE)buffer_num, &dwSize) != ERROR_SUCCESS)
					{
						RegCloseKey(hSubKey);
						RegCloseKey(hKey);
						return false;
					}
					QString versionMajor = QString::number(buffer_num);
					//次版本号
					if (RegQueryValueExW(hSubKey, L"VersionMinor", NULL, NULL,
						(LPBYTE)buffer_num, &dwSize) != ERROR_SUCCESS)
					{
						RegCloseKey(hSubKey);
						RegCloseKey(hKey);
						return false;
					}
					QString versionMinor = QString::number(buffer_num);
					//将主版本号和次版本号拼接在一起
					QString version = versionMajor + "." + versionMinor;
					record.version = version;
					//开发者
					if (RegQueryValueExW(hSubKey, L"Publisher", NULL, NULL,
						(LPBYTE)buffer, &dwSize) != ERROR_SUCCESS)
					{
						RegCloseKey(hSubKey);
						RegCloseKey(hKey);
						return false;
					}
					record.dev = QString::fromWCharArray(buffer);
					record.type = "app";
					record.locked = false;
					RegCloseKey(hSubKey);
					reg_records.insert(path, record);
				}
			}
			else
			{
				break;
			}
		}
		RegCloseKey(hKey);
	}
	//对比两个路径，找出公共部分
	QHash<QString, Record> public_programs_list;
	for(auto path:paths)
	{
		QStringList path_list = path.split("\\");
		path_list.removeLast();
		QString path2;
		for(auto str : path_list)
		{
			path2.append(str);
			path2.append("\\");
		}
		path2.remove(path2.length() - 1, 1);
		if(reg_records.contains(path2))
		{
			reg_records[path2].path = path;
			public_programs_list.insert(reg_records[path2].orig_name, reg_records[path2]);
		}
	}
	//进行网络请求，补全字段
	SoftwareRequest software_request;
	if(!software_request.sendRequest(&public_programs_list))
	{
		return false;
	}
	QSqlQuery begin("begin;");
	if (!begin.exec())
	{
		return false;
	}
	for(auto key : public_programs_list.keys())
	{
		
		QString sql_find = "select sort from kmd_menu where orig_name='";
		sql_find += key;
		sql_find += "';";
		QSqlQuery query_find(sql_find);
		if(!query_find.exec())
		{
			QSqlQuery rollback("rollback;");
			rollback.exec();
			return false;
		}
		QString sql;
		if(query_find.next())
		{
			sql = "update kmd_menu set";
			sql += " path='";
			sql += public_programs_list[key].path;
			sql += "'";
			sql += " op=";
			sql += public_programs_list[key].op;
			sql += " func=";
			sql += public_programs_list[key].func;
			sql += " url=";
			sql += public_programs_list[key].url;
			sql += " where orig_name='";
			sql += key;
			sql += "';";
		}
		else
		{
			sql = "insert into kmd_menu (sort,app_id,locked,type,category_id,name,orig_name,version,dev,create_time,use_time,op,func,path,url) values (";
			sql += "50";
			sql += ",'";
			sql += public_programs_list[key].app_id;
			sql += "',";
			sql += QString::number(public_programs_list[key].locked);
			sql += ",'";
			sql += public_programs_list[key].type;
			sql += "','";
			sql += public_programs_list[key].category_id;
			sql += "','";
			sql += public_programs_list[key].name;
			sql += "','";
			sql += public_programs_list[key].orig_name;
			sql += "','";
			sql += public_programs_list[key].version;
			sql += "','";
			sql += public_programs_list[key].dev;
			sql += "',";
			sql += QString::number(public_programs_list[key].create_time);
			sql += ",";
			sql += QString::number(public_programs_list[key].use_time);
			sql += ",'";
			sql += public_programs_list[key].op;
			sql += "','";
			sql += public_programs_list[key].func;
			sql += "','";
			sql += public_programs_list[key].path;
			sql += "','";
			sql += public_programs_list[key].url;
			sql += "');";
		}
		QSqlQuery query(sql);
		if(!query.exec())
		{
			QSqlQuery rollback("rollback;");
			rollback.exec();
			return false;
		}
	}
	QSqlQuery commit("commit;");
	commit.exec();
	return true;
}
void SetSVGBackColor(QDomElement& elem, QString strtagname, QString strattr, QString strattrval)
{
	if (elem.tagName().compare(strtagname) == 0)
	{
		QString before_color = elem.attribute(strattr);
		elem.setAttribute(strattr, strattrval);
		QString color = elem.attribute(strattr);
	}
	for (int i = 0; i < elem.childNodes().count(); i++)
	{
		if (!elem.childNodes().at(i).isElement())
		{
			continue;
		}
		SetSVGBackColor(elem.childNodes().at(i).toElement(), strtagname, strattr, strattrval);
	}
}
bool SQLiteHelper::get_software(QList<ButtonStruct>* buttons)
{
	QSqlQuery query(db);
	QString sql = "select * from kmd_menu;";
	if (!query.exec(sql))
	{
		return false;
	}
	QByteArray* buffer = new QByteArray;
	while (query.next())
	{
		QNetworkAccessManager manager;
		downloadSuccess = true;
		ButtonStruct button_struct;
		button_struct.path = query.value("path").toString();
		button_struct.text = query.value("name").toString();
		button_struct.orig_name = query.value("orig_name").toString();
		QUrl url_image(query.value("logo").toString());
		QNetworkRequest* request_image = new QNetworkRequest(url_image);
		reply = manager.get(*request_image);
		QTimer timer;
		timer.setInterval(5000);
		connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
		connect(&timer, &QTimer::timeout, this, &SQLiteHelper::cancelDownload);
		eventLoop.exec();
		timer.stop();
		QImage* image = new QImage(200, 200, QImage::Format_ARGB32);
		if (downloadSuccess) {
			*buffer = reply->readAll();
			QSvgRenderer* render_image = new QSvgRenderer(*buffer);
			QPainter painter_image(image);
			painter_image.setCompositionMode(QPainter::CompositionMode_Clear); // 清除画布
			painter_image.fillRect(image->rect(), Qt::transparent); // 填充透明色
			painter_image.setCompositionMode(QPainter::CompositionMode_SourceOver);     // 恢复默认值
			render_image->render(&painter_image);
			buffer->clear();
			delete render_image;
		}
		else
		{
			QString icon = QApplication::applicationDirPath() + "/icon/default.svg";
			QFile file(icon);
			if(!file.open(QIODevice::ReadOnly))
			{
				return false;
			}
			QByteArray svg_buffer = file.readAll();
			file.close();
			QDomDocument doc;
			doc.setContent(svg_buffer);
			QColor color;
			color.setNamedColor(DEFAULT_COLOR);
			SetSVGBackColor(doc.documentElement(), "path", "fill",QColor() );

			
		}
		reply->close();
		button_struct.image = image;
		*buttons << button_struct;
	}
	return true;
}

void SQLiteHelper::cancelDownload() {
	disconnect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
	eventLoop.quit();
	reply->abort();
	downloadSuccess = false;
}
bool SQLiteHelper::update_others()
{
	
}