package jrummikub.control.network;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import jrummikub.control.AbstractSettingsControl;
import jrummikub.model.GameSettings;
import jrummikub.model.PlayerSettings;
import jrummikub.model.PlayerSettings.Type;
import jrummikub.util.Event;
import jrummikub.util.Event1;
import jrummikub.util.IListener;
import jrummikub.view.ISettingsPanel;
import jrummikub.view.ISettingsPanel.SettingsMode;
import jrummikub.view.IView;

/**
 * Settings for network games, entered by host
 */
public class NetworkSettingsControl extends AbstractSettingsControl {
	private String nickname;
	private Event1<GameSettings> offerGameEvent = new Event1<GameSettings>();
	private Event backEvent = new Event();

	/**
	 * Creates a new network settings control
	 * 
	 * @param nickname
	 *          to be set as player name
	 * @param view
	 *          for events and handlers
	 * @param settings
	 *          for playerNumber, color...
	 */
	public NetworkSettingsControl(String nickname, IView view,
			GameSettings settings) {
		super(view, settings);
		this.nickname = nickname;

		view.getSettingsPanel().setSettingsMode(SettingsMode.NETWORK_SETUP);

		addFirstPlayer();
		addPlayer();

		addListeners();

		connections.add(view.getSettingsPanel().getOfferGameEvent()
				.add(new IListener() {
					@Override
					public void handle() {
						offerGame();
					}
				}));

		connections.add(view.getSettingsPanel().getBackEvent().add(new IListener() {
			@Override
			public void handle() {
				abort();
				backEvent.emit();
			}
		}));
	}

	/**
	 * The game offer event is emitted when a player wants to offer a new network
	 * game
	 * 
	 * @return the event
	 */
	public Event1<GameSettings> getOfferGameEvent() {
		return offerGameEvent;
	}

	/**
	 * The get back event is emitted when the player wants to go back to the
	 * previous settings panel
	 * 
	 * @return the event
	 */
	public Event getBackEvent() {
		return backEvent;
	}

	private void offerGame() {
		if (!checkSettings()) {
			return;
		}
		abort();
		offerGameEvent.emit(settings);
	}

	@Override
	protected void update() {
		view.getSettingsPanel().enableAddPlayerButton(
				settings.getPlayerList().size() < ISettingsPanel.PLAYER_COLORS.length);

		checkSettings();

		List<List<Type>> choices = new ArrayList<List<Type>>();
		List<Boolean> enableRemoveButtons = new ArrayList<Boolean>();
		List<Boolean> playerNamesEditable = new ArrayList<Boolean>();

		for (int i = 0; i < settings.getPlayerList().size(); i++) {
			if (i == 0) {
				choices.add(Collections.singletonList(Type.HUMAN));
				enableRemoveButtons.add(false);
			} else {
				choices.add(Arrays.asList(Type.VACANT, Type.COMPUTER));
				enableRemoveButtons.add(settings.getPlayerList().size() > 2);
			}

			playerNamesEditable
					.add(settings.getPlayerList().get(i).getType() == Type.COMPUTER);
		}
		view.getSettingsPanel().enableRemovePlayerButtons(enableRemoveButtons);
		view.getSettingsPanel().setPlayerNamesEditable(playerNamesEditable);
		view.getSettingsPanel().setPlayerTypeChoices(choices);

		view.getSettingsPanel().setGameSettings(settings);
	}

	@Override
	protected void setPlayerType(int i, Type type) {
		Type oldType = settings.getPlayerList().get(i).getType();

		settings.getPlayerList().get(i).setType(type);

		if (type == Type.VACANT) {
			settings.getPlayerList().get(i).setName("Offen");
		} else if (oldType != Type.COMPUTER && type == Type.COMPUTER) {
			// Find unused player name
			int num = 0;

			nameLoop: while (true) {
				num++;
				String playerName = "Computer " + num;

				for (PlayerSettings player : settings.getPlayerList()) {
					if (player.getType() == Type.COMPUTER
							&& playerName.equals(player.getName())) {
						continue nameLoop;
					}
				}
				break;
			}

			settings.getPlayerList().get(i).setName("Computer " + num);
		}

		update();
	}

	private void addFirstPlayer() {
		PlayerSettings playerSettings = new PlayerSettings(nickname,
				findUnusedColor());
		settings.getPlayerList().add(playerSettings);
	}

	@Override
	protected void addPlayer() {
		if (settings.getPlayerList().size() >= ISettingsPanel.PLAYER_COLORS.length) {
			return;
		}

		PlayerSettings playerSettings = new PlayerSettings("Offen",
				findUnusedColor());
		playerSettings.setType(Type.VACANT);
		settings.getPlayerList().add(playerSettings);

		update();
	}
}
