#include "KNCenter.h"

KNCenter::KNCenter()
{
	sql = new SqliteHelper("udb.db");
	sql->Open();
	if (!sql->IsTableExist("Users"))
	{
		sql->Excute(R"(CREATE TABLE [Users] (
	[Id] integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
	[UserName] text, 
	[Pwd] text, 
	[CreateTime] long, 
	[LastIP] text,
	[Level] integer, 
	[Parent] integer, 
	[Authority] long, 
	[Products] blob
);)");
	}
	if (!sql->IsTableExist("Cards"))
	{
		sql->Excute(R"(CREATE TABLE [Cards] (
	[Id] integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
	[Code] text, 
	[Enable] integer, 
	[Type] integer, 
	[UID] integer, 
	[CreateTime] long, 
	[HardId] text, 
	[Infomation] text, 
	[EnabledTime] long
);)");
	}
	if (!sql->IsTableExist("CardTypes"))
	{
		sql->Excute(R"(CREATE TABLE [CardTypes] (
	[Id] integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
	[Name] text, 
	[Prefix] text, 
	[TimeOfSeconds] long, 
	[Infomation] text, 
	[File] text
);)");
	}
	if (!sql->IsTableExist("Files"))
	{
		sql->Excute(R"(CREATE TABLE [Files] (
	[Id] integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
	[Name] ntext NOT NULL, 
	[Data] blob
);)");
	}
}
KNCenter::~KNCenter()
{

}
std::unique_ptr<User> KNCenter::CreateUser(std::string uname, std::string pwd, int level, int parent, UINT64 Authority, List<int> products)
{
	if (sql->Select(StringHelper::Format("SELECT [Id] FROM [Users] WHERE [UserName] = '%s'", uname.c_str())).Count > 0)
		return NULL;//用户名已存在
	StringBuilder sb;
	for (auto p : products)
		sb << p << ",";
	bool status = sql->Insert("Users",
		{
			ColumnValue("UserName",		uname),
			ColumnValue("Pwd",			pwd),
			ColumnValue("CreateTime",	DateTime::Now().Data),
			ColumnValue("LastIP",		"NULL"),
			ColumnValue("Level",		level),
			ColumnValue("Parent",		parent),
			ColumnValue("Authority",	Authority),
			ColumnValue("Products",		std::vector<BYTE>((BYTE*)products.data(),(BYTE*)products.data() + (products.size() * sizeof(int)))),
		}
		);
	if (!status)
		return NULL;
	int Id = 0;
	sql->Select(
		StringHelper::Format("SELECT [Id] FROM [Users] WHERE [UserName] = '%s'", uname.c_str()),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			Id = sqlite3_column_int(stmt, 0);
			return true;
		}
	);
	return GetUser(Id);
}
std::unique_ptr<User> KNCenter::GetUser(int id)
{
	std::unique_ptr<User> u = NULL;
	sql->Select(StringHelper::Format("SELECT * FROM [Users] WHERE [Id] = %d", id),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			u = std::unique_ptr<User>(new User());
			u->Id = sqlite3_column_int(stmt, 0);
			u->UserName = sqlite3_column_text(stmt, 1);
			u->Pwd = sqlite3_column_text(stmt, 2);
			u->CreateTime = DateTime(sqlite3_column_int64(stmt, 3));
			u->LastIP = sqlite3_column_text(stmt, 4);
			u->Level = sqlite3_column_int(stmt, 5);
			u->Parent = sqlite3_column_int(stmt, 6);
			u->Authority = sqlite3_column_int64(stmt, 7);

			int blobSize = sqlite3_column_bytes(stmt, 8);
			if (blobSize > 0)
			{
				int* blobData = (int*)sqlite3_column_blob(stmt, 8);
				auto sp = StringHelper::Split(colData[8], { "," });
				for (int i=0;i< blobSize/sizeof(int);i++)
				{
					u->Products.Add(blobData[i]);
				}
			}
			return true;
		}
	);
	if (u)
	{
		sql->Select(StringHelper::Format("SELECT [Id] FROM [Users] WHERE [Parent] = %d", u->Id),
			[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
			{
				u->Childs.Add(sqlite3_column_int64(stmt, 0));
				return false;
			}
		);
	}
	return u;
}
std::unique_ptr<User> KNCenter::GetUser(std::string uname)
{
	std::unique_ptr<User> u = NULL;
	sql->Select(StringHelper::Format("SELECT * FROM [Users] WHERE [UserName] = '%s'", uname.c_str()),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			u = std::unique_ptr<User>(new User());
			u->Id = sqlite3_column_int(stmt, 0);
			u->UserName = sqlite3_column_text(stmt, 1);
			u->Pwd = sqlite3_column_text(stmt, 2);
			u->CreateTime = DateTime(sqlite3_column_int64(stmt, 3));
			u->LastIP = sqlite3_column_text(stmt, 4);
			u->Level = sqlite3_column_int(stmt, 5);
			u->Parent = sqlite3_column_int(stmt, 6);
			u->Authority = sqlite3_column_int64(stmt, 7);
			int blobSize = sqlite3_column_bytes(stmt, 8);
			if (blobSize > 0)
			{
				int* blobData = (int*)sqlite3_column_blob(stmt, 8);
				auto sp = StringHelper::Split(colData[8], { "," });
				for (int i = 0; i < blobSize / sizeof(int); i++)
				{
					u->Products.Add(blobData[i]);
				}
			}
			return true;
		}
	);
	if (u)
	{
		sql->Select(StringHelper::Format("SELECT [Id] FROM [Users] WHERE [Parent] = %d", u->Id),
			[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
			{
				u->Childs.Add(sqlite3_column_int64(stmt, 0));
				return false;
			}
		);
	}
	return u;
}
List<User> KNCenter::GetAllUser()
{
	List<User> result;
	auto se = sql->Select("SELECT * FROM [Users]");
	sql->Select("SELECT * FROM [Users]",
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			User u;
			u.Id = sqlite3_column_int(stmt, 0);
			u.UserName = sqlite3_column_text(stmt, 1);
			u.Pwd = sqlite3_column_text(stmt, 2);
			u.CreateTime = DateTime(sqlite3_column_int64(stmt, 3));
			u.LastIP = sqlite3_column_text(stmt, 4);
			u.Level = sqlite3_column_int(stmt, 5);
			u.Parent = sqlite3_column_int(stmt, 6);
			u.Authority = sqlite3_column_int64(stmt, 7);
			int blobSize = sqlite3_column_bytes(stmt, 8);
			if (blobSize > 0)
			{
				int* blobData = (int*)sqlite3_column_blob(stmt, 8);
				auto sp = StringHelper::Split(colData[8], { "," });
				for (int i = 0; i < blobSize / sizeof(int); i++)
				{
					u.Products.Add(blobData[i]);
				}
			}
			result.Add(u);
			return false;
		});
	for (User& u : result)
	{
		for (User& su : result)
		{
			if (u.Id != su.Id && su.Parent == u.Id)
			{
				u.Childs.Add(su.Id);
			}
		}
	}
	return result;
}
std::unique_ptr<Card> KNCenter::GetCard(int id)
{
	std::unique_ptr<Card> c = NULL;
	sql->Select(StringHelper::Format("SELECT * FROM [Cards] WHERE [Id] = %d", id),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			c = std::unique_ptr<Card>(new Card());
			c->Id = sqlite3_column_int(stmt, 0);
			c->Code = sqlite3_column_text(stmt, 1);
			c->Enable = sqlite3_column_int(stmt, 2);
			c->Type = sqlite3_column_int(stmt, 3);
			c->UserId = sqlite3_column_int(stmt, 4);
			c->CreateTime = DateTime(sqlite3_column_int64(stmt, 5));
			c->HardId = sqlite3_column_text(stmt, 6);
			c->Info = sqlite3_column_text(stmt, 7);
			c->EnabledTime = DateTime(sqlite3_column_int64(stmt, 8));
			return true;
		});
	return c;
}
std::unique_ptr<Card> KNCenter::GetCard(std::string code)
{
	std::unique_ptr<Card> c = NULL;
	sql->Select(StringHelper::Format("SELECT * FROM [Cards] WHERE [Code] = '%s'", code.c_str()),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			c = std::unique_ptr<Card>(new Card());
			c->Id = sqlite3_column_int(stmt, 0);
			c->Code = sqlite3_column_text(stmt, 1);
			c->Enable = sqlite3_column_int(stmt, 2);
			c->Type = sqlite3_column_int(stmt, 3);
			c->UserId = sqlite3_column_int(stmt, 4);
			c->CreateTime = DateTime(sqlite3_column_int64(stmt, 5));
			c->HardId = sqlite3_column_text(stmt, 6);
			c->Info = sqlite3_column_text(stmt, 7);
			c->EnabledTime = DateTime(sqlite3_column_int64(stmt, 8));
			return true;
		});
	return c;
}
List<Card> KNCenter::GetAllCard()
{
	List<Card> result;
	auto se = sql->Select("SELECT * FROM [Cards]");
	sql->Select("SELECT * FROM [Cards]",
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			Card c;
			c.Id = sqlite3_column_int(stmt, 0);
			c.Code = sqlite3_column_text(stmt, 1);
			c.Enable = sqlite3_column_int(stmt, 2);
			c.Type = sqlite3_column_int(stmt, 3);
			c.UserId = sqlite3_column_int(stmt, 4);
			c.CreateTime = DateTime(sqlite3_column_int64(stmt, 5));
			c.HardId = sqlite3_column_text(stmt, 6);
			c.Info = sqlite3_column_text(stmt, 7);
			c.EnabledTime = DateTime(sqlite3_column_int64(stmt, 8));
			result.Add(c);
			return false;
		});
	return result;
}
List<Card> KNCenter::GetAllCardForUser(int uid)
{
	List<Card> result;
	sql->Select(StringHelper::Format("SELECT * FROM [Cards] WHERE [UID] = '%d'", uid),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			Card c;
			c.Id = sqlite3_column_int(stmt, 0);
			c.Code = sqlite3_column_text(stmt, 1);
			c.Enable = sqlite3_column_int(stmt, 2);
			c.Type = sqlite3_column_int(stmt, 3);
			c.UserId = sqlite3_column_int(stmt, 4);
			c.CreateTime = DateTime(sqlite3_column_int64(stmt, 5));
			c.HardId = sqlite3_column_text(stmt, 6);
			c.Info = sqlite3_column_text(stmt, 7);
			c.EnabledTime = DateTime(sqlite3_column_int64(stmt, 8));
			result.Add(c);
			return false;
		});
	return result;
}
std::unique_ptr<CardType> KNCenter::CreateCardType(std::string name, std::string prefix, UINT64 timeOfSeconds, std::string info, std::string file)
{
	if (sql->Select(StringHelper::Format("SELECT * FROM [CardTypes] WHERE [Name] = '%s'", name.c_str())).Count > 0)
		return NULL;//卡名已存在
	int status = sql->Excute(StringHelper::Format(
		R"(INSERT INTO [CardTypes]([Name],[Prefix],[TimeOfSeconds],[Infomation],[File])VALUES('%s','%s',%llu,'%s','%s'))",
		name.c_str(), prefix.c_str(), timeOfSeconds, info.c_str(), file.c_str()));
	if (status)
		return NULL;
	int Id = Convert::ToInt32(
		sql->Select(StringHelper::Format("SELECT [Id] FROM [CardTypes] WHERE [Name] = '%s'", name.c_str()))[0][0]
		);
	return GetCardType(Id);
}
std::unique_ptr<CardType> KNCenter::GetCardType(int id)
{
	std::unique_ptr<CardType> c = NULL;
	sql->Select(StringHelper::Format("SELECT * FROM [CardTypes] WHERE [Id] = %d", id),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			c = std::unique_ptr<CardType>(new CardType());
			c->Id = sqlite3_column_int(stmt, 0);
			c->TypeName = sqlite3_column_text(stmt, 1);
			c->Prefix = sqlite3_column_text(stmt, 2);
			c->TimeOfSeconds = sqlite3_column_int64(stmt, 3);
			c->Infomation = sqlite3_column_text(stmt, 4);
			c->File = sqlite3_column_text(stmt, 5);
			return true;
		});
	return c;
}
std::unique_ptr<CardType> KNCenter::GetCardType(std::string name)
{
	std::unique_ptr<CardType> c = NULL;
	sql->Select(StringHelper::Format("SELECT * FROM [CardTypes] WHERE [Name] = '%s'", name.c_str()),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			c = std::unique_ptr<CardType>(new CardType());
			c->Id = sqlite3_column_int(stmt, 0);
			c->TypeName = sqlite3_column_text(stmt, 1);
			c->Prefix = sqlite3_column_text(stmt, 2);
			c->TimeOfSeconds = sqlite3_column_int64(stmt, 3);
			c->Infomation = sqlite3_column_text(stmt, 4);
			c->File = sqlite3_column_text(stmt, 5);
			return true;
		});
	return c;
}
List<CardType> KNCenter::GetAllCardType()
{
	List<CardType> result;
	auto se = sql->Select("SELECT * FROM [CardTypes]");
	sql->Select("SELECT * FROM [CardTypes]",
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			CardType c;
			c.Id = sqlite3_column_int(stmt, 0);
			c.TypeName = sqlite3_column_text(stmt, 1);
			c.Prefix = sqlite3_column_text(stmt, 2);
			c.TimeOfSeconds = sqlite3_column_int64(stmt, 3);
			c.Infomation = sqlite3_column_text(stmt, 4);
			c.File = sqlite3_column_text(stmt, 5);
			result.Add(c);
			return false;
		});
	return result;
}
std::string KNCenter::CreateCard(int uid,int type, std::string info)
{
	std::unique_ptr<CardType> _type = GetCardType(type);
	std::string newCode = _type->Prefix + Guid::NewGuid().ToString();
	DateTime now = DateTime::Now();
	sql->Excute(StringHelper::Format("INSERT INTO [Cards] ([Code], [Enable], [Type], [UID], [CreateTime], [HardId], [Infomation], [EnabledTime]) VALUES ('%s', 1, %d, %d, %llu, '', '%s', 0)",
		newCode.c_str(), type, uid, now.Data, info.c_str()));
	return newCode;
}
VerificationState KNCenter::CheckCard(std::string code, std::string hard)
{
	auto card = GetCard(code);
	if (!card)
		return VerificationState::InvalidCode;
	if(!card->Enable)
		return VerificationState::Disabled;
	if (card->EnabledTime.Data == 0)
	{
		card->EnabledTime = DateTime::Now();
		auto se = sql->Excute(StringHelper::Format("UPDATE [Cards] SET [Enable] = 1, [EnabledTime] = %llu, [HardId] = '%s' WHERE [Id] = %d", 
			card->EnabledTime.Data, hard.c_str(), card->Id));
	}
	else
	{
		if (card->HardId != hard)
			return VerificationState::DifferentDevices;
	}
	std::unique_ptr<CardType> _type = GetCardType(card->Type);
	DateTime endTime = DateTime(card->EnabledTime.Data + (_type->TimeOfSeconds * 10000000));
	if(DateTime::Now().Data >= endTime.Data)
		return VerificationState::Expired;
	return VerificationState::Verified;
}
void KNCenter::DeleteCard(std::string code)
{
	sql->Excute(StringHelper::Format("DELETE FROM [Cards] WHERE [Code] = '%s'", code.c_str()));
}
void KNCenter::DisableCard(std::string code)
{
	sql->Excute(StringHelper::Format("UPDATE [Cards]  SET [Enable] = 0 WHERE [Code] = '%s'", code.c_str()));
}
void KNCenter::UpdateFile(std::string name, std::vector<BYTE> file)
{
	if (sql->Select(StringHelper::Format("SELECT [Id] FROM [Files] WHERE [Name] = '%s'", name.c_str())).Count > 0)
	{
		sqlite3_stmt* stmt;
		int rc = sqlite3_prepare_v2(sql->pDB, StringHelper::Format("UPDATE [Files] SET [Data] = ? WHERE [Name] = '%s'", name.c_str()).c_str(), -1, &stmt, 0);
		if (rc == SQLITE_OK) {
			sqlite3_bind_blob(stmt, 1, file.data(), file.size(), SQLITE_TRANSIENT);
			rc = sqlite3_step(stmt);
			sqlite3_finalize(stmt);
		}
	}
	else
	{
		sqlite3_stmt* stmt;
		int rc = sqlite3_prepare_v2(sql->pDB, StringHelper::Format("INSERT INTO [Files]([Name],[Data])VALUES('%s',?)", name.c_str()).c_str(), -1, &stmt, 0);
		if (rc == SQLITE_OK) {
			sqlite3_bind_blob(stmt, 1, file.data(), file.size(), SQLITE_TRANSIENT);
			rc = sqlite3_step(stmt);
			sqlite3_finalize(stmt);
		}
	}
}
std::vector<BYTE> KNCenter::GetFile(std::string name)
{
	std::vector<BYTE> result = std::vector<BYTE>();

	sql->Select(StringHelper::Format("SELECT [Data] FROM [Files] WHERE [Name] = '%s'", name.c_str()),
		[&](int columns, char** colData, char** colNames, sqlite3_stmt* stmt)
		{
			BYTE* blobData = (BYTE*)sqlite3_column_blob(stmt, 0);
			int blobSize = sqlite3_column_bytes(stmt, 0);
			result = std::vector<BYTE>(blobData, blobData + blobSize);
			return true;
		});
	return result;
}

