package com.kartoflane.ftl.layout; import java.util.Scanner; import java.util.regex.Pattern; /** * Parser for FTL .txt layout files. * * @author kartoFlane * */ public class FTLLayoutParser { private FTLLayoutFactory factory; public FTLLayoutParser() { this(null); } public FTLLayoutParser(FTLLayoutFactory factory) { if (factory == null) factory = new DefaultFTLLayoutFactory(); this.factory = factory; } /** * Attempts to parse the content and construct a viable FTL * Layout object out of it. * * @param source * the string representing file contents * @return the Layout that represents the .txt layout file * @throws FTLLayoutParseException * when an error occurs while parsing */ public ShipLayout build(String source) throws FTLLayoutParseException { Scanner sc = new Scanner(source); ShipLayout layout = new ShipLayout(); int line = -1; try { String lineContent = null; while (sc.hasNextLine()) { ++line; lineContent = sc.nextLine(); if (lineContent == null || lineContent.trim().equals("")) { if (sc.hasNextLine()) { // throw new FTLLayoutParseException("Double line break only allowed at the end of the file.", layout, line); } } else if (Pattern.matches("\\w*", lineContent)) { LOType objectType = null; try { objectType = LOType.valueOf(lineContent); switch (objectType) { case X_OFFSET: layout.addLayoutObject(factory.xOffset(line, sc.nextInt())); ++line; break; case Y_OFFSET: layout.addLayoutObject(factory.yOffset(line, sc.nextInt())); ++line; break; case HORIZONTAL: layout.addLayoutObject(factory.horizontal(line, sc.nextInt())); ++line; break; case VERTICAL: layout.addLayoutObject(factory.vertical(line, sc.nextInt())); ++line; break; case ELLIPSE: layout.addLayoutObject(factory.ellipse(line, sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt())); line += 4; break; case ROOM: layout.addLayoutObject(factory.room(line, sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt())); line += 5; break; case DOOR: layout.addLayoutObject(factory.door(line, sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt(), sc.nextInt() == 0)); line += 5; break; default: throw new RuntimeException("Implementation error. Should never happen."); } } catch (IllegalArgumentException e) { throw new FTLLayoutParseException("Unrecognised layout object: " + lineContent, layout, line); } } else { throw new FTLLayoutParseException("Unexpected characters: " + lineContent, layout, line); } } if (!lineContent.equals("")) { throw new FTLLayoutParseException("No empty line at the end of the file", layout, line); } } finally { sc.close(); } return layout; } }