package leigh.mud.engine.io;

import leigh.mecha.lang.DangerousRunnable;
import leigh.mecha.log.MechaLogger;
import leigh.mecha.log.MechaLoggerFactory;
import leigh.mud.engine.Direction;
import leigh.mud.engine.Exit;
import leigh.mud.engine.Extra;
import leigh.mud.engine.Room;

import java.io.*;
import java.util.ArrayList;

/**
 * Processor to load CircleMUD format room files.
 * <p>
 * Note that this class is not intended to be production quality, and is simply to be used for testing purposes.
 *
 * @author Alex Leigh
 */
public class CircleDataImporter implements DangerousRunnable {
    private static final MechaLogger logger = MechaLoggerFactory.getLogger(CircleDataImporter.class);
    private final File f;
    private final ArrayList<Room> rooms = new ArrayList<>();

    public CircleDataImporter(File f) {
        this.f = f;
    }

    public ArrayList<Room> getRooms() {
        return rooms;
    }

    @Override
    public void runDangerously() throws Exception {
        logger.info("Parsing Circle world file. [file: {}]", f);

        try (BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(f)))) {
            Room room;
            while ((room = readRoom(in)) != null) {
                rooms.add(room);
            }
        }
    }

    public String readDesc(BufferedReader in) throws IOException {
        StringBuffer buf = new StringBuffer();
        String line;
        while ((line = in.readLine()) != null) {
            if (line.equals("~")) break;
            line = line.trim();
            line = line.replace("  ", " ");
            logger.debug("line: [{}]", line);
            if (buf.length() > 0) buf.append(' ');
            buf.append(line);
        }
        return buf.toString().trim();
    }

    public void readExtra(BufferedReader in, String first, Room room) throws IOException {
        String nouns = in.readLine();
        String desc = readDesc(in);

        nouns = nouns.replace("~", "");
        String n[] = nouns.split(" ");

        Extra ex = new Extra(desc);

        for (String noun : n) {
            room.getExtras().put(noun, ex);
        }

        logger.debug("Extra found. [nouns: {}] [desc: {}]", nouns, desc);
    }

    public void readDirection(BufferedReader in, String first, Room room) throws IOException {
        String desc = readDesc(in);
        String keyword = in.readLine();
        String door = in.readLine();
        String dArr[] = door.split(" ");

        logger.debug("Door argument: {}", door);

        Exit e = new Exit(Integer.parseInt(dArr[2]), desc);

        Direction d;
        switch (first.trim()) {
            case "D0":
                d = Direction.NORTH;
                break;
            case "D1":
                d = Direction.EAST;
                break;
            case "D2":
                d = Direction.SOUTH;
                break;
            case "D3":
                d = Direction.WEST;
                break;
            case "D4":
                d = Direction.UP;
                break;
            case "D5":
                d = Direction.DOWN;
                break;
            default:
                logger.warn("Unknown direction found in world file: {}", first);
                throw new IllegalStateException();
        }

        room.getExits().put(d, e);

        logger.debug("Read exit: [direction: {}] [desc: {}] [door: {}]", d, desc, door);
    }

    public Room readRoom(BufferedReader in) throws IOException {
        // Not meant to be production quality - just needs to work enough to load rooms for testing the engine
        String id = in.readLine();
        if (id == null) return null;
        String title = in.readLine();
        if (title == null) return null;
        title = title.replace("~", "");
        String desc = readDesc(in);
        if (desc == null) return null;
        String status = in.readLine();
        if (status == null) return null;

        Room room = new Room(Integer.parseInt(id.substring(1)), title, desc);

        // At this point, we have sets of either D or E items. Ironically, D is exit, and E is description. S ends.
        String line;
        while ((line = in.readLine()) != null) {
            if (line.equals("S")) {
                return room;
            }
            if (line.startsWith("D")) {
                readDirection(in, line, room);
            }
            if (line.startsWith("E")) {
                readExtra(in, line, room);
            }

        }

        return null;
    }

    @Override
    public void run() {
        try {
            runDangerously();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
