package polly.rx.parsing; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.skuzzle.polly.sdk.User; import de.skuzzle.polly.sdk.time.Milliseconds; import de.skuzzle.polly.tools.iterators.ArrayIterator; import polly.rx.MSG; import polly.rx.entities.BattleReport; import polly.rx.entities.BattleDrop; import polly.rx.entities.BattleReportShip; import polly.rx.entities.BattleTactic; import polly.rx.entities.RxRessource; public class BattleReportParser { private final static Pattern NUBER_PATTERN = Pattern.compile("\\d+"); //$NON-NLS-1$ final static Pattern WHERE_PATTERN = Pattern.compile( "Gefecht bei (.*) (\\d+),(\\d+)"); //$NON-NLS-1$ final static int QUADRANT_GROUP = 1; final static int X_GROUP = 2; final static int Y_GROUP = 3; private final static Pattern HEADER_PATTERN = Pattern.compile( "Die (Angreifer|Verteidiger) waren siegreich\\s+Gefechtstaktik\\s+([^\n]+)\n" + //$NON-NLS-1$ "\\s*Bonus Angreifer\\s+(-?\\d+)%\\s+Bonus Verteidiger\\s+(-?\\d+)%\n\\s*" + //$NON-NLS-1$ "Kampfwert Angreifer/XP-Mod\\s+(\\d+(?:\\.\\d+)?)/(\\d+(\\.\\d+)?)\\s+" + //$NON-NLS-1$ "Kampfwert Verteidiger/XP-Mod\\s+(\\d+(?:\\.\\d+)?)/(\\d+(\\.\\d+)?)", //$NON-NLS-1$ Pattern.DOTALL); private final static int TACTIC_GROUP = 2; private final static int ATTACKER_BONUS_GROUP = 3; private final static int DEFENDER_BONUS_GROUP = 4; private final static int ATTACKER_KW_GROUP = 5; private final static int ATTACKER_XPMOD_GROUP = 6; private final static int DEFENDER_KW_GROUP = 8; private final static int DEFENDER_XPMOD_GROUP = 9; private final static Pattern FLEET_NAME_PATTERN = Pattern.compile("(Angreifer|Verteidiger) Flotte: ([^\\)]+)\\(([^\\)]+)\\)"); //$NON-NLS-1$ private final static int FLEET_NAME_GROUP = 2; private final static int VENAD_NAME_GROUP = 3; private final static Pattern SHIP_PATTERN = Pattern.compile("(.*?)\\s{2,}(.*?)\\s+" + //$NON-NLS-1$ "Angriffswert\\s+(\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s+Captain\\s+(-?\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s+XPs\\s+(\\d+)\\s+" + //$NON-NLS-1$ "Schild\\s+(\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s+Crew\\s+(-?\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s+XPs\\s+(\\d+)\\s+" + //$NON-NLS-1$ "Panzerung\\s+(\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s+Systeme\\s+(-?\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s+" + //$NON-NLS-1$ "Struktur\\s+(\\d+) / (\\d+)(\\(-(\\d+)\\))?\\s*(?:ID:(\\d+)\\s+)?"); //$NON-NLS-1$ private final static int SHIP_NAME_GROUP = 1; private final static int CAPI_NAME_GROUP = 2; private final static int AW_GROUP = 4; private final static int AW_DMG_GROUP = 6; private final static int HP_GROUP = 8; private final static int HP_DMG_GROUP = 10; private final static int XP_CAPI_GROUP = 11; private final static int SHIELDS_GROUP = 13; private final static int SHIELDS_DMG_GROUP = 15; private final static int MIN_CREW_GROUP = 16; private final static int MAX_CREW_GROUP = 17; private final static int CREW_DMG_GROUP = 19; private final static int XP_CREW_GROUP = 20; private final static int CURRENT_PZ_GROUP = 21; private final static int PZ_GROUP = 22; private final static int PZ_DMG_GROUP = 24; private final static int SYSTEMS_GROUP = 26; private final static int SYSTEMS_DMG_GROUP = 28; private final static int STRUCTURE_GROUP = 30; private final static int STRUCTURE_DMG_GROUP = 32; private final static int ID_GROUP = 33; private final static DateFormat getDateFormat() { return new SimpleDateFormat("HH:mm dd-MM-yyyy"); //$NON-NLS-1$ } private BattleReportParser() {} public final static BattleReport parseReport(String paste, User submitter) throws ParseException { try { return parseReportHelper(paste, submitter); } catch (Exception e) { throw new ParseException(MSG.reportParserInvalid); } } private static BattleReport parseReportHelper(String paste, User submitter) throws ParseException { String[] lines = paste.split("[\n\r]+"); //$NON-NLS-1$ ArrayIterator<String> it = ArrayIterator.get(lines); // KB date Date date = null; try { date = getDateFormat().parse(it.next()); // round to minutes long d = date.getTime() / Milliseconds.fromMinutes(1) * Milliseconds.fromMinutes(1); date = new Date(d); } catch (Exception e) { throw new ParseException(MSG.bind(MSG.reportParserInvalidDate, it.previous())); } // KB drop it.next(); Matcher numbers = NUBER_PATTERN.matcher(it.next()); List<BattleDrop> drops = new ArrayList<BattleDrop>(14); int i = 0; while (numbers.find()) { int amount = Integer.parseInt(numbers.group()); RxRessource r = RxRessource.values()[i++]; drops.add(new BattleDrop(r, amount)); } // kb artifact boolean artifact = it.peekNext().startsWith("1 Artefakt"); //$NON-NLS-1$ // KB location while (!it.peekNext().startsWith("Gefecht bei ")) { //$NON-NLS-1$ it.next(); } String tmp = it.next(); Matcher where = WHERE_PATTERN.matcher(tmp); if (!where.find()) { throw new ParseException(MSG.bind(MSG.reportParserInvalidLocation, tmp)); } String quadrant = RegexUtils.substr(tmp, where, QUADRANT_GROUP); int x = RegexUtils.subint(tmp, where, X_GROUP); int y = RegexUtils.subint(tmp, where, Y_GROUP); // KB tactic StringBuilder kbheader = new StringBuilder(); while (it.hasNext() && !it.peekNext().startsWith("Angreifer")) { //$NON-NLS-1$ kbheader.append(it.next()); kbheader.append('\n'); } tmp = kbheader.toString(); Matcher header = HEADER_PATTERN.matcher(tmp); if (!header.find()) { throw new ParseException(MSG.reportParserInvalidHeader); } BattleTactic tactic = BattleTactic.parseTactic( RegexUtils.substr(tmp, header, TACTIC_GROUP)); double attackerBonus = parseBonus(RegexUtils.substr(tmp, header, ATTACKER_BONUS_GROUP)); double defenderBonus = parseBonus(RegexUtils.substr(tmp, header, DEFENDER_BONUS_GROUP)); double attackerKw = Double.parseDouble(RegexUtils.substr(tmp, header, ATTACKER_KW_GROUP)); double attackerXpMod = Double.parseDouble( RegexUtils.substr(tmp, header, ATTACKER_XPMOD_GROUP)); double defenderkw = Double.parseDouble(RegexUtils.substr(tmp, header, DEFENDER_KW_GROUP)); double defenderXpMod = Double.parseDouble( RegexUtils.substr(tmp, header, DEFENDER_XPMOD_GROUP)); // KB attacker fleet tmp = it.next(); Matcher fleet = FLEET_NAME_PATTERN.matcher(tmp); if (!fleet.find()) { throw new ParseException(MSG.bind(MSG.reportParserExpectedAttackerFleet, tmp)); } String attackerVenad = RegexUtils.substr(tmp, fleet, VENAD_NAME_GROUP); String attackerClan = ""; //$NON-NLS-1$ String attackerFleetName = RegexUtils.substr(tmp, fleet, FLEET_NAME_GROUP); i = attackerVenad.indexOf("["); //$NON-NLS-1$ if (i != -1) { attackerClan = attackerVenad.substring(i + 1, attackerVenad.length() - 1); attackerVenad = attackerVenad.substring(0, attackerVenad.length() - attackerClan.length() - 2); } StringBuilder b = new StringBuilder(); while (it.hasNext() && !it.peekNext().startsWith("Verteidiger Flotte")) { //$NON-NLS-1$ b.append(it.next()); b.append('\n'); } // KB defender fleet tmp = it.next(); fleet = FLEET_NAME_PATTERN.matcher(tmp); if (!fleet.find()) { throw new ParseException(MSG.bind(MSG.reportParserExpectedDefenderFleet, tmp)); } String defenderVenad = RegexUtils.substr(tmp, fleet, VENAD_NAME_GROUP); String defenderFleetName = RegexUtils.substr(tmp, fleet, FLEET_NAME_GROUP); String defenderClan = ""; //$NON-NLS-1$ i = defenderVenad.indexOf("["); //$NON-NLS-1$ if (i != -1) { defenderClan = defenderVenad.substring(i + 1, defenderVenad.length() - 1); defenderVenad = defenderVenad.substring(0, defenderVenad.length() - defenderClan.length() - 2); } List<BattleReportShip> attackerShips = parseShips(b.toString()); if (attackerShips.isEmpty()) { throw new ParseException(MSG.reportParserNoAttackerShips); } b = new StringBuilder(); while (it.hasNext()) { b.append(it.next()); b.append('\n'); } List<BattleReportShip> defenderShips = parseShips(b.toString()); if (defenderShips.isEmpty()) { throw new ParseException(MSG.reportParserNoDefenderShips); } return new BattleReport(submitter.getId(), quadrant, x, y, drops, artifact, date, tactic, attackerBonus, defenderBonus, attackerKw, attackerXpMod, defenderkw, defenderXpMod, attackerFleetName, attackerVenad, defenderFleetName, defenderVenad, attackerClan, defenderClan, attackerShips, defenderShips); } public static double parseBonus(String bonus) { int b = Integer.parseInt(bonus); return 1.0 + ((double)b / 100.0); } private static List<BattleReportShip> parseShips(String paste) { Matcher ships = SHIP_PATTERN.matcher(paste); List<BattleReportShip> result = new LinkedList<BattleReportShip>(); while (ships.find()) { String shipName = RegexUtils.substr(paste, ships, SHIP_NAME_GROUP); String capiName = RegexUtils.substr(paste, ships, CAPI_NAME_GROUP); int aw = RegexUtils.subint(paste, ships, AW_GROUP); int awDmg = RegexUtils.subint(paste, ships, AW_DMG_GROUP); int hp = RegexUtils.subint(paste, ships, HP_GROUP); int hpDmg = RegexUtils.subint(paste, ships, HP_DMG_GROUP); int shields = RegexUtils.subint(paste, ships, SHIELDS_GROUP); int shieldsDmg = RegexUtils.subint(paste, ships, SHIELDS_DMG_GROUP); int minCrew = RegexUtils.subint(paste, ships, MIN_CREW_GROUP); int maxCrew = RegexUtils.subint(paste, ships, MAX_CREW_GROUP); int crewDmg = RegexUtils.subint(paste, ships, CREW_DMG_GROUP); int xpCapi = RegexUtils.subint(paste, ships, XP_CAPI_GROUP); int xpCrew = RegexUtils.subint(paste, ships, XP_CREW_GROUP); int pz = RegexUtils.subint(paste, ships, PZ_GROUP); int currentPz = RegexUtils.subint(paste, ships, CURRENT_PZ_GROUP); int pzDmg = RegexUtils.subint(paste, ships, PZ_DMG_GROUP); int systems = RegexUtils.subint(paste, ships, SYSTEMS_GROUP); int systemsDmg = RegexUtils.subint(paste, ships, SYSTEMS_DMG_GROUP); int structure = RegexUtils.subint(paste, ships, STRUCTURE_GROUP); int structureDmg = RegexUtils.subint(paste, ships, STRUCTURE_DMG_GROUP); int rxId = RegexUtils.subint(paste, ships, ID_GROUP); BattleReportShip ship = new BattleReportShip(rxId, shipName, capiName, aw, shields, pz, structure, minCrew, maxCrew, systems, xpCapi, xpCrew, shieldsDmg, currentPz, pzDmg, structureDmg, systemsDmg, hp, hpDmg, awDmg, crewDmg); result.add(ship); } return result; } }