/*
* Copyright 2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.nebhale.springone2013.model;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.fasterxml.jackson.annotation.JsonIgnore;
public final class Game {
private final Integer id;
private final Map<Integer, Door> doors;
private final Object monitor = new Object();
private volatile GameStatus status;
public Game(Integer id, Set<Door> doors) {
this.id = id;
this.doors = new HashMap<>();
for (Door door : doors) {
this.doors.put(door.getId(), door);
}
this.status = GameStatus.AWAITING_INITIAL_SELECTION;
}
public void select(Integer doorId) throws IllegalTransitionException, DoorDoesNotExistException {
synchronized (this.monitor) {
if (this.status != GameStatus.AWAITING_INITIAL_SELECTION) {
throw new IllegalTransitionException(this.id, this.status, GameStatus.AWAITING_FINAL_SELECTION);
}
Door door = getDoor(doorId);
door.setStatus(DoorStatus.SELECTED);
openHintDoor();
this.status = GameStatus.AWAITING_FINAL_SELECTION;
}
}
public void open(Integer doorId) throws IllegalTransitionException, DoorDoesNotExistException {
synchronized (this.monitor) {
if (this.status != GameStatus.AWAITING_FINAL_SELECTION) {
throw new IllegalTransitionException(this.id, this.status, GameStatus.WON);
}
Door door = getDoor(doorId);
if (DoorStatus.OPEN == door.getStatus()) {
throw new IllegalTransitionException(this.id, doorId, door.getStatus(), DoorStatus.OPEN);
}
door.setStatus(DoorStatus.OPEN);
if (DoorContent.BICYCLE == door.getContent()) {
this.status = GameStatus.WON;
} else {
this.status = GameStatus.LOST;
}
}
}
@JsonIgnore
public Integer getId() {
return this.id;
}
public Door getDoor(Integer doorId) throws DoorDoesNotExistException {
if (this.doors.containsKey(doorId)) {
return this.doors.get(doorId);
}
throw new DoorDoesNotExistException(this.id, doorId);
}
@JsonIgnore
public Set<Door> getDoors() {
return new HashSet<>(this.doors.values());
}
public GameStatus getStatus() {
synchronized (this.monitor) {
return this.status;
}
}
private void openHintDoor() {
for (Door door : getDoors()) {
if ((DoorStatus.CLOSED == door.getStatus()) && (DoorContent.SMALL_FURRY_ANIMAL == door.peekContent())) {
door.setStatus(DoorStatus.OPEN);
break;
}
}
}
}