/**
 * Stores in-game names for all players.
 *
 * NB: the regular gamesetup has a particular handling of this setting.
 * The names are loaded from the map, but the GUI also show playernames.
 * Force these at the start of the match.
 */
GameSettings.prototype.Attributes.PlayerName = class PlayerName extends GameSetting
{
	init()
	{
		// NB: watchers aren't auto-triggered when modifying array elements.
		this.values = [];
		this.settings.playerCount.watch(() => this.maybeUpdate(), ["nbPlayers"]);
		this.settings.map.watch(() => this.onMapChange(), ["map"]);
	}

	toInitAttributes(attribs)
	{
		if (!attribs.settings.PlayerData)
			attribs.settings.PlayerData = [];
		while (attribs.settings.PlayerData.length < this.values.length)
			attribs.settings.PlayerData.push({});

		for (const i in this.values)
			if (this.values[i])
				attribs.settings.PlayerData[i].Name = this.values[i];
	}

	fromInitAttributes(attribs, fromPersistentSettings)
	{
		if (fromPersistentSettings || !this.getLegacySetting(attribs, "PlayerData"))
			return;
		const pData = this.getLegacySetting(attribs, "PlayerData");
		for (let i = 0; i < this.values.length; ++i)
			if (pData[i] && pData[i].Name !== undefined)
			{
				this.values[i] = pData[i].Name;
				this.trigger("values");
			}
	}

	_resize(nb)
	{
		while (this.values.length > nb)
			this.values.pop();
		while (this.values.length < nb)
			this.values.push(undefined);
	}

	onMapChange()
	{
		// Reset.
		this._resize(0);
		this.maybeUpdate();
	}

	maybeUpdate()
	{
		this._resize(this.settings.playerCount.nbPlayers);
		this.values.forEach((_, i) => this._set(i));
		this.trigger("values");
	}

	/**
	 * Pick AI names.
	 */
	pickRandomItems()
	{
		const AIPlayerNamesList = [];
		let picked = false;
		for (const i in this.values)
		{
			if (!!this.values[i] &&
				this.values[i] !== g_Settings.PlayerDefaults[+i + 1].Name)
				continue;

			const ai = this.settings.playerAI.values[i];
			if (!ai)
				continue;

			const civ = this.settings.playerCiv.values[i];
			if (!civ || civ == "random")
				continue;

			picked = true;

			const names = this.settings.civData[civ].AINames;
			const remainingNames = names.filter(name => !AIPlayerNamesList.includes(name));
			const chosenName = pickRandom(remainingNames.length ? remainingNames : names);

			// Avoid translating AI names if the game is networked, so all players see and refer to
			// English names instead of names in the language of the host.
			const translatedCountLabel = this.settings.isNetworked ? this.CountLabel : translate(this.CountLabel);
			const translatedChosenName = this.settings.isNetworked ? chosenName : translate(chosenName);

			const duplicateNameCount = AIPlayerNamesList.reduce((count, name) => {
				if (name == chosenName)
					count++;
				return count;
			}, 0);

			AIPlayerNamesList.push(chosenName);

			this.values[i] = !duplicateNameCount ? translatedChosenName :
				sprintf(translatedCountLabel, {
					"playerName": translatedChosenName,
					"nameCount": duplicateNameCount + 1
				});
		}
		if (picked)
		{
			this.trigger("values");
		}
		return picked;
	}

	onFinalizeAttributes(attribs, playerAssignments)
	{
		// Replace client player names with the real players.
		for (const guid in playerAssignments)
			if (playerAssignments[guid].player !== -1)
				attribs.settings.PlayerData[playerAssignments[guid].player -1].Name = playerAssignments[guid].name;
	}

	_getMapData(i)
	{
		const data = this.settings.map.data;
		if (!data || !data.settings || !data.settings.PlayerData)
			return undefined;
		if (data.settings.PlayerData.length <= i)
			return undefined;
		return data.settings.PlayerData[i].Name;
	}

	_set(playerIndex)
	{
		this.values[playerIndex] = this._getMapData(playerIndex) || g_Settings && g_Settings.PlayerDefaults[playerIndex + 1].Name || "";
	}
};

/** Translation: This is a template (sprintf format specifier) for the name of
 * an AI-controlled player and a unique number for each of the players with
 * that same name. Example: Perseus (2)
 */
GameSettings.prototype.Attributes.PlayerName.prototype.CountLabel = markForTranslation("%(playerName)s (%(nameCount)i)");
