<commit_before>require('es6-shim');

var TournamentGenerators = {
	roundrobin: require('./generator-round-robin.js').RoundRobin,
	elimination: require('./generator-elimination.js').Elimination
};

var tournaments = {};

function usersToNames(users) {
	return users.map(function (user) { return user.name; });
}

function createTournamentGenerator(generator, args, output) {
	var Generator = TournamentGenerators[toId(generator)];
	if (!Generator) {
		output.sendReply(generator + " is not a valid type.");
		output.sendReply("Valid types: " + Object.keys(TournamentGenerators).join(", "));
		return;
	}
	args.unshift(null);
	return new (Generator.bind.apply(Generator, args));
}
function createTournament(room, format, generator, args, output) {
	if (room.type !== 'chat') {
		output.sendReply("Tournaments can only be created in chat rooms.");
		return;
	}
	if (tournaments[room.id]) {
		output.sendReply("A tournament is already running in the room.");
		return;
	}
	if (Tools.getFormat(format).effectType !== 'Format') {
		output.sendReply(format + " is not a valid format.");
		output.sendReply("Valid formats: " + Object.keys(Tools.data.Formats).filter(function (f) { return Tools.data.Formats[f].effectType === 'Format'; }).join(", "));
		return;
	}
	if (!TournamentGenerators[toId(generator)]) {
		output.sendReply(generator + " is not a valid type.");
		output.sendReply("Valid types: " + Object.keys(TournamentGenerators).join(", "));
		return;
	}
	return tournaments[room.id] = new Tournament(room, format, createTournamentGenerator(generator, args, output));
}
function deleteTournament(name, output) {
	var id = toId(name);
	var tournament = tournaments[id];
	if (!tournament)
		output.sendReply(name + " doesn't exist.");
	tournament.forceEnd(output);
	delete tournaments[id];
}
function getTournament(name, output) {
	var id = toId(name);
	if (tournaments[id])
		return tournaments[id];
}

var Tournament = (function () {
	function Tournament(room, format, generator) {
		this.room = room;
		this.format = toId(format);
		this.generator = generator;

		this.isBracketInvalidated = true;
		this.bracketCache = null;

		this.isTournamentStarted = false;
		this.availableMatches = null;
		this.inProgressMatches = null;

		this.isAvailableMatchesInvalidated = true;
		this.availableMatchesCache = null;

		this.pendingChallenges = null;

		room.send('|tournament|create|' + format + '|' + generator.name);
		this.update();
	}

	Tournament.prototype.setGenerator = function (generator, output) {
		if (this.isTournamentStarted) {
			output.sendReply('|tournament|error|BracketFrozen');
			return;
		}

		var isErrored = false;
		this.generator.getUsers().forEach(function (user) {
			var error = generator.addUser(user);
			if (typeof error === 'string') {
				output.sendReply('|tournament|error|' + error);
				isErrored = true;
			}
		});

		if (isErrored)
			return;

		this.generator = generator;
		this.isBracketInvalidated = true;
		this.update();
	};

	Tournament.prototype.forceEnd = function () {
		this.room.send('|tournament|forceend');
	};

	Tournament.prototype.update = function (targetUser) {
		if (targetUser && (this.isBracketInvalidated || (this.isTournamentStarted && this.isAvailableMatchesInvalidated)))
			targetUser = null;

		this.room.send('|tournament|update|' + JSON.stringify({
			isStarted: this.isTournamentStarted,
			format: this.format,
			generator: this.generator.name,
			bracketData: this.getBracketData(),

			// Defaults of the below packets (which gets overwritten client side)
			isJoined: false,
			challenges: [],
			challengeBys: [],
			challenging: null,
			challenged: null
		}), targetUser);

		this.generator.getUsers().forEach(function (user) {
			if (!targetUser || user === targetUser)
				user.sendTo(this.room, '|tournament|update|{"isJoined":true}');
		}, this);

		if (this.isTournamentStarted) {
			var availableMatches = this.getAvailableMatches();
			availableMatches.challenges.forEach(function (opponents, user) {
				if (opponents.length > 0 && (!targetUser || user === targetUser))
					user.sendTo(this.room, '|tournament|update|' + JSON.stringify({challenges: usersToNames(opponents)}));
			}, this);
			availableMatches.challengeBys.forEach(function (opponents, user) {
				if (opponents.length > 0 && (!targetUser || user === targetUser))
					user.sendTo(this.room, '|tournament|update|' + JSON.stringify({challengeBys: usersToNames(opponents)}));
			}, this);

			this.pendingChallenges.forEach(function (challenge, user) {
				if (!challenge || (targetUser && challenge.to !== targetUser && challenge.from !== targetUser))
					return;

				if (challenge.to)
					user.sendTo(this.room, '|tournament|update|' + JSON.stringify({challenging: challenge.to.name}));
				else if (challenge.from)
					user.sendTo(this.room, '|tournament|update|' + JSON.stringify({challenged: challenge.from.name}));
			}, this);
		}

		this.room.send('|tournament|updateEnd', targetUser);
	};

	Tournament.prototype.addUser = function (user, output) {
		var error = this.generator.addUser(user);
		if (typeof error === 'string') {
			output.sendReply('|tournament|error|' + error);
			return;
		}

		this.room.send('|tournament|join|' + user.name);
		this.isBracketInvalidated = true;
		this.update();
	};
	Tournament.prototype.removeUser = function (user, output) {
		var error = this.generator.removeUser(user);
		if (typeof error === 'string') {
			output.sendReply('|tournament|error|' + error);
			return;
		}

		this.room.send('|tournament|leave|' + user.name);<commit_msg>Revert "Change to a more JSON-type update format" for now<commit_after>require('es6-shim');

var TournamentGenerators = {
	roundrobin: require('./generator-round-robin.js').RoundRobin,
	elimination: require('./generator-elimination.js').Elimination
};

var tournaments = {};

function usersToNames(users) {
	return users.map(function (user) { return user.name; });
}

function createTournamentGenerator(generator, args, output) {
	var Generator = TournamentGenerators[toId(generator)];
	if (!Generator) {
		output.sendReply(generator + " is not a valid type.");
		output.sendReply("Valid types: " + Object.keys(TournamentGenerators).join(", "));
		return;
	}
	args.unshift(null);
	return new (Generator.bind.apply(Generator, args));
}
function createTournament(room, format, generator, args, output) {
	if (room.type !== 'chat') {
		output.sendReply("Tournaments can only be created in chat rooms.");
		return;
	}
	if (tournaments[room.id]) {
		output.sendReply("A tournament is already running in the room.");
		return;
	}
	if (Tools.getFormat(format).effectType !== 'Format') {
		output.sendReply(format + " is not a valid format.");
		output.sendReply("Valid formats: " + Object.keys(Tools.data.Formats).filter(function (f) { return Tools.data.Formats[f].effectType === 'Format'; }).join(", "));
		return;
	}
	if (!TournamentGenerators[toId(generator)]) {
		output.sendReply(generator + " is not a valid type.");
		output.sendReply("Valid types: " + Object.keys(TournamentGenerators).join(", "));
		return;
	}
	return tournaments[room.id] = new Tournament(room, format, createTournamentGenerator(generator, args, output));
}
function deleteTournament(name, output) {
	var id = toId(name);
	var tournament = tournaments[id];
	if (!tournament)
		output.sendReply(name + " doesn't exist.");
	tournament.forceEnd(output);
	delete tournaments[id];
}
function getTournament(name, output) {
	var id = toId(name);
	if (tournaments[id])
		return tournaments[id];
}

var Tournament = (function () {
	function Tournament(room, format, generator) {
		this.room = room;
		this.format = toId(format);
		this.generator = generator;

		this.isBracketInvalidated = true;
		this.bracketCache = null;

		this.isTournamentStarted = false;
		this.availableMatches = null;
		this.inProgressMatches = null;

		this.isAvailableMatchesInvalidated = true;
		this.availableMatchesCache = null;

		this.pendingChallenges = null;

		room.send('|tournament|create|' + format + '|' + generator.name);
		this.update();
	}

	Tournament.prototype.setGenerator = function (generator, output) {
		if (this.isTournamentStarted) {
			output.sendReply('|tournament|error|BracketFrozen');
			return;
		}

		var isErrored = false;
		this.generator.getUsers().forEach(function (user) {
			var error = generator.addUser(user);
			if (typeof error === 'string') {
				output.sendReply('|tournament|error|' + error);
				isErrored = true;
			}
		});

		if (isErrored)
			return;

		this.generator = generator;
		this.isBracketInvalidated = true;
		this.update();
	};

	Tournament.prototype.forceEnd = function () {
		this.room.send('|tournament|forceend');
	};

	Tournament.prototype.update = function (targetUser) {
		if (targetUser && (this.isBracketInvalidated || (this.isTournamentStarted && this.isAvailableMatchesInvalidated)))
			targetUser = null;

		this.room.send('|tournament|update', targetUser);
		this.room.send('|tournament|info|' + JSON.stringify({
			isStarted: this.isTournamentStarted,
			format: this.format,
			generator: this.generator.name
		}), targetUser);

		this.generator.getUsers().forEach(function (user) {
			if (!targetUser || user === targetUser)
				user.sendTo(this.room, '|tournament|isjoined');
		}, this);

		this.room.send('|tournament|bracketdata|' + JSON.stringify(this.getBracketData()), targetUser);

		if (this.isTournamentStarted) {
			var availableMatches = this.getAvailableMatches();
			availableMatches.challenges.forEach(function (opponents, user) {
				if (opponents.length > 0 && (!targetUser || user === targetUser))
					user.sendTo(this.room, '|tournament|challenges|' + usersToNames(opponents).join(','));
			}, this);
			availableMatches.challengeBys.forEach(function (opponents, user) {
				if (opponents.length > 0 && (!targetUser || user === targetUser))
					user.sendTo(this.room, '|tournament|challengeBys|' + usersToNames(opponents).join(','));
			}, this);

			this.pendingChallenges.forEach(function (challenge, user) {
				if (!challenge || (targetUser && challenge.to !== targetUser && challenge.from !== targetUser))
					return;

				if (challenge.to)
					user.sendTo(this.room, '|tournament|challenging|' + challenge.to.name);
				else if (challenge.from)
					user.sendTo(this.room, '|tournament|challenged|' + challenge.from.name);
			}, this);
		}
	};

	Tournament.prototype.addUser = function (user, output) {
		var error = this.generator.addUser(user);
		if (typeof error === 'string') {
			output.sendReply('|tournament|error|' + error);
			return;
		}

		this.room.send('|tournament|join|' + user.name);
		this.isBracketInvalidated = true;
		this.update();
	};
	Tournament.prototype.removeUser = function (user, output) {
		var error = this.generator.removeUser(user);
		if (typeof error === 'string') {
			output.sendReply('|tournament|error|' + error);
			return;
		}

		this.room.send('|tournament|leave|' + user.name);
{'fraction_non_alphanumeric': 0.1561897770028448, 'fraction_numerical': 0.0005506102597045058, 'mean_word_length': 4.750923482849604, 'pattern_counts': {'":': 1, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5075214', 'n_tokens_mistral': 3965, 'n_tokens_neox': 3459, 'n_words': 677}