package server;
import java.awt.Point;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import common.CommonUtils;
import common.PubRoom;
import common.RoomType;
import common.gameevent.MapGameEvent;
public class Area implements Externalizable {
private static final long serialVersionUID = 3762253019898722361L;
private static Map<String,Area> areas = new HashMap<String,Area>();
private static Map<String,Point> defaultRooms = new HashMap<String,Point>();
private static Set<AreaListener> listeners = new HashSet<AreaListener>();
static {
defaultRooms.put("main", new Point(3, 1));
}
private String name;
private Map<Point,Room> rooms = new HashMap<Point,Room>();
private Map<Point,PubRoom> pubrooms = new HashMap<Point,PubRoom>();
private int minX, minY, maxX, maxY;
public Area() {
}
public Area(String name) {
this.name = name.intern();
areas.put(name, this);
new Room(this, 0, 0, null, "Default Room", RoomType.ROAD);
}
public String getName() {
return name;
}
public static Area findByName(String name) {
return areas.get(name);
}
public static Collection<Area> getAreas() {
return new ArrayList<Area>(areas.values());
}
public MapGameEvent makeMapGameEvent() {
return new MapGameEvent(name, minX, minY, maxX, maxY, pubrooms);
}
public Room getDefaultRoom() {
Point loc = defaultRooms.get(name);
if (loc != null) {
Room room = findByPoint(loc);
if (room != null) {
return room;
}
}
loc = new Point(0, 0);
Room room = findByPoint(loc);
if (room != null) {
return room;
}
return getRandomRoom();
}
public Room findByPoint(Point point) {
return rooms.get(point);
}
private Room getRandomRoom() {
int size = rooms.size();
if (size == 0) {
throw new FatalError("No rooms in area " + name);
}
int roomNumber = new Random().nextInt(size);
Iterator<Room> iter = rooms.values().iterator();
for (int i = 0; i < roomNumber; i++) {
iter.next();
}
return iter.next();
}
public void addRoom(Room room) {
assert room.getArea() == this;
int x = room.getX();
int y = room.getY();
minX = Math.min(x, minX);
minY = Math.min(y, minY);
maxX = Math.max(x, maxX);
maxY = Math.max(y, maxY);
Point location = new Point(x, y);
PubRoom pubroom = room.makePubRoom();
rooms.put(location, room);
pubrooms.put(location, pubroom);
notifyRoomChanged(pubroom);
}
void removeRoom(Room room) {
assert room.getArea() == this;
Point location = new Point(room.getX(), room.getY());
rooms.remove(location);
pubrooms.remove(location);
notifyRoomDeleted(location);
}
public void updateRoom(Room room) {
assert room.getArea() == this;
PubRoom pubroom = room.makePubRoom();
Point loc = new Point(room.getX(), room.getY());
rooms.put(loc, room);
pubrooms.put(loc, pubroom);
notifyRoomChanged(pubroom);
}
public int getSize() {
return rooms.size();
}
public void destroy() {
if (name.equals("main")) {
throw new FatalError("Attempt to destroy 'main' area.");
}
if (rooms.size() != 1) {
throw new FatalError("Attempt to destroy area with more than one room.");
}
Room other = Area.findByName("main").getDefaultRoom();
Room room = getRandomRoom(); for (Player player : room.getPlayers()) {
player.moveTo(other);
}
removeRoom(room);
areas.remove(name);
}
public static void doSave(ObjectOutputStream oos) throws IOException {
oos.writeInt(1); oos.writeObject(areas);
}
public static void doLoad(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.readInt(); areas = CommonUtils.uncheckedCast(ois.readObject());
}
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt(1); out.writeObject(name);
out.writeObject(rooms);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
in.readInt(); name = (String) in.readObject();
rooms = CommonUtils.uncheckedCast(in.readObject());
for (Map.Entry<Point,Room> entry : rooms.entrySet()) {
Point point = entry.getKey();
Room room = entry.getValue();
pubrooms.put(point, room.makePubRoom());
minX = Math.min(minX, room.getX());
minY = Math.min(minY, room.getY());
maxX = Math.max(maxX, room.getX());
maxY = Math.max(maxY, room.getY());
}
}
public void addAreaListener(AreaListener l) {
listeners.add(l);
}
public void removeAreaListener(AreaListener l) {
listeners.remove(l);
}
private void notifyRoomChanged(PubRoom pr) {
for (AreaListener l : listeners) {
l.roomChanged(pr);
}
}
private void notifyRoomDeleted(Point p) {
for (AreaListener l : listeners) {
l.roomDeleted(p);
}
}
}