#include "SqlCore.h"
#include <QThread>
#include <QDebug>
#include <QSqlError>
#include <QFile>


QMap<QString, QMap<QString, QMutex*>> SqlCore::mutexMap;

QString SqlCore::msDriverName;
QString SqlCore::msPasswd;
QString SqlCore::msUserName;
QString SqlCore::msDBFile;
QMutex  SqlCore::mWriteMutex;
void SqlCore::init(QString sDriver, QString sUser, QString sPasswd, QString sDBFile)
{
	QByteArray base64User(sUser.toUtf8());
	QByteArray base64Passwd(sPasswd.toUtf8());
	msDriverName = sDriver;
	msUserName = base64User.toBase64();
	msPasswd = base64Passwd.toBase64();
	msDBFile = sDBFile;
}

bool SqlCore::setKey(QString sDriver,QString sConnect, QString sUser, QString sPasswd, QString sdbFile)
{
	bool ok = false;
	QSqlDatabase dataBase = QSqlDatabase::addDatabase(sDriver, sConnect);
	if (QFile::exists(sdbFile))
	{
	 
		QByteArray base64User(sUser.toUtf8());
		QByteArray base64Passwd(sPasswd.toUtf8());
		dataBase.setUserName(base64User.toBase64());
		dataBase.setDatabaseName(sdbFile);//
		dataBase.setPassword(base64Passwd.toBase64());
		if (sPasswd.isEmpty())
		{
			dataBase.setConnectOptions("QSQLITE_REMOVE_KEY");
            //logInfo() << QString::fromLocal8Bit("����") << endl;
		}
		else
		{
			dataBase.setConnectOptions("QSQLITE_CREATE_KEY");
            //logInfo() << QString::fromLocal8Bit("����") << endl;
		}
		if (!dataBase.open())
		{
            //logError() << QString::fromLocal8Bit("�������") << endl;
			ok = false;
		}
		else
		{
			ok = true;
		}
	}
	dataBase.close();
	return ok;
}

bool SqlCore::updateKey(QString NewsPasswd, QString oldPasswd)
{
	bool ok = false;
	getSqlDataBase().setPassword(oldPasswd);
	getSqlDataBase().setConnectOptions("QSQLITE_UPDATE_KEY=" + NewsPasswd);
	ok = getSqlDataBase().open();
	if (!ok)
	{
        //logError() << "updatePasswd: " << getSqlDataBase().lastError().driverText();
		ok = false;
	}
	return ok;
}

bool SqlCore::execute(QString sql )
{
	QMutexLocker lockTemp(&mWriteMutex);
	QString connName = QString("%1(%2)").arg(msDBFile).arg(QString::number(qint64(QThread::currentThread()), 16));//�ļ��� + �߳�
	//qDebug() << "execute:" << connName << endl;
    QSqlDatabase t = getSqlDataBase( );
    mutexMap[msDBFile][connName]->lock();
    if (!t.isOpen())
        t.open(msUserName,msPasswd);
    QSqlQuery sqlQuery(t);
    bool flag = sqlQuery.exec(sql);
	if (!flag)
	{
        qDebug() << connName << sqlQuery.lastError().text() << endl;
	}
    mutexMap[msDBFile][connName]->unlock();
    return flag;
}

 
 

QSharedPointer<QSqlQuery> SqlCore::select(QString sql)
{
	//QMutexLocker lockTemp(&mWriteMutex);
	QString connName = QString("%1(%2)").arg(msDBFile).arg(QString::number(qint64(QThread::currentThread()), 16));//�ļ��� + �߳�
	//qDebug() << "select:" << connName << endl;
    QSqlDatabase t = getSqlDataBase();

    mutexMap[msDBFile][connName]->lock();
    if (!t.isOpen())
        t.open(msUserName,msPasswd);
   // QSqlQuery *sqlQuery = new QSqlQuery(t);
	//QSharedPointer<QSqlQuery> sqlQuery = new QSharedPointer<QSqlQuery(t)>;
	QSharedPointer<QSqlQuery> sqlQuery = QSharedPointer<QSqlQuery>(new QSqlQuery(t));
    if (!sqlQuery->exec(sql)) {
        //logError() << "CSqlCore::select() sql = " << sql << sqlQuery->lastError().text() << " failed!" << endl;
	}

    mutexMap[msDBFile][connName]->unlock();
    return sqlQuery;
}

QSharedPointer<QSqlQuery> SqlCore::select(QString sql, bool& ok)
{
	//QMutexLocker lockTemp(&mWriteMutex);
	QString connName = QString("%1(%2)").arg(msDBFile).arg(QString::number(qint64(QThread::currentThread()), 16));//�ļ��� + �߳�
	//qDebug() << "select:" << connName << endl;
	QSqlDatabase t = getSqlDataBase();

	mutexMap[msDBFile][connName]->lock();
	if (!t.isOpen())
		t.open(msUserName, msPasswd);
	// QSqlQuery *sqlQuery = new QSqlQuery(t);
	//QSharedPointer<QSqlQuery> sqlQuery = new QSharedPointer<QSqlQuery(t)>;
	QSharedPointer<QSqlQuery> sqlQuery = QSharedPointer<QSqlQuery>(new QSqlQuery(t));
	ok = sqlQuery->exec(sql);
	if (!ok) 
	{
        //logError() << "CSqlCore::select() sql = " << sql << sqlQuery->lastError().text() << " failed!" << endl;
	}

	mutexMap[msDBFile][connName]->unlock();
	return sqlQuery;
}

void SqlCore::destroyConn()
{
	QString connName = QString("%1(%2)").arg(msDBFile).arg(QString::number(qint64(QThread::currentThread()), 16));//�ļ��� + �߳�
	//qDebug() << "destroyConn:" << connName << endl;
    if (!QSqlDatabase::contains( connName))
        return;
    QSqlDatabase t = QSqlDatabase::database(connName);
    if (t.isOpen())
        t.close();
    QSqlDatabase::removeDatabase( connName);
    delete mutexMap[msDBFile][connName];
    mutexMap[msDBFile].remove(connName);
    if (mutexMap[msDBFile].keys().length() == 0)
        mutexMap.remove(msDBFile);
}

void SqlCore::destroyOneDBConn()
{
   // foreach (QString i, mutexMap[msDBFile].keys())
    {
        destroyConn();
    }
}

void SqlCore::destroyAllDBConn()
{
   // foreach (QString i, mutexMap.keys())
   // {
        destroyOneDBConn();
   // }
}

QSqlDatabase SqlCore::getSqlDataBase()
{
	QString connName = QString("%1(%2)").arg(msDBFile).arg(QString::number(qint64(QThread::currentThread()), 16));//�ļ��� + �߳�
    if (!QSqlDatabase::contains(connName))
    {
        QSqlDatabase database = QSqlDatabase::addDatabase(msDriverName, connName);
        database.setDatabaseName(msDBFile);
		database.setUserName(msUserName);
		database.setPassword(msPasswd);
        if (!mutexMap.contains(msDBFile))
        {
            QMap<QString, QMutex*> tMap;
            mutexMap.insert(msDBFile, tMap);
        }
		if (database.isOpen() || database.open())
		{
			QSqlQuery query(database);
			query.exec("PRAGMA journal_mode=WAL;"); // ����WALģʽ
			query.finish();
			query.clear();
		}
		else
		{
            //logWarning() << "DB open failed! " << database.lastError().text() << endl;
		}
        QMutex *mutex = new QMutex();
        mutexMap[msDBFile].insert(connName, mutex);
    }
    return QSqlDatabase::database( connName);
}