/*
Copyright (C) 2005 David Green <green@couchpotato.net>
All Rights Reserved.

This file is part of Aelfengard.

Aelfengard is proprietary software. You may not redistribute it without
prior written permission from the copyright holder.
*/

package server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import common.ScriptType;

public enum IdType {
    NPC(EnumSet.of(ScriptType.NPC_HEARTBEAT, ScriptType.NPC_COMBAT, ScriptType.NPC_DEATHBEAT)),
    PLAYER(EnumSet.noneOf(ScriptType.class)),
    ITEM(EnumSet.noneOf(ScriptType.class));
    
    private static Map<Integer,Player> players = new HashMap<Integer,Player>();
    private static Map<Integer,NPC> npcs = new HashMap<Integer,NPC>();
    private static Map<Integer, Item> items = new HashMap<Integer, Item>();
    
    private final Set<ScriptType> scriptTypes;
    private int lastId = ordinal() == 0 ? 0 : ordinal() - 3;
    
    private static IdType[] VALUES = IdType.values();

    private IdType(EnumSet<ScriptType> scriptTypes) {
        this.scriptTypes = Collections.unmodifiableSet(scriptTypes);
    }
    
    public void setMinLastId(int lastId) {
        int modulo = lastId % 3;
        if (modulo < 0) {
            modulo = 3 + modulo;
        }
        if (modulo != ordinal()) {
            throw new IllegalArgumentException(
                    lastId + " % 3 != " + ordinal() + " for " + 
                    getClass().getName() + "." + name());
        }
        this.lastId = Math.max(lastId, this.lastId);
    }
    
    public int getLastId() {
        return lastId;
    }
    
    public int getNextId() {
        lastId += 3;
        return lastId;
    }
    
    public Set<ScriptType> getScriptTypes() {
        return scriptTypes;
    }
    
    public static IdType getIdType(int id) {
        return VALUES[id % 3];
    }
    
    public static void addPlayer(Player player) {
        players.put(player.getId(), player);
    }
    
    public static void addNPC(NPC npc) {
        npcs.put(npc.getId(), npc);
    }
    
    public static void addItem(Item item) {
        items.put(item.getId(), item);
    }
    
    public static void removeNPC(NPC npc) {
        npcs.remove(npc.getId());
    }
    
    public static void removeItem(Item item) {
        items.remove(item.getId());
    }
    
    public static void removePlayer(Player player) {
        players.remove(player.getId());
    }

    public static Player getPlayerById(int id) {
        return players.get(id);
    }
    
    public static NPC getNPCById(int id) {
        return npcs.get(id);
    }
    
    public static Item getItemById(int id) {
        return items.get(id);
    }
    
    public static RoomEntity getRoomEntityById(int id) {
        switch (getIdType(id)) {
            case PLAYER: return getPlayerById(id);
            case NPC: return getNPCById(id);
            case ITEM: return getItemById(id);
            default: throw new IllegalArgumentException();
        }
    }
    
    public static Living getLivingById(int id) {
        switch (getIdType(id)) {
            case PLAYER: return getPlayerById(id);
            case NPC: return getNPCById(id);
            default: throw new IllegalArgumentException();
        }
    }
    
    public static Collection<Player> getAllPlayers() {
        return players.values();
    }
    
    public static void doSave(ObjectOutputStream oos) throws IOException {
        oos.writeInt(1); // protocol version
        oos.writeInt(PLAYER.getLastId());
        oos.writeInt(NPC.getLastId());
        oos.writeInt(ITEM.getLastId());
    }
    
    public static void doLoad(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.readInt(); // protocol version
        PLAYER.setMinLastId(ois.readInt());
        NPC.setMinLastId(ois.readInt());
        ITEM.setMinLastId(ois.readInt());
    }

}