#include <amxmodx>
#include <fakemeta>

#define PLUGIN "Registration System"
#define VERSION "1.2"
#define AUTHOR "mforce"


new const PREFIX[] = "RegSystem"

// If you want to use the SQL remove the // characters before the #. (default is file)
//#define SQL

#if defined SQL
	#include <sqlx>
	new Handle:g_SqlTuple;
	new Query[512], text[512];
	
	new const SQL_INFO[][] = {
		"127.0.0.1",	// HOST
		"username",		// USERNAME
		"password",		// PASSWORD
		"database"		// DATABASE
	}
#else
	new filename[128];
#endif

new bool:registered[33];
new bool:loggedin[33];
new username[33][32], password[33][32], writepass[33][32];

public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	register_clcmd("say /reg", "reg_menu")
	register_clcmd("TYPE_PASSWORD", "Type_password")
	register_clcmd("NEW_PASSWORD", "New_password")
	register_cvar("reg_system", AUTHOR, FCVAR_SERVER | FCVAR_SPONLY);
	register_dictionary("reg_system.txt");
	register_forward(FM_ClientUserInfoChanged, "ClientUserInfoChanged")
	set_task(60.0, "regcheck", .flags = "b");
	
	#if !defined SQL
	get_localinfo("amxx_configsdir", filename, charsmax(filename))
	format(filename, charsmax(filename), "%s/registration_system.ini", filename)
	#endif
}

public regcheck() {
	new players[32], num;
	get_players(players, num, "ch")
	for(new i = 0; i < num; i++) {
		new tempid = players[i]
		if(!loggedin[tempid]) {
			ChatColor(tempid, "^4[%s]^1 %L ^3/reg", PREFIX, LANG_SERVER, "HELP", LANG_SERVER, registered[tempid] ? "FOR_LOGIN":"FOR_REGISTER");
		}
	}
}

public client_putinserver(id) {
	if(!is_user_bot(id) && !is_user_hltv(id)) {
		get_user_name(id, username[id], charsmax(username[]));
		load(id);
	}
}

public client_disconnect(id) {
	loggedin[id] = false;
	registered[id] = false;
	username[id] = "";
	password[id] = "";
	writepass[id] = "";
	if(task_exists(id)) remove_task(id);
}

public reg_menu(id) {
	new temp[128], loggedinmsg[32], registeredmsg[32], logoffmsg[32], notreggedname[32], exitname[32];
	formatex(notreggedname, charsmax(notreggedname), "%L", LANG_SERVER, "NOTREGGED");
	formatex(loggedinmsg, charsmax(loggedinmsg), "%L", LANG_SERVER, loggedin[id] ? "LOGGED_IN":"REGISTERED");
	formatex(temp, charsmax(temp), "\r[\y%s\r] %L", PREFIX, LANG_SERVER, "REG_MENU_TITLE", AUTHOR, registered[id] ? loggedinmsg:notreggedname);
	new menu = menu_create(temp, "reg_menu_h" )

	formatex(temp, charsmax(temp), "%L", LANG_SERVER, "USERNAME", username[id])
	menu_additem(menu,temp, "0",0)
	formatex(temp, charsmax(temp), "%L", LANG_SERVER, "PASSWORD", writepass[id])
	menu_additem(menu,temp, "1",0)
	formatex(registeredmsg, charsmax(registeredmsg), "%L", LANG_SERVER, registered[id] ? "LOGIN":"REGISTER")
	formatex(logoffmsg, charsmax(logoffmsg), "%L", LANG_SERVER, "LOGOFF")
	formatex(temp, charsmax(temp), "%s^n", loggedin[id] ? logoffmsg:registeredmsg)
	menu_additem(menu,temp, "2",0)
	if(loggedin[id])
	{
		formatex(temp, charsmax(temp), "%L", LANG_SERVER, "CHGPASS")
		menu_additem(menu,temp, "3",0)
	}
	menu_setprop(menu, MPROP_EXIT, MEXIT_ALL);
	formatex(exitname, charsmax(exitname), "%L", LANG_SERVER, "EXIT")
	menu_setprop(menu, MPROP_EXITNAME, exitname);
	menu_display(id, menu, 0)
	return PLUGIN_HANDLED;
}

public reg_menu_h(id, menu, item) {
	if(item == MENU_EXIT) {
		menu_destroy(menu);
		return PLUGIN_HANDLED;
	}
	new command[6], name[64], access, callback;
	menu_item_getinfo(menu, item, access, command, sizeof command - 1, name, sizeof name - 1, callback);

	switch(item)
	{
		case 0: {
			reg_menu(id)
		}
		case 1: {
			if(!loggedin[id]) {
				client_cmd(id, "messagemode TYPE_PASSWORD")
			}
			else reg_menu(id)
		}
		case 2: {
			if(registered[id]) {
				if(!loggedin[id]) {
					if(strlen(password[id]) >= 6 && equal(writepass[id], password[id])) {
						ChatColor(id, "^4[%s]^1 %L ^3/reg", PREFIX, LANG_SERVER, "SUCCESS_LOGIN")
						loggedin[id] = true;
					}
					else {
						ChatColor(id, "^4[%s]^1 %L", PREFIX, LANG_SERVER, "WRONG_PASS")
						writepass[id] = "";
						reg_menu(id)
					}
				}
				else {
					loggedin[id] = false;
					ChatColor(id, "^4[%s]^1 %L ^3/reg", PREFIX, LANG_SERVER, "SUCCESS_LOGOFF")
					writepass[id] = "";
				}
			}
			else {
				if(strlen(writepass[id]) >= 6) {
					ChatColor(id, "^4[%s]^1 %L", PREFIX, LANG_SERVER, "SUCCESS_REGISTER")
					copy(password[id], charsmax(password[]), writepass[id]);
					registered[id] = true;
					save(id);
					reg_menu(id)
				}
				else reg_menu(id)
			}
		}
		case 3: {
			if(loggedin[id]) {
				client_cmd(id, "messagemode NEW_PASSWORD")
			}
			else reg_menu(id)
		}
	}
	
	menu_destroy(menu);
	return PLUGIN_HANDLED;
}

public Type_password(id) {
	new adat[32]
	read_args(adat, charsmax(adat))
	remove_quotes(adat)
	if(strlen(adat) < 6) {
		ChatColor(id, "^4[%s]^1 %L", PREFIX, LANG_SERVER, "PASS_CHANGE1")
	}
	else {
		copy(writepass[id], charsmax(writepass[]), adat)
	}
	reg_menu(id)
}

public New_password(id) {
	if(!loggedin[id]) return;
	
	new adat[32]
	read_args(adat, charsmax(adat))
	remove_quotes(adat)
	if(strlen(adat) < 6) {
		ChatColor(id, "^4[%s]^1 %L", PREFIX, LANG_SERVER, "PASS_CHANGE1")
	}
	else {
		copy(writepass[id], charsmax(writepass[]), adat)
		copy(password[id], charsmax(password[]), adat)
		ChatColor(id, "^4[%s]^1 %L", PREFIX, LANG_SERVER, "PASS_CHANGE2")
		#if defined SQL
		update(id);
		#else
		save(id);
		#endif
	}
	reg_menu(id)
}

public ClientUserInfoChanged(id, buffer) { 
	if (!is_user_connected(id))
		return FMRES_IGNORED
	static name[32], val[32]
	get_user_name(id, name, charsmax(name))
	engfunc(EngFunc_InfoKeyValue, buffer, "name", val, charsmax(val))
	if (equal(val, name))
		return FMRES_IGNORED
	engfunc(EngFunc_SetClientKeyValue, id, buffer, "name", name)
	client_cmd(id, "name ^"%s^"; setinfo name ^"%s^"", name, name)
	ChatColor(id, "^4[%s]^1 %L", PREFIX, LANG_SERVER, "NAMECHANGE_BLOCK")
	return FMRES_SUPERCEDE
}

public plugin_natives() {
	register_native("is_user_loggedin", "native_loggedin", 1);
	register_native("is_user_registered", "native_registered", 1);
}
public native_loggedin(index) {
	return loggedin[index];
}
public native_registered(index) {
	return registered[index];
}

stock ChatColor(const id, const szMessage[], any:...) {
	static pnum, players[32], szMsg[190], IdMsg; 
	vformat(szMsg, charsmax(szMsg), szMessage, 3);
	
	if(!IdMsg) IdMsg = get_user_msgid("SayText");
	
	if(id) {
		if(!is_user_connected(id)) return;
		players[0] = id;
		pnum = 1; 
	} 
	else get_players(players, pnum, "ch");
	
	for(new i; i < pnum; i++) {
		message_begin(MSG_ONE, IdMsg, .player = players[i]);
		write_byte(players[i]);
		write_string(szMsg);
		message_end();
	}
}

#if defined SQL
public plugin_cfg() {
	g_SqlTuple = SQL_MakeDbTuple(SQL_INFO[0],SQL_INFO[1],SQL_INFO[2],SQL_INFO[3])
	formatex(Query, charsmax(Query), "CREATE TABLE IF NOT EXISTS registration_system (`username` varchar(32) NOT NULL,`password` varchar(32) NOT NULL,`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY)")
	SQL_ThreadQuery(g_SqlTuple,"createTableThread", Query)
}

public createTableThread(FailState, Handle:Query, Error[], Errcode, Data[], DataSize, Float:Queuetime) {
	if(FailState == TQUERY_CONNECT_FAILED)
		set_fail_state("Nem tudtam csatlakozni az adatbazishoz.");
	else if(FailState == TQUERY_QUERY_FAILED)
		set_fail_state("Query Error");
	if(Errcode)
		log_amx("Hibat dobtam: %s",Error);
}

public load(id) {
	new Data[1]
	Data[0] = id

	formatex(Query, charsmax(Query), "SELECT * FROM `registration_system` WHERE username = ^"%s^";", username[id])
	SQL_ThreadQuery(g_SqlTuple, "QuerySelectData", Query, Data, 1)
}

public QuerySelectData(FailState, Handle:Query, Error[], Errcode, Data[], DataSize, Float:Queuetime) { 
	if(FailState == TQUERY_CONNECT_FAILED || FailState == TQUERY_QUERY_FAILED) {
		log_amx("%s", Error)
		return
	}
	else {
		new id = Data[0];

		if(SQL_NumRows(Query) > 0) {
			SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "password"), password[id], charsmax(password[]));
			registered[id] = true;
			set_task(10.0, "reg_menu", id);
		}
	}
}

public save(id) {
	formatex(text, charsmax(text), "INSERT INTO `registration_system` (`username`, `password`) VALUES (^"%s^", ^"%s^");", username[id], password[id])
	SQL_ThreadQuery(g_SqlTuple, "QuerySetData", text) 
}

public update(id) {
	formatex(text, charsmax(text), "UPDATE `registration_system` SET password = ^"%s^" WHERE username = ^"%s^";", password[id], username[id])
	SQL_ThreadQuery(g_SqlTuple, "QuerySetData", text)
}

public QuerySetData(FailState, Handle:Query, Error[], Errcode, Data[], DataSize, Float:Queuetime) {
	if(FailState == TQUERY_CONNECT_FAILED || FailState == TQUERY_QUERY_FAILED) {
		log_amx("%s", Error)
		return
	}
}

public plugin_end() {
	SQL_FreeHandle(g_SqlTuple)
}

#else

public load(id) {
	new szData[32];
 
	if(get_data(username[id], szData, charsmax(szData))) {
		new szPassword[32];
		parse(szData, szPassword, charsmax(szPassword));
		copy(password[id], charsmax(password[]), szPassword)
		registered[id] = true;
		set_task(10.0, "reg_menu", id);
	}
}

public save(id) {
	new szData[32];
	formatex(szData, charsmax(szData), "%s", password[id]);
	set_data(username[id], szData)
}

stock get_data(const key[], data[], len) {
	new vault = fopen(filename, "rt");
	new _data[512], _key[64];
	
	while( !feof(vault) ) {
		fgets(vault, _data, charsmax(_data));
		parse(_data, _key, charsmax(_key), data, len);
		
		if( equal(_key, key) ) {
			fclose(vault);
			return 1;
		}
	}
	
	fclose(vault);
	copy(data, len, "");
	
	return 0;
}

stock set_data(const key[], const data[]) {
	static const temp_vault_name[] = "set_data.txt";
	new file = fopen(temp_vault_name, "wt");
	
	new vault = fopen(filename, "rt");
	new _data[512], _key[64], _other[32];
	new bool:replaced = false;
	
	while( !feof(vault) ) {
		fgets(vault, _data, charsmax(_data));
		parse(_data, _key, charsmax(_key), _other, charsmax(_other));
		
		if( equal(_key, key) && !replaced ) {
			fprintf(file, "^"%s^" ^"%s^"^n", key, data);
			
			replaced = true;
		}
		else {
			fputs(file, _data);
		}
	}
	
	if( !replaced ) {
		fprintf(file, "^"%s^" ^"%s^"^n", key, data);
	}
	
	fclose(file);
	fclose(vault);
	
	delete_file(filename);
	
	while( !rename_file(temp_vault_name, filename, 1) ) { }
	
	//delete_file(temp_vault_name);
}
#endif