package jrummikub.control;

import static jrummikub.model.StoneColor.*;
import static org.junit.Assert.*;

import java.awt.Color;
import java.util.Arrays;
import java.util.HashSet;

import jrummikub.model.GameSettings;
import jrummikub.model.PlayerSettings.Type;
import jrummikub.model.StoneColor;
import jrummikub.util.IListener1;
import jrummikub.view.ISettingsPanel;
import jrummikub.view.MockView;

import org.junit.Before;
import org.junit.Test;

/** */
public class SettingsControlTest {
	MockView view = new MockView();
	GameSettings initialSettings = new GameSettings();
	SettingsControl settingsControl = new SettingsControl(view, initialSettings);
	GameSettings gameSettings = null;

	/** */
	@Before
	public void setup() {
		settingsControl.getStartGameEvent().add(new IListener1<GameSettings>() {
			@Override
			public void handle(GameSettings value) {
				gameSettings = value;
			}
		});

		settingsControl.startSettings();
	}

	/** */
	@Test
	public void initialStateTest() {
		assertSame(ISettingsPanel.SettingsError.NO_ERROR,
				view.settingsPanel.error);
		for (Boolean enabled : view.settingsPanel.removePlayerButtonsEnabled) {
			assertFalse(enabled);
		}

		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(2, gameSettings.getPlayerList().size());
		assertEquals(2, view.settingsPanel.removePlayerButtonsEnabled.size());
	}

	/** */
	@Test
	public void addPlayerTest() {
		view.settingsPanel.addPlayerEvent.emit();
		for (Boolean enabled : view.settingsPanel.removePlayerButtonsEnabled) {
			assertTrue(enabled);
		}

		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(3, gameSettings.getPlayerList().size());
		assertEquals(3, view.settingsPanel.removePlayerButtonsEnabled.size());
	}

	/** */
	@Test
	public void add14PlayerTest() {
		for (int i = 0; i < 14; i++) {
			view.settingsPanel.addPlayerEvent.emit();
		}
		view.settingsPanel.changeStoneSetNumberEvent.emit(8);
		for (Boolean enabled : view.settingsPanel.removePlayerButtonsEnabled) {
			assertTrue(enabled);
		}
		assertFalse(view.settingsPanel.addPlayerButtonEnabled);

		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(16, gameSettings.getPlayerList().size());
		assertEquals(16, view.settingsPanel.removePlayerButtonsEnabled.size());
	}

	/** */
	@Test
	public void add14RemovePlayerTest() {
		for (int i = 0; i < 14; i++) {
			view.settingsPanel.addPlayerEvent.emit();
		}
		view.settingsPanel.removePlayerEvent.emit(0);
		view.settingsPanel.changeStoneSetNumberEvent.emit(8);
		for (Boolean enabled : view.settingsPanel.removePlayerButtonsEnabled) {
			assertTrue(enabled);
		}
		assertTrue(view.settingsPanel.addPlayerButtonEnabled);

		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(15, gameSettings.getPlayerList().size());
		assertEquals(15, view.settingsPanel.removePlayerButtonsEnabled.size());
	}

	/** */
	@Test
	public void removePlayerTest() {
		view.settingsPanel.addPlayerEvent.emit();
		view.settingsPanel.removePlayerEvent.emit(0);
		for (Boolean enabled : view.settingsPanel.removePlayerButtonsEnabled) {
			assertFalse(enabled);
		}

		view.settingsPanel.startGameEvent.emit();

		assertNotNull(gameSettings);
		assertEquals(2, gameSettings.getPlayerList().size());
		assertEquals(2, view.settingsPanel.removePlayerButtonsEnabled.size());
	}

	/** */
	@Test
	public void takenColorTest() {
		Color color1 = Color.RED;
		Color color2 = Color.BLUE;
		view.settingsPanel.changePlayerColorEvent.emit(0, color1);
		view.settingsPanel.changePlayerColorEvent.emit(1, color2);
		view.settingsPanel.changePlayerColorEvent.emit(1, color1);
		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(2, gameSettings.getPlayerList().size());
		assertSame(color2, gameSettings.getPlayerList().get(0).getColor());
		assertSame(color1, gameSettings.getPlayerList().get(1).getColor());
	}

	/** */
	@Test
	public void unusedColorTest() {
		Color color1 = Color.RED;
		Color color2 = Color.BLUE;
		Color color3 = Color.PINK;
		view.settingsPanel.changePlayerColorEvent.emit(0, color1);
		view.settingsPanel.changePlayerColorEvent.emit(1, color2);
		view.settingsPanel.changePlayerColorEvent.emit(1, color3);
		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(2, gameSettings.getPlayerList().size());
		assertSame(color1, gameSettings.getPlayerList().get(0).getColor());
		assertSame(color3, gameSettings.getPlayerList().get(1).getColor());
	}

	/** */
	@Test
	public void takenNameTest() {
		String name1 = "Julia";
		view.settingsPanel.changePlayerNameEvent.emit(0, name1);
		view.settingsPanel.changePlayerNameEvent.emit(1, name1);

		assertFalse(view.settingsPanel.startButtonEnabled);
		assertSame(ISettingsPanel.SettingsError.DUPLICATE_PLAYER_NAME_ERROR,
				view.settingsPanel.error);

		view.settingsPanel.startGameEvent.emit();
		assertNull(gameSettings);
	}

	/** */
	@Test
	public void fixTakenNameTest() {
		String name1 = "Julia";
		view.settingsPanel.changePlayerNameEvent.emit(0, name1);
		view.settingsPanel.changePlayerNameEvent.emit(1, name1);

		assertFalse(view.settingsPanel.startButtonEnabled);
		assertSame(ISettingsPanel.SettingsError.DUPLICATE_PLAYER_NAME_ERROR,
				view.settingsPanel.error);

		view.settingsPanel.startGameEvent.emit();
		assertNull(gameSettings);

		String name2 = "Karl";
		view.settingsPanel.changePlayerNameEvent.emit(1, name2);

		assertTrue(view.settingsPanel.startButtonEnabled);
		assertSame(ISettingsPanel.SettingsError.NO_ERROR,
				view.settingsPanel.error);

		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
	}

	/** */
	@Test
	public void emptyNameTest() {
		String name1 = "";
		view.settingsPanel.changePlayerNameEvent.emit(0, name1);

		assertFalse(view.settingsPanel.startButtonEnabled);
		assertSame(ISettingsPanel.SettingsError.NO_PLAYER_NAME_ERROR,
				view.settingsPanel.error);

		view.settingsPanel.startGameEvent.emit();
		assertNull(gameSettings);
	}

	/** */
	@Test
	public void initialMeldThresholdTest() {
		assertEquals(initialSettings.getInitialMeldThreshold(),
				view.settingsPanel.initialMeldThreshold);

		view.settingsPanel.changeInitialMeldThresholdEvent.emit(25);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(25, gameSettings.getInitialMeldThreshold());
	}

	/** */
	@Test
	public void initialMeldWarningTest() {
		assertEquals(initialSettings.getInitialMeldThreshold(),
				view.settingsPanel.initialMeldThreshold);
		view.settingsPanel.changeInitialMeldThresholdEvent.emit(900);
		assertTrue(view.settingsPanel.startButtonEnabled);
		assertSame(ISettingsPanel.SettingsError.TOO_HIGH_THRESHOLD_WARNING,
				view.settingsPanel.error);

		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
	}

	/** */
	@Test
	public void jokerNumberTest() {
		assertEquals(initialSettings.getJokerNumber(),
				view.settingsPanel.jokerNumber);

		view.settingsPanel.changeJokerNumberEvent.emit(25);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(25, gameSettings.getJokerNumber());
	}

	/** */
	@Test
	public void changeStoneSetNumberTest() {
		assertEquals(initialSettings.getStoneSetNumber(),
				view.settingsPanel.stoneSetNumber);

		view.settingsPanel.changeStoneSetNumberEvent.emit(3);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(3, gameSettings.getStoneSetNumber());
	}

	/** */
	@Test
	public void changeNumberOfStonesDealtTest() {
		assertEquals(initialSettings.getNumberOfStonesDealt(),
				view.settingsPanel.numberOfStonesDealt);

		view.settingsPanel.changeNumberOfStonesDealtEvent.emit(15);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(15, gameSettings.getNumberOfStonesDealt());
	}

	/** */
	@Test
	public void changeHighestValueTest() {
		assertEquals(initialSettings.getHighestValue(),
				view.settingsPanel.highestValue);

		view.settingsPanel.changeHighestValueEvent.emit(10);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(10, gameSettings.getHighestValue());
	}
	
	/** */
	@Test
	public void changeTurnTimeTest() {
		assertEquals(initialSettings.getTotalTime(),
				view.settingsPanel.totalTime);

		view.settingsPanel.changeTimeEvent.emit(50);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(50, gameSettings.getTotalTime());
	}
	
	/** */
	@Test
	public void changeNoLimitsTest() {
		assertEquals(initialSettings.isNoLimits(),
				view.settingsPanel.noLimits);

		view.settingsPanel.changeNoLimitsEvent.emit(true);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(true, gameSettings.isNoLimits());
	}
	
	/** */
	@Test
	public void changeSeeHandsTest() {
		assertEquals(initialSettings.getSeeHandSize(),
				view.settingsPanel.seeHandSize);

		view.settingsPanel.changeSeeHandSizeEvent.emit(true);
		view.settingsPanel.startGameEvent.emit();
		assertEquals(true, gameSettings.getSeeHandSize());
	}

	/** */
	@Test
	public void changeStoneColorsTest() {
		assertEquals(initialSettings.getStoneColors(),
				view.settingsPanel.stoneColors);

		view.settingsPanel.changeStoneColorsEvent.emit(new HashSet<StoneColor>(
				Arrays.asList(BLUE, RED, BLACK)));
		view.settingsPanel.startGameEvent.emit();
		assertEquals(new HashSet<StoneColor>(Arrays.asList(BLUE, RED, BLACK)),
				gameSettings.getStoneColors());
	}
	
	/** */
	@Test
	public void notEnoghColorsErrorTest() {
		assertEquals(initialSettings.getStoneColors(),
				view.settingsPanel.stoneColors);

		view.settingsPanel.changeStoneColorsEvent.emit(new HashSet<StoneColor>(
				Arrays.asList(BLUE, RED)));
		assertFalse(view.settingsPanel.startButtonEnabled);
		assertSame(ISettingsPanel.SettingsError.NOT_ENOUGH_COLORS_ERROR,
				view.settingsPanel.error);		

		view.settingsPanel.startGameEvent.emit();
		assertNull(gameSettings);
	}
	
	/** */
	@Test
	public void childrenVariantTest(){
		assertEquals(initialSettings.getInitialMeldThreshold(), view.settingsPanel.initialMeldThreshold);
		assertEquals(initialSettings.getStoneSetNumber(), view.settingsPanel.stoneSetNumber);
		assertEquals(initialSettings.getHighestValue(), view.settingsPanel.highestValue);
		assertEquals(initialSettings.getNumberOfStonesDealt(), view.settingsPanel.numberOfStonesDealt);
		assertEquals(initialSettings.getJokerNumber(), view.settingsPanel.jokerNumber);
		assertEquals(initialSettings.getTotalTime(), view.settingsPanel.totalTime);
		assertEquals(initialSettings.isNoLimits(), view.settingsPanel.noLimits);
		
		view.settingsPanel.setVariantChildrenEvent.emit();
		
		assertEquals(20, view.settingsPanel.initialMeldThreshold);
		assertEquals(initialSettings.getStoneSetNumber(), view.settingsPanel.stoneSetNumber);
		assertEquals(10, view.settingsPanel.highestValue);
		assertEquals(initialSettings.getNumberOfStonesDealt(), view.settingsPanel.numberOfStonesDealt);
		assertEquals(6, view.settingsPanel.jokerNumber);
		assertEquals(120, view.settingsPanel.totalTime);
		assertEquals(initialSettings.isNoLimits(), view.settingsPanel.noLimits);
		
		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		
		assertEquals(20, gameSettings.getInitialMeldThreshold());
		assertEquals(initialSettings.getStoneSetNumber(), gameSettings.getStoneSetNumber());
		assertEquals(10, view.settingsPanel.highestValue);
		assertEquals(initialSettings.getNumberOfStonesDealt(),gameSettings.getNumberOfStonesDealt());
		assertEquals(6,gameSettings.getJokerNumber());
		assertEquals(120, gameSettings.getTotalTime());
		assertEquals(initialSettings.isNoLimits(), gameSettings.isNoLimits());
	}
	
	/** */
	@Test
	public void defaultVariantTest(){
		assertEquals(initialSettings.getInitialMeldThreshold(), view.settingsPanel.initialMeldThreshold);
		assertEquals(initialSettings.getStoneSetNumber(), view.settingsPanel.stoneSetNumber);
		assertEquals(initialSettings.getHighestValue(), view.settingsPanel.highestValue);
		assertEquals(initialSettings.getNumberOfStonesDealt(), view.settingsPanel.numberOfStonesDealt);
		assertEquals(initialSettings.getJokerNumber(), view.settingsPanel.jokerNumber);
		assertEquals(initialSettings.getTotalTime(), view.settingsPanel.totalTime);
		assertEquals(initialSettings.isNoLimits(), view.settingsPanel.noLimits);
		
		view.settingsPanel.setVariantChildrenEvent.emit();
		
		assertEquals(20, view.settingsPanel.initialMeldThreshold);
		assertEquals(initialSettings.getStoneSetNumber(), view.settingsPanel.stoneSetNumber);
		assertEquals(10, view.settingsPanel.highestValue);
		assertEquals(initialSettings.getNumberOfStonesDealt(), view.settingsPanel.numberOfStonesDealt);
		assertEquals(6, view.settingsPanel.jokerNumber);
		assertEquals(120, view.settingsPanel.totalTime);
		assertEquals(initialSettings.isNoLimits(), view.settingsPanel.noLimits);
		
		view.settingsPanel.setVariantDefaultEvent.emit();
		
		assertEquals(initialSettings.getInitialMeldThreshold(), view.settingsPanel.initialMeldThreshold);
		assertEquals(initialSettings.getStoneSetNumber(), view.settingsPanel.stoneSetNumber);
		assertEquals(initialSettings.getHighestValue(), view.settingsPanel.highestValue);
		assertEquals(initialSettings.getNumberOfStonesDealt(), view.settingsPanel.numberOfStonesDealt);
		assertEquals(initialSettings.getJokerNumber(), view.settingsPanel.jokerNumber);
		assertEquals(initialSettings.getTotalTime(), view.settingsPanel.totalTime);
		assertEquals(initialSettings.isNoLimits(), view.settingsPanel.noLimits);
		
		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		
		assertEquals(initialSettings.getInitialMeldThreshold(), gameSettings.getInitialMeldThreshold());
		assertEquals(initialSettings.getStoneSetNumber(), gameSettings.getStoneSetNumber());
		assertEquals(initialSettings.getHighestValue(), gameSettings.getHighestValue());
		assertEquals(initialSettings.getNumberOfStonesDealt(), gameSettings.getNumberOfStonesDealt());
		assertEquals(initialSettings.getJokerNumber(), gameSettings.getJokerNumber());
		assertEquals(initialSettings.getTotalTime(),gameSettings.getTotalTime());
		assertEquals(initialSettings.isNoLimits(), gameSettings.isNoLimits());
	}

	/** */
	@Test
	public void typeChangeTest() {
		view.settingsPanel.changePlayerTypeEvent.emit(0, Type.COMPUTER);
		view.settingsPanel.changePlayerTypeEvent.emit(1, Type.COMPUTER);
		view.settingsPanel.changePlayerTypeEvent.emit(1, Type.HUMAN);
		view.settingsPanel.startGameEvent.emit();
		assertNotNull(gameSettings);
		assertEquals(2, gameSettings.getPlayerList().size());
		assertSame(Type.COMPUTER, gameSettings.getPlayerList().get(0).getType());
		assertSame(Type.HUMAN, gameSettings.getPlayerList().get(1).getType());
	}

}
