package leigh.mud.engine;

import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import leigh.mecha.util.StringAccumulator;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;

/**
 * This class implements the book-keeping for a room in the mud.
 *
 * @author Alex Leigh
 */
public class Room {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(Room.class);
    private final int id;
    private String title;
    private String desc;
    private final HashMap<Direction, Exit> exits = new HashMap<>();
    private final HashMap<String, Extra> extras = new HashMap<>();
    private final HashSet<MudSession> players = new HashSet<>();

    public Room(int id, String title, String desc) {
        this.id = id;
        this.title = title;
        this.desc = desc;
    }

    public int getId() {
        return id;
    }

    public String getTitle() {
        return title;
    }

    public HashMap<String, Extra> getExtras() {
        return extras;
    }

    public String getDesc() {
        return desc;
    }

    /**
     * Add a player to this room. The arrival of the player will be announced to any other players in the room.
     */
    public synchronized void addPlayer(MudSession p) throws IOException {
        for (MudSession player : players) {
            String nm = p.getPlayer().getShortDesc();
            player.write(nm + " arrives.");
        }
        players.add(p);
    }

    public void setTitle(String title) {
        this.title = title;
    }

    /**
     * Remove a player from this room. The departure of the player will be announced to any other players in the room.
     */
    public synchronized void removePlayer(MudSession p) throws IOException {
        players.remove(p);
        for (MudSession player : players) {
            String nm = p.getPlayer().getShortDesc();
            player.write(nm + " departs.");
        }
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    /**
     * Process the look command for this room. This will provide the general room description, or, the description
     * of an extra.
     */
    public String look(String[] cmd, MudSession session) {
        logger.info("Look called: {}", cmd);
        if (cmd.length == 1) {
            StringBuffer buf = new StringBuffer();
            buf.append(title);
            buf.append("\r\n   ");
            buf.append(desc);

            if (players.size() > 1) {
                for (MudSession p : players) {
                    if (p.equals(session)) continue;
                    buf.append("\r\n" + p.getPlayer().getShortDesc() + " is here.");
                }
            }

            return buf.toString();
        } else {
            String noun = null;
            if (cmd.length == 2) {
                noun = cmd[1];
            } else if (cmd.length >= 3) {
                // TODO: Don't take it on faith that the command says LOOK AT
                noun = cmd[2];
            }

            noun = noun.trim().toLowerCase();

            // Maybe we are looking at a direction...
            Direction dir = Direction.getDirection(noun);
            if (dir != null) {
                return lookDirection(dir);
            }

            // Maybe we are looking at a thing...
            Extra extra = extras.get(noun.trim().toLowerCase());

            if (extra == null) {
                return "I don't see that here.";
            } else {
                return extra.getDesc();
            }
        }
    }

    /**
     * Process the player looking in the given direction. This typically returns the description for the exit
     * in that direction, if one exists.
     */
    public String lookDirection(Direction dir) {
        Exit ex = exits.get(dir);
        if (ex == null) {
            return "I don't see exit that way.";
        }

        String str = ex.getDesc();
        if (str == null) {
            return "You see an exit, but it doesn't look like anything to you";
        }

        return ex.getDesc();
    }

    public HashMap<Direction, Exit> getExits() {
        return exits;
    }

    @Override
    public String toString() {
        return "Room{" +
                "id=" + id +
                ", title='" + title + '\'' +
                ", desc='" + desc + '\'' +
                ", exits=" + exits +
                '}';
    }

    public String say(String[] cmd, MudSession session) throws IOException {
        StringAccumulator msg = new StringAccumulator(" ");
        for (int i = 1; i < cmd.length; i++) {
            msg.append(cmd[i]);
        }

        String nm = session.getPlayer().getShortDesc();

        for (MudSession player : players) {
            if (!player.equals(session)) {
                player.write(nm + " says '" + msg.toString() + "'.");
            } else {
                player.write("You say, '" + msg.toString() + "'.");
            }
        }
        return null;
    }
}
