diff --git a/build.gradle b/build.gradle index 07b34e07e..df3cecd4b 100644 --- a/build.gradle +++ b/build.gradle @@ -28,6 +28,7 @@ plugins { id "com.github.breadmoirai.github-release" version "2.5.2" id "com.install4j.gradle" version "9.0.6" id "org.barfuin.gradle.taskinfo" version "2.1.0" + id "io.freefair.lombok" version "8.10" } apply plugin: de.jansauer.poeditor.POEditorPlugin diff --git a/src/main/java/core/db/DBUpdater.java b/src/main/java/core/db/DBUpdater.java index a08be3e3d..8762b9aba 100644 --- a/src/main/java/core/db/DBUpdater.java +++ b/src/main/java/core/db/DBUpdater.java @@ -95,6 +95,10 @@ private void updateDBv900(int dbVersion) throws SQLException { var playerTable = dbManager.getTable(SpielerTable.TABLENAME); playerTable.tryAddColumn("SubForm", "FLOAT DEFAULT 0"); + var arenaTable = dbManager.getTable(StadionTable.TABLENAME); + arenaTable.tryAddColumn("REBUILT_DATE", "TIMESTAMP"); + arenaTable.tryAddColumn("EXPANSION_DATE", "TIMESTAMP"); + updateDBVersion(dbVersion, 900); } diff --git a/src/main/java/core/db/StadionTable.java b/src/main/java/core/db/StadionTable.java index 3fd3b7353..9776ce1c4 100644 --- a/src/main/java/core/db/StadionTable.java +++ b/src/main/java/core/db/StadionTable.java @@ -1,7 +1,10 @@ package core.db; +import core.training.TrainingPerWeek; +import core.util.HODateTime; import tool.arenasizer.Stadium; import java.sql.Types; +import java.util.Optional; final class StadionTable extends AbstractTable { static final String TABLENAME = "STADION"; @@ -13,19 +16,21 @@ final class StadionTable extends AbstractTable { @Override protected void initColumns() { columns = new ColumnDescriptor[]{ - ColumnDescriptor.Builder.newInstance().setColumnName("HRF_ID").setGetter((p) -> ((Stadium) p).getHrfId()).setSetter((p, v) -> ((Stadium) p).setHrfId((int) v)).setType(Types.INTEGER).isNullable(false).isPrimaryKey(true).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("StadionName").setGetter((p) -> ((Stadium) p).getStadienname()).setSetter((p, v) -> ((Stadium) p).setStadienname((String) v)).setType(Types.VARCHAR).setLength(127).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AnzSteh").setGetter((p) -> ((Stadium) p).getStehplaetze()).setSetter((p, v) -> ((Stadium) p).setStehplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AnzSitz").setGetter((p) -> ((Stadium) p).getSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AnzDach").setGetter((p) -> ((Stadium) p).getUeberdachteSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setUeberdachteSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AnzLogen").setGetter((p) -> ((Stadium) p).getLogen()).setSetter((p, v) -> ((Stadium) p).setLogen((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AusbauSteh").setGetter((p) -> ((Stadium) p).getAusbauStehplaetze()).setSetter((p, v) -> ((Stadium) p).setAusbauStehplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AusbauSitz").setGetter((p) -> ((Stadium) p).getAusbauSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setAusbauSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AusbauDach").setGetter((p) -> ((Stadium) p).getAusbauUeberdachteSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setAusbauUeberdachteSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AusbauLogen").setGetter((p) -> ((Stadium) p).getAusbauLogen()).setSetter((p, v) -> ((Stadium) p).setAusbauLogen((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("Ausbau").setGetter((p) -> ((Stadium) p).isAusbau()).setSetter((p, v) -> ((Stadium) p).setAusbau(0 != (int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("AusbauKosten").setGetter((p) -> ((Stadium) p).getAusbauKosten()).setSetter((p, v) -> ((Stadium) p).setAusbauKosten((int) v)).setType(Types.INTEGER).isNullable(false).build(), - ColumnDescriptor.Builder.newInstance().setColumnName("ArenaID").setGetter((p) -> ((Stadium) p).getArenaId()).setSetter((p, v) -> ((Stadium) p).setArenaId((int) v)).setType(Types.INTEGER).isNullable(false).build() + ColumnDescriptor.Builder.newInstance().setColumnName("HRF_ID").setGetter(p -> ((Stadium) p).getHrfId()).setSetter((p, v) -> ((Stadium) p).setHrfId((int) v)).setType(Types.INTEGER).isNullable(false).isPrimaryKey(true).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("StadionName").setGetter(p -> ((Stadium) p).getStadienname()).setSetter((p, v) -> ((Stadium) p).setStadienname((String) v)).setType(Types.VARCHAR).setLength(127).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AnzSteh").setGetter(p -> ((Stadium) p).getStehplaetze()).setSetter((p, v) -> ((Stadium) p).setStehplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AnzSitz").setGetter(p -> ((Stadium) p).getSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AnzDach").setGetter(p -> ((Stadium) p).getUeberdachteSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setUeberdachteSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AnzLogen").setGetter(p -> ((Stadium) p).getLogen()).setSetter((p, v) -> ((Stadium) p).setLogen((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AusbauSteh").setGetter(p -> ((Stadium) p).getAusbauStehplaetze()).setSetter((p, v) -> ((Stadium) p).setAusbauStehplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AusbauSitz").setGetter(p -> ((Stadium) p).getAusbauSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setAusbauSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AusbauDach").setGetter(p -> ((Stadium) p).getAusbauUeberdachteSitzplaetze()).setSetter((p, v) -> ((Stadium) p).setAusbauUeberdachteSitzplaetze((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AusbauLogen").setGetter(p -> ((Stadium) p).getAusbauLogen()).setSetter((p, v) -> ((Stadium) p).setAusbauLogen((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("Ausbau").setGetter(p -> ((Stadium) p).isAusbau()).setSetter((p, v) -> ((Stadium) p).setAusbau(0 != (int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("AusbauKosten").setGetter(p -> ((Stadium) p).getAusbauKosten()).setSetter((p, v) -> ((Stadium) p).setAusbauKosten((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("ArenaID").setGetter(p -> ((Stadium) p).getArenaId()).setSetter((p, v) -> ((Stadium) p).setArenaId((int) v)).setType(Types.INTEGER).isNullable(false).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("REBUILT_DATE").setGetter(p -> HODateTime.toDbTimestamp(((Stadium) p).getRebuiltDate())).setSetter((p, v) -> ((Stadium) p).setRebuiltDate((HODateTime) v)).setType(Types.TIMESTAMP).isNullable(true).build(), + ColumnDescriptor.Builder.newInstance().setColumnName("EXPANSION_DATE").setGetter(p -> ((Stadium) p).getExpansionDate().toDbTimestamp()).setSetter((p, v) -> ((Stadium) p).setExpansionDate((HODateTime) v)).setType(Types.TIMESTAMP).isNullable(true).build() }; } diff --git a/src/main/java/core/file/hrf/HRFStringBuilder.java b/src/main/java/core/file/hrf/HRFStringBuilder.java index f01c19754..89e27428f 100644 --- a/src/main/java/core/file/hrf/HRFStringBuilder.java +++ b/src/main/java/core/file/hrf/HRFStringBuilder.java @@ -14,11 +14,19 @@ import core.model.player.IMatchRoleID; import core.util.HOLogger; import core.util.StringUtils; +import hattrickdata.Arena; +import hattrickdata.Capacity; +import hattrickdata.ExpandedCapacity; import module.lineup.substitution.model.Substitution; import module.youth.YouthPlayer; import org.apache.commons.lang3.math.NumberUtils; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; +import java.util.Optional; public class HRFStringBuilder { private StringBuilder basicsStringBuilder; @@ -60,10 +68,11 @@ private void appendKeyValue(StringBuilder s, String key, Integer value){ private void appendKeyValue(StringBuilder s, String key, Double value){ s.append(key).append("=").append(value!=null?value:"").append("\n"); } + private void appendKeyValue(StringBuilder s, String key, boolean value){ + s.append(key).append("=").append(value?"1":"0").append("\n"); + } - /** - * Create the arena data. - */ + // TODO: fix the overload solution with 'Arena' public void createArena(Map arenaDataMap) { arenaStringBuilder = new StringBuilder("[arena]\n"); appendKeyValue(arenaStringBuilder, "arenaname", arenaDataMap.get("ArenaName")); @@ -79,8 +88,39 @@ public void createArena(Map arenaDataMap) { appendKeyValue(arenaStringBuilder, "expandingVIP", arenaDataMap.get("ExVIP")); appendKeyValue(arenaStringBuilder, "expandingSseatTotal", arenaDataMap.get("ExTotal")); appendKeyValue(arenaStringBuilder, "isExpanding", arenaDataMap.get("isExpanding")); - // Achtung bei keiner Erweiterung = 0! - appendKeyValue(arenaStringBuilder, "ExpansionDate", arenaDataMap.get("ExpansionDate")); + appendKeyValue(arenaStringBuilder, "RebuiltDate", Optional.ofNullable(arenaDataMap.get("RebuiltDate")).orElse("")); + appendKeyValue(arenaStringBuilder, "ExpansionDate", Optional.ofNullable(arenaDataMap.get("ExpansionDate")).orElse("")); + } + + /** + * Create the arena data. + */ + public void createArena(Arena arena) { + arenaStringBuilder = new StringBuilder("[arena]\n"); + appendKeyValue(arenaStringBuilder, "arenaname", arena.getName()); + appendKeyValue(arenaStringBuilder, "arenaid", arena.getId()); + appendKeyValue(arenaStringBuilder, "antalStaplats", arena.getCurrentCapacity().getTerraces()); + appendKeyValue(arenaStringBuilder, "antalSitt", arena.getCurrentCapacity().getBasic()); + appendKeyValue(arenaStringBuilder, "antalTak", arena.getCurrentCapacity().getRoof()); + appendKeyValue(arenaStringBuilder, "antalVIP", arena.getCurrentCapacity().getVip()); + appendKeyValue(arenaStringBuilder, "seatTotal", arena.getCurrentCapacity().getTotal()); + appendKeyValue(arenaStringBuilder, "expandingStaplats", arena.getExpandedCapacity().map(Capacity::getTerraces).orElse(0)); + appendKeyValue(arenaStringBuilder, "expandingSitt", arena.getExpandedCapacity().map(Capacity::getBasic).orElse(0)); + appendKeyValue(arenaStringBuilder, "expandingTak", arena.getExpandedCapacity().map(Capacity::getRoof).orElse(0)); + appendKeyValue(arenaStringBuilder, "expandingVIP", arena.getExpandedCapacity().map(Capacity::getVip).orElse(0)); + appendKeyValue(arenaStringBuilder, "expandingSseatTotal", arena.getExpandedCapacity().map(Capacity::getTotal).orElse(0)); + appendKeyValue(arenaStringBuilder, "isExpanding", arena.getExpandedCapacity().isPresent()); + appendKeyValue(arenaStringBuilder, "RebuiltDate", arena.getCurrentCapacity().getRebuiltDate().map(HRFStringBuilder::localDateTimeToHrfString).orElse("")); + appendKeyValue(arenaStringBuilder, "ExpansionDate", arena.getExpandedCapacity().map(ExpandedCapacity::getExpansionDate).map(HRFStringBuilder::localDateTimeToHrfString).orElse("")); + } + + // TODO: duplicates from HODateTime + private static final ZoneId DEFAULT_TIMEZONE = ZoneId.of("Europe/Stockholm"); + private static final DateTimeFormatter DATE_TIME_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(DEFAULT_TIMEZONE); + + private static String localDateTimeToHrfString(LocalDateTime localDateTime) { + return localDateTime.format(DATE_TIME_FORMATTER); } /** diff --git a/src/main/java/core/file/xml/ConvertXml2Hrf.java b/src/main/java/core/file/xml/ConvertXml2Hrf.java index 0509ec9a0..7fbf414ef 100644 --- a/src/main/java/core/file/xml/ConvertXml2Hrf.java +++ b/src/main/java/core/file/xml/ConvertXml2Hrf.java @@ -20,6 +20,7 @@ import core.util.Helper; import core.module.config.ModuleConfig; import core.net.MyConnector; +import hattrickdata.Arena; import module.transfer.PlayerTransfer; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -185,7 +186,7 @@ private ConvertXml2Hrf() { } catch (Exception ignored) { } - Map arenaDataMap = XMLArenaParser.parseArenaFromString(mc.downloadArena(arenaId)); + Arena arena = XMLArenaParser.parseArenaFromString(mc.downloadArena(arenaId)).getRight(); // MatchOrder HOMainFrame.instance().setInformation(Helper.getTranslation("ls.update_status.match_orders"), progressIncrement); @@ -229,7 +230,7 @@ private ConvertXml2Hrf() { // Arena HOMainFrame.instance().setInformation(Helper.getTranslation("ls.update_status.create_arena"), progressIncrement); - hrfSgtringBuilder.createArena(arenaDataMap); + hrfSgtringBuilder.createArena(arena); // players HOMainFrame.instance().setInformation(Helper.getTranslation("ls.update_status.create_players"), progressIncrement); diff --git a/src/main/java/core/file/xml/XMLArenaParser.java b/src/main/java/core/file/xml/XMLArenaParser.java index 2265c2866..1e4d3778c 100644 --- a/src/main/java/core/file/xml/XMLArenaParser.java +++ b/src/main/java/core/file/xml/XMLArenaParser.java @@ -1,13 +1,30 @@ package core.file.xml; import core.util.HOLogger; +import hattrickdata.Arena; +import hattrickdata.CurrentCapacity; +import hattrickdata.ExpandedCapacity; +import hattrickdata.HattrickDataInfo; +import hattrickdata.League; +import hattrickdata.Region; +import hattrickdata.Team; +import org.apache.commons.lang3.tuple.Pair; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.Map; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; public class XMLArenaParser { + public static final ZoneId DEFAULT_TIMEZONE = ZoneId.of("Europe/Stockholm"); + private static final DateTimeFormatter DATE_TIME_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(DEFAULT_TIMEZONE); + + private static final String ELEMENT_NAME_FILE_NAME = "FileName"; + private static final String ELEMENT_NAME_VERSION = "Version"; + private static final String ELEMENT_NAME_USER_ID = "UserID"; private static final String ELEMENT_NAME_FETCHED_DATE = "FetchedDate"; private static final String ELEMENT_NAME_ARENA = "Arena"; private static final String ELEMENT_NAME_ARENA_ID = "ArenaID"; @@ -34,130 +51,125 @@ public class XMLArenaParser { private static final String ELEMENT_NAME_CAPACITY_VIP = "VIP"; private static final String ELEMENT_NAME_CAPACITY_TOTAL = "Total"; - private static final String PROPERTY_NAME_FETCHED_DATE = "FetchedDate"; - private static final String PROPERTY_NAME_ARENA_ID = "ArenaID"; - private static final String PROPERTY_NAME_ARENA_NAME = "ArenaName"; - private static final String PROPERTY_NAME_TEAM_ID = "TeamID"; - private static final String PROPERTY_NAME_TEAM_NAME = "TeamName"; - private static final String PROPERTY_NAME_LEAGUE_ID = "LeagueID"; - private static final String PROPERTY_NAME_LEAGUE_NAME = "LeagueName"; - private static final String PROPERTY_NAME_REGION_ID = "RegionID"; - private static final String PROPERTY_NAME_REGION_NAME = "RegionName"; - - private static final String PROPERTY_NAME_CURRENT_CAPACITY_REBUILT_DATE = "RebuiltDate"; - private static final String PROPERTY_NAME_CURRENT_CAPACITY_TERRACES = "Terraces"; - private static final String PROPERTY_NAME_CURRENT_CAPACITY_BASIC = "Basic"; - private static final String PROPERTY_NAME_CURRENT_CAPACITY_ROOF = "Roof"; - private static final String PROPERTY_NAME_CURRENT_CAPACITY_VIP = "VIP"; - private static final String PROPERTY_NAME_CURRENT_CAPACITY_TOTAL = "Total"; - - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_IS_EXPANDING = "isExpanding"; - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_EXPANSION_DATE = "ExpansionDate"; - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_TERRACES = "ExTerraces"; - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_BASIC = "ExBasic"; - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_ROOF = "ExRoof"; - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_VIP = "ExVIP"; - private static final String PROPERTY_NAME_EXPANDING_CAPACITY_TOTAL = "ExTotal"; - - private static final String PROPERTY_VALUE_ZERO = "0"; - private static final String PROPERTY_VALUE_ONE = "1"; - private XMLArenaParser() { throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); } - public static Map parseArenaFromString(String str) { + public static Pair parseArenaFromString(String str) { return parseDetails(XMLManager.parseString(str)); } - private static Map parseDetails(Document doc) { - Map map = new SafeInsertMap(); - + private static Pair parseDetails(Document doc) { if (doc == null) { - return map; + return null; } try { + var hattrickDataInfoBuilder = HattrickDataInfo.builder(); + Element root = doc.getDocumentElement(); - Element element = (Element) root.getElementsByTagName(ELEMENT_NAME_FETCHED_DATE).item(0); - map.put(PROPERTY_NAME_FETCHED_DATE, XMLManager.getFirstChildNodeValue(element)); + + // FileName + Element element = (Element) root.getElementsByTagName(ELEMENT_NAME_FILE_NAME).item(0); + hattrickDataInfoBuilder.fileName(XMLManager.getFirstChildNodeValue(element)); + // Version + element = (Element) root.getElementsByTagName(ELEMENT_NAME_VERSION).item(0); + hattrickDataInfoBuilder.version(XMLManager.getFirstChildNodeValue(element)); + // UserId + element = (Element) root.getElementsByTagName(ELEMENT_NAME_USER_ID).item(0); + hattrickDataInfoBuilder.userId(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); + // FetchedDate + element = (Element) root.getElementsByTagName(ELEMENT_NAME_FETCHED_DATE).item(0); + hattrickDataInfoBuilder.fetchedDate(LocalDateTime.parse(XMLManager.getFirstChildNodeValue(element), DATE_TIME_FORMATTER)); + + final var hattrickDataInfo = hattrickDataInfoBuilder.build(); // Root wechseln root = (Element) root.getElementsByTagName(ELEMENT_NAME_ARENA).item(0); element = (Element) root.getElementsByTagName(ELEMENT_NAME_ARENA_ID).item(0); - map.put(PROPERTY_NAME_ARENA_ID, XMLManager.getFirstChildNodeValue(element)); + + var arenaBuilder = Arena.builder(); + arenaBuilder.id(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) root.getElementsByTagName(ELEMENT_NAME_ARENA_NAME).item(0); - map.put(PROPERTY_NAME_ARENA_NAME, XMLManager.getFirstChildNodeValue(element)); + arenaBuilder.name(XMLManager.getFirstChildNodeValue(element)); - Element tmpRoot = (Element) root.getElementsByTagName(ELEMENT_NAME_TEAM).item( - 0); + // Team + Element tmpRoot = (Element) root.getElementsByTagName(ELEMENT_NAME_TEAM).item(0); + var teamBuilder = Team.builder(); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_TEAM_ID).item(0); - map.put(PROPERTY_NAME_TEAM_ID, XMLManager.getFirstChildNodeValue(element)); + teamBuilder.id(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_TEAM_NAME).item(0); - map.put(PROPERTY_NAME_TEAM_NAME, XMLManager.getFirstChildNodeValue(element)); + teamBuilder.name(XMLManager.getFirstChildNodeValue(element)); + arenaBuilder.team(teamBuilder.build()); + // League + var leagueBuilder = League.builder(); tmpRoot = (Element) root.getElementsByTagName(ELEMENT_NAME_LEAGUE).item(0); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_LEAGUE_ID).item(0); - map.put(PROPERTY_NAME_LEAGUE_ID, XMLManager.getFirstChildNodeValue(element)); + leagueBuilder.id(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_LEAGUE_NAME).item(0); - map.put(PROPERTY_NAME_LEAGUE_NAME, XMLManager.getFirstChildNodeValue(element)); + leagueBuilder.name(XMLManager.getFirstChildNodeValue(element)); + arenaBuilder.league(leagueBuilder.build()); + // Region + var regionBuilder = Region.builder(); tmpRoot = (Element) root.getElementsByTagName(ELEMENT_NAME_REGION).item(0); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_REGION_ID).item(0); - map.put(PROPERTY_NAME_REGION_ID, XMLManager.getFirstChildNodeValue(element)); + regionBuilder.id(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_REGION_NAME).item(0); - map.put(PROPERTY_NAME_REGION_NAME, XMLManager.getFirstChildNodeValue(element)); + regionBuilder.name(XMLManager.getFirstChildNodeValue(element)); + arenaBuilder.region(regionBuilder.build()); + // Current Capacity tmpRoot = (Element) root.getElementsByTagName(ELEMENT_NAME_CURRENT_CAPACITY).item(0); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CURRENT_CAPACITY_REBUILT_DATE).item(0); + var currentCapacityBuilder = CurrentCapacity.builder(); final boolean rebuiltDateAvailable = getXmlAttributeAsBoolean(element, ATTRIBUTE_NAME_CAPACITY_AVAILABLE); if (rebuiltDateAvailable) { - map.put(PROPERTY_NAME_CURRENT_CAPACITY_REBUILT_DATE, XMLManager.getFirstChildNodeValue(element)); + currentCapacityBuilder.rebuildDate(LocalDateTime.parse(XMLManager.getFirstChildNodeValue(element), DATE_TIME_FORMATTER)); } element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_TERRACES).item(0); - map.put(PROPERTY_NAME_CURRENT_CAPACITY_TERRACES, XMLManager.getFirstChildNodeValue(element)); + currentCapacityBuilder.terraces(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_BASIC).item(0); - map.put(PROPERTY_NAME_CURRENT_CAPACITY_BASIC, XMLManager.getFirstChildNodeValue(element)); + currentCapacityBuilder.basic(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_ROOF).item(0); - map.put(PROPERTY_NAME_CURRENT_CAPACITY_ROOF, XMLManager.getFirstChildNodeValue(element)); + currentCapacityBuilder.roof(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_VIP).item(0); - map.put(PROPERTY_NAME_CURRENT_CAPACITY_VIP, XMLManager.getFirstChildNodeValue(element)); + currentCapacityBuilder.vip(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_TOTAL).item(0); - map.put(PROPERTY_NAME_CURRENT_CAPACITY_TOTAL, XMLManager.getFirstChildNodeValue(element)); + currentCapacityBuilder.total(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); + + arenaBuilder.currentCapacity(currentCapacityBuilder.build()); tmpRoot = (Element) root.getElementsByTagName(ELEMENT_NAME_EXPANDED_CAPACITY).item(0); final boolean expandedCapacityAvailable = getXmlAttributeAsBoolean(tmpRoot, ATTRIBUTE_NAME_CAPACITY_AVAILABLE); if (expandedCapacityAvailable) { - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_IS_EXPANDING, PROPERTY_VALUE_ONE); + var expandedCapacityBuilder = ExpandedCapacity.builder(); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_EXPANDED_CAPACITY_EXPANSION_DATE).item(0); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_EXPANSION_DATE, XMLManager.getFirstChildNodeValue(element)); + expandedCapacityBuilder.expansionDate(LocalDateTime.parse(XMLManager.getFirstChildNodeValue(element), DATE_TIME_FORMATTER)); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_TERRACES).item(0); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_TERRACES, XMLManager.getFirstChildNodeValue(element)); + expandedCapacityBuilder.terraces(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_BASIC).item(0); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_BASIC, XMLManager.getFirstChildNodeValue(element)); + expandedCapacityBuilder.basic(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_ROOF).item(0); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_ROOF, XMLManager.getFirstChildNodeValue(element)); + expandedCapacityBuilder.roof(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_VIP).item(0); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_VIP, XMLManager.getFirstChildNodeValue(element)); + expandedCapacityBuilder.vip(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); element = (Element) tmpRoot.getElementsByTagName(ELEMENT_NAME_CAPACITY_TOTAL).item(0); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_TOTAL, XMLManager.getFirstChildNodeValue(element)); - } else { - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_IS_EXPANDING, PROPERTY_VALUE_ZERO); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_EXPANSION_DATE, PROPERTY_VALUE_ZERO); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_TERRACES, PROPERTY_VALUE_ZERO); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_BASIC, PROPERTY_VALUE_ZERO); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_ROOF, PROPERTY_VALUE_ZERO); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_VIP, PROPERTY_VALUE_ZERO); - map.put(PROPERTY_NAME_EXPANDING_CAPACITY_TOTAL, PROPERTY_VALUE_ZERO); + expandedCapacityBuilder.total(Integer.parseInt(XMLManager.getFirstChildNodeValue(element))); + + arenaBuilder.expandedCapacity(expandedCapacityBuilder.build()); } + + return Pair.of(hattrickDataInfo, arenaBuilder.build()); } catch (Exception e) { HOLogger.instance().log(XMLArenaParser.class, e); } - return map; + return null; } @SuppressWarnings(value = "SameParameterValue") diff --git a/src/main/java/core/net/OnlineWorker.java b/src/main/java/core/net/OnlineWorker.java index a73727d7e..202ce79f4 100644 --- a/src/main/java/core/net/OnlineWorker.java +++ b/src/main/java/core/net/OnlineWorker.java @@ -805,8 +805,7 @@ private static Matchdetails downloadMatchDetails(int matchID, MatchType matchTyp } String arenaString = MyConnector.instance().downloadArena(details.getArenaID()); HOMainFrame.instance().setWaitInformation(); - String regionIdAsString = XMLArenaParser.parseArenaFromString(arenaString).get("RegionID"); - details.setRegionId(Integer.parseInt(regionIdAsString)); + details.setRegionId(XMLArenaParser.parseArenaFromString(arenaString).getRight().getRegion().getId()); } catch (Exception e) { String msg = getLangString("Downloadfehler") + ": Error fetching Matchdetails XML.: "; // Info diff --git a/src/main/java/core/util/HODateTime.java b/src/main/java/core/util/HODateTime.java index f42d399b0..c5c0999ca 100644 --- a/src/main/java/core/util/HODateTime.java +++ b/src/main/java/core/util/HODateTime.java @@ -32,7 +32,7 @@ public class HODateTime implements Comparable { /** * internal time representation */ - final public Instant instant; + public final Instant instant; /** * create an HODateTime instance (should it be private?) @@ -44,6 +44,14 @@ public HODateTime(@NotNull Instant in) { } public HODateTime(@NotNull HODateTime in){this.instant=in.instant;} + public Instant getInstant() { + return instant; + } + + public LocalDateTime getLocalDateTime() { + return LocalDateTime.ofInstant(instant, DEFAULT_TIMEZONE); + } + /** * Create instance from HT (chpp) string * diff --git a/src/main/java/hattrickdata/Arena.java b/src/main/java/hattrickdata/Arena.java new file mode 100644 index 000000000..38e9afeba --- /dev/null +++ b/src/main/java/hattrickdata/Arena.java @@ -0,0 +1,31 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +import java.util.Optional; + +@Getter +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@ToString +public class Arena { + + private int id; + private String name; + + private Team team; + private League league; + private Region region; + + private CurrentCapacity currentCapacity; + private ExpandedCapacity expandedCapacity; + + public Optional getExpandedCapacity() { + return Optional.ofNullable(expandedCapacity); + } +} diff --git a/src/main/java/hattrickdata/Capacity.java b/src/main/java/hattrickdata/Capacity.java new file mode 100644 index 000000000..4dd1b11be --- /dev/null +++ b/src/main/java/hattrickdata/Capacity.java @@ -0,0 +1,25 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +@Getter +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +@ToString +public class Capacity { + + private int terraces; + private int basic; + private int roof; + private int vip; + private int total; +} diff --git a/src/main/java/hattrickdata/CurrentCapacity.java b/src/main/java/hattrickdata/CurrentCapacity.java new file mode 100644 index 000000000..f54b6b8b4 --- /dev/null +++ b/src/main/java/hattrickdata/CurrentCapacity.java @@ -0,0 +1,26 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +import java.time.LocalDateTime; +import java.util.Optional; + +@Getter +@SuperBuilder() +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CurrentCapacity extends Capacity { + + private LocalDateTime rebuildDate; + + public Optional getRebuiltDate() { + return Optional.ofNullable(rebuildDate); + } +} diff --git a/src/main/java/hattrickdata/ExpandedCapacity.java b/src/main/java/hattrickdata/ExpandedCapacity.java new file mode 100644 index 000000000..52e4f9a63 --- /dev/null +++ b/src/main/java/hattrickdata/ExpandedCapacity.java @@ -0,0 +1,21 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +import java.time.LocalDateTime; + +@Getter +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ExpandedCapacity extends Capacity { + + private LocalDateTime expansionDate; +} diff --git a/src/main/java/hattrickdata/HattrickDataInfo.java b/src/main/java/hattrickdata/HattrickDataInfo.java new file mode 100644 index 000000000..c20040c44 --- /dev/null +++ b/src/main/java/hattrickdata/HattrickDataInfo.java @@ -0,0 +1,24 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; +import lombok.experimental.SuperBuilder; + +import java.time.LocalDateTime; + +@Getter +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode +@ToString +public class HattrickDataInfo { + + private String fileName; + private String version; + private int userId; + private LocalDateTime fetchedDate; +} diff --git a/src/main/java/hattrickdata/League.java b/src/main/java/hattrickdata/League.java new file mode 100644 index 000000000..a83ead13e --- /dev/null +++ b/src/main/java/hattrickdata/League.java @@ -0,0 +1,18 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@ToString +public class League { + + private int id; + private String name; +} diff --git a/src/main/java/hattrickdata/Region.java b/src/main/java/hattrickdata/Region.java new file mode 100644 index 000000000..5d06dc1c6 --- /dev/null +++ b/src/main/java/hattrickdata/Region.java @@ -0,0 +1,18 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@ToString +public class Region { + + private int id; + private String name; +} diff --git a/src/main/java/hattrickdata/Team.java b/src/main/java/hattrickdata/Team.java new file mode 100644 index 000000000..b24051920 --- /dev/null +++ b/src/main/java/hattrickdata/Team.java @@ -0,0 +1,18 @@ +package hattrickdata; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@ToString +public class Team { + + private int id; + private String name; +} diff --git a/src/main/java/tool/arenasizer/ArenaInfoPanel.java b/src/main/java/tool/arenasizer/ArenaInfoPanel.java new file mode 100644 index 000000000..4dfbdd2f2 --- /dev/null +++ b/src/main/java/tool/arenasizer/ArenaInfoPanel.java @@ -0,0 +1,174 @@ +package tool.arenasizer; + +import core.model.HOVerwaltung; +import core.util.HODateTime; +import core.util.Helper; + +import javax.swing.*; +import java.awt.*; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Optional; + +import static org.apache.commons.lang3.StringUtils.EMPTY; +import static tool.arenasizer.LabelWithSignedNumber.percentString; + +public class ArenaInfoPanel extends JPanel { + + private static final String DURATION_SUB_FORMAT = "%s%s"; + + private final CapacityPanel currentCapacityPanel; + private final CapacityPanel expandedCapacityPanel; + private final CapacityPanel futureCapacityPanel; + + public ArenaInfoPanel() { + setLayout(new FlowLayout()); + + currentCapacityPanel = new CapacityPanel(); + add(currentCapacityPanel); + + expandedCapacityPanel = new CapacityPanel(); + add(expandedCapacityPanel); + + futureCapacityPanel = new CapacityPanel(); + add(futureCapacityPanel); + + updateValues(); + + Timer timer = new Timer(1000, actionEvent -> updateExpansionFinishedLabel()); + timer.start(); + } + + private void updateValues() { + final Stadium stadium = HOVerwaltung.instance().getModel().getStadium(); + + final String notAvailableString = HOVerwaltung.instance().getLanguageString("ls.general_label.not_available_abbreviation"); + final var numberformat = Helper.getNumberFormat(false, 0); + + // Current Capacity + currentCapacityPanel.labelCountTerraces.setText(numberformat.format(stadium.getStehplaetze())); + currentCapacityPanel.labelCountBasicSeating.setText(numberformat.format(stadium.getSitzplaetze())); + currentCapacityPanel.labelCountSeatsUnderRoof.setText(numberformat.format(stadium.getUeberdachteSitzplaetze())); + currentCapacityPanel.labelCountVipBoxes.setText(numberformat.format(stadium.getLogen())); + currentCapacityPanel.labelCountTotal.setText(numberformat.format(stadium.getGesamtgroesse())); + + currentCapacityPanel.labelPercentageTerraces.setText(percentString(stadium.getStehplaetze(), stadium.getGesamtgroesse())); + currentCapacityPanel.labelPercentageBasicSeating.setText(percentString(stadium.getSitzplaetze(), stadium.getGesamtgroesse())); + currentCapacityPanel.labelPercentageSeatsUnderRoof.setText(percentString(stadium.getUeberdachteSitzplaetze(), stadium.getGesamtgroesse())); + currentCapacityPanel.labelPercentageVipBoxes.setText(percentString(stadium.getLogen(), stadium.getGesamtgroesse())); + currentCapacityPanel.labelPercentageTotal.setText(percentString(stadium.getGesamtgroesse(), stadium.getGesamtgroesse())); + + currentCapacityPanel.label2.setText(Optional.ofNullable(stadium.getRebuiltDate()).map(HODateTime::toLocaleDate).orElse(getLanguageString("ArenaInfoPanel.construction_in_progress"))); + + // Expanded Capacity + expandedCapacityPanel.labelCountTerraces.setNumber(stadium.isAusbau() ? stadium.getAusbauStehplaetze() : null); + expandedCapacityPanel.labelCountBasicSeating.setNumber(stadium.isAusbau() ? stadium.getAusbauSitzplaetze() : null); + expandedCapacityPanel.labelCountSeatsUnderRoof.setNumber(stadium.isAusbau() ? stadium.getAusbauUeberdachteSitzplaetze() : null); + expandedCapacityPanel.labelCountVipBoxes.setNumber(stadium.isAusbau() ? stadium.getAusbauLogen() : null); + expandedCapacityPanel.labelCountTotal.setNumber(stadium.getAusbauGesamtgroesse().orElse(null)); + + expandedCapacityPanel.labelPercentageTerraces.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauStehplaetze()).divide(BigDecimal.valueOf(stadium.getStehplaetze()), 3, RoundingMode.HALF_DOWN) : null); + expandedCapacityPanel.labelPercentageBasicSeating.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauSitzplaetze()).divide(BigDecimal.valueOf(stadium.getSitzplaetze()), 3, RoundingMode.HALF_DOWN) : null); + expandedCapacityPanel.labelPercentageSeatsUnderRoof.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauUeberdachteSitzplaetze()).divide(BigDecimal.valueOf(stadium.getUeberdachteSitzplaetze()), 3, RoundingMode.HALF_DOWN) : null); + expandedCapacityPanel.labelPercentageVipBoxes.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauLogen()).divide(BigDecimal.valueOf(stadium.getLogen()), 3, RoundingMode.HALF_DOWN) : null); + expandedCapacityPanel.labelPercentageTotal.setPercentNumber(stadium.getAusbauGesamtgroesse().map(expansionTotal -> BigDecimal.valueOf(expansionTotal).divide(BigDecimal.valueOf(stadium.getGesamtgroesse()), 3, RoundingMode.HALF_DOWN)).orElse(null)); + + expandedCapacityPanel.label2.setText(Optional.ofNullable(stadium.getExpansionDate()).map(expansionDate -> expansionDate.toLocaleDateTime()).orElse(EMPTY)); + + // Future + futureCapacityPanel.labelCountTerraces.setText(stadium.getZukunftStehplaetze().map(numberformat::format).orElse(notAvailableString)); + futureCapacityPanel.labelCountBasicSeating.setText(stadium.getZukunftSitzplaetze().map(numberformat::format).orElse(notAvailableString)); + futureCapacityPanel.labelCountSeatsUnderRoof.setText(stadium.getZukunftUeberdachteSitzplaetze().map(numberformat::format).orElse(notAvailableString)); + futureCapacityPanel.labelCountVipBoxes.setText(stadium.getZukunftLogen().map(numberformat::format).orElse(notAvailableString)); + futureCapacityPanel.labelCountTotal.setText(stadium.getZukunftGesamtgroesse().map(numberformat::format).orElse(notAvailableString)); + + futureCapacityPanel.labelPercentageTerraces.setText(stadium.getZukunftStehplaetze().map(future -> percentString(future, stadium.getZukunftGesamtgroesse().get())).orElse(notAvailableString)); + futureCapacityPanel.labelPercentageBasicSeating.setText(stadium.getZukunftSitzplaetze().map(future -> percentString(future, stadium.getZukunftGesamtgroesse().get())).orElse(notAvailableString)); + futureCapacityPanel.labelPercentageSeatsUnderRoof.setText(stadium.getZukunftUeberdachteSitzplaetze().map(future -> percentString(future, stadium.getZukunftGesamtgroesse().get())).orElse(notAvailableString)); + futureCapacityPanel.labelPercentageVipBoxes.setText(stadium.getZukunftLogen().map(future -> percentString(future, stadium.getZukunftGesamtgroesse().get())).orElse(notAvailableString)); + futureCapacityPanel.labelPercentageTotal.setText(stadium.getZukunftGesamtgroesse().map(future -> percentString(future, stadium.getZukunftGesamtgroesse().get())).orElse(notAvailableString)); + + futureCapacityPanel.label2.setText(Optional.ofNullable(stadium.getExpansionDate()) + .map(expansionDate -> nextDay(expansionDate).toLocaleDate()) + .orElse(EMPTY)); + + setTranslation(); + } + + private static HODateTime nextDay(HODateTime hoDateTime) { + var localDate = hoDateTime.getLocalDateTime().toLocalDate(); + var nextDay = localDate.plusDays(1); + var instant = Instant.from(nextDay.atStartOfDay(HODateTime.DEFAULT_TIMEZONE)); + return new HODateTime(instant); + } + + private void setTranslation() { + currentCapacityPanel.setTranslation(); + currentCapacityPanel.setTitle(getLanguageString("ArenaInfoPanel.current")); + currentCapacityPanel.label1.setText(getLanguageString("ArenaInfoPanel.last_improvement")); + + expandedCapacityPanel.setTranslation(); + expandedCapacityPanel.setTitle(getLanguageString("ArenaInfoPanel.expansion")); + expandedCapacityPanel.labelPercentage.setText(getLanguageString("ArenaInfoPanel.change_in_percent")); + expandedCapacityPanel.label1.setText(getLanguageString("ArenaInfoPanel.completion")); + + futureCapacityPanel.setTranslation(); + futureCapacityPanel.setTitle(getLanguageString("ArenaInfoPanel.future")); + futureCapacityPanel.label1.setText(getLanguageString("ArenaInfoPanel.available")); + } + + private void updateExpansionFinishedLabel() { + final JLabel labelExpansionFinished = expandedCapacityPanel.label3; + final Stadium stadium = HOVerwaltung.instance().getModel().getStadium(); + Optional.ofNullable(stadium).map(Stadium::getExpansionDate).ifPresentOrElse(expansionDate -> { + final String text = toDurationString(expansionDate); + final String toolTipText = String.format(getLanguageString("ArenaInfoPanel.finished_in_n_days_format"), calculateDaysToNow(expansionDate, 1)); + labelExpansionFinished.setText(text); + labelExpansionFinished.setToolTipText(toolTipText); + }, + () -> { + labelExpansionFinished.setToolTipText(null); + labelExpansionFinished.setText(EMPTY); + } + ); + } + + private static String getLanguageString(String key) { + return HOVerwaltung.instance().getLanguageString(key); + } + + private static BigDecimal calculateDaysToNow(HODateTime hoDateTime, int scale) { + return BigDecimal.valueOf(hoDateTime.getInstant().toEpochMilli() - HODateTime.now().getInstant().toEpochMilli()) + .divide(BigDecimal.valueOf(1000L * 86400L), scale, RoundingMode.HALF_DOWN); + } + + private static String toDurationString(HODateTime hoDateTime) { + long seconds = (hoDateTime.getInstant().toEpochMilli() - HODateTime.now().getInstant().toEpochMilli()) / 1000L; + final long days = seconds / 86400L; + seconds -= days * 86400L; + final long hours = seconds / 3600L; + seconds -= hours * 3600L; + final long minutes = seconds / 60L; + seconds -= minutes * 60L; + ArrayList strings = new ArrayList<>(); + if (days > 0) { + final var unit = getLanguageString("ArenaInfoPanel.days_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, days, unit)); + } + if (hours > 0) { + final var unit = getLanguageString("ArenaInfoPanel.hours_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, hours, unit)); + } + if (minutes > 0) { + final var unit = getLanguageString("ArenaInfoPanel.minutes_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, minutes, unit)); + } + if (seconds > 0) { + final var unit = getLanguageString("ArenaInfoPanel.seconds_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, seconds, unit)); + } + return String.join(", ", strings); + } +} \ No newline at end of file diff --git a/src/main/java/tool/arenasizer/ArenaSizerDialog.java b/src/main/java/tool/arenasizer/ArenaSizerDialog.java index cf2097163..060871e42 100644 --- a/src/main/java/tool/arenasizer/ArenaSizerDialog.java +++ b/src/main/java/tool/arenasizer/ArenaSizerDialog.java @@ -3,7 +3,6 @@ import core.model.HOVerwaltung; import java.awt.BorderLayout; -import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -19,9 +18,9 @@ public class ArenaSizerDialog extends JDialog implements ActionListener { private static final long serialVersionUID = 1L; private JTabbedPane tabbedPane; - private ArenaPanel panel; + private ArenaPanel arenaPanel; private DistributionStatisticsPanel historyPanel; - private ArenaPanel infoPanel; + private ArenaInfoPanel arenaInfoPanel; private ControlPanel controlPanel; private JPanel toolbar; private JButton refreshButton = new JButton(HOVerwaltung.instance().getLanguageString("ls.button.apply")); @@ -33,7 +32,6 @@ public ArenaSizerDialog(JFrame owner){ } private void initialize() { - setSize(900,430); setLayout(new BorderLayout()); setTitle(HOVerwaltung.instance().getLanguageString("ArenaSizer")); add(getToolbar(), BorderLayout.NORTH); @@ -47,6 +45,8 @@ private void initialize() { add(centerPanel,BorderLayout.CENTER); + pack(); + setLocationByPlatform(true); } private JPanel getToolbar(){ @@ -74,18 +74,18 @@ private JPanel getHistoryPanel(){ return historyPanel; } - ArenaPanel getArenaPanel(){ - if(panel == null){ - panel = new ArenaPanel(); + ArenaPanel getArenaPanel() { + if (arenaPanel == null) { + arenaPanel = new ArenaPanel(); } - return panel; + return arenaPanel; } - ArenaPanel getInfoPanel(){ - if(infoPanel == null){ - infoPanel = new ArenaPanel(); + ArenaInfoPanel getArenaInfoPanel() { + if (arenaInfoPanel == null) { + arenaInfoPanel = new ArenaInfoPanel(); } - return infoPanel; + return arenaInfoPanel; } private JTabbedPane getTabbedPane(){ @@ -93,30 +93,18 @@ private JTabbedPane getTabbedPane(){ tabbedPane = new JTabbedPane(); HOVerwaltung hoV = HOVerwaltung.instance(); tabbedPane.addTab(hoV.getLanguageString("Stadion"), getArenaPanel()); - tabbedPane.addTab(hoV.getModel().getStadium().getStadienname(), getInfoPanel()); + tabbedPane.addTab(hoV.getModel().getStadium().getStadienname(), getArenaInfoPanel()); tabbedPane.addTab(hoV.getLanguageString("Statistik"), getHistoryPanel()); } return tabbedPane; } - @Override - public void setSize(int width, int height) { - super.setSize(width, height); - - Dimension screenSize = getParent().getSize(); - int x = (screenSize.width - getWidth()) / 2; - int y = (screenSize.height - getHeight()) / 2; - - setLocation(getParent().getX()+x, getParent().getY()+y); - } - @Override public void actionPerformed(ActionEvent e) { if(e.getSource() == refreshButton){ Stadium stadium = getControlPanel().getStadium(); int[] supporter = getControlPanel().getModifiedSupporter(); getArenaPanel().reinitArena(stadium, supporter[0],supporter[1],supporter[2]); - getInfoPanel().reinitArena(HOVerwaltung.instance().getModel().getStadium(), supporter[0],supporter[1],supporter[2]); } } } diff --git a/src/main/java/tool/arenasizer/CapacityPanel.java b/src/main/java/tool/arenasizer/CapacityPanel.java new file mode 100644 index 000000000..dce766de1 --- /dev/null +++ b/src/main/java/tool/arenasizer/CapacityPanel.java @@ -0,0 +1,185 @@ +package tool.arenasizer; + +import core.model.HOVerwaltung; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.io.IOException; +import java.util.Optional; + +import static org.apache.commons.lang3.StringUtils.EMPTY; + +public class CapacityPanel extends JPanel { + + private static final int HORIZONTAL_ALIGNMENT_PLACE_TYPE = SwingConstants.RIGHT; + private static final int HORIZONTAL_ALIGNMENT_PLACES = SwingConstants.RIGHT; + private static final int HORIZONTAL_ALIGNMENT_PERCENTAGE = SwingConstants.RIGHT; + + private static final String SUM_SIGN = "∑"; + + private static final boolean LONG_MODE = true; + + final JLabel labelPlaceType; + final JLabel labelPlaces; + final JLabel labelPercentage; + + final JLabel labelTerraces; + final JLabel labelBasicSeating; + final JLabel labelSeatsUnderRoof; + final JLabel labelVipBoxes; + final JLabel labelTotal; + + final LabelWithSignedNumber labelCountTerraces; + final LabelWithSignedNumber labelCountBasicSeating; + final LabelWithSignedNumber labelCountSeatsUnderRoof; + final LabelWithSignedNumber labelCountVipBoxes; + final LabelWithSignedNumber labelCountTotal; + + final LabelWithSignedNumber labelPercentageTerraces; + final LabelWithSignedNumber labelPercentageBasicSeating; + final LabelWithSignedNumber labelPercentageSeatsUnderRoof; + final LabelWithSignedNumber labelPercentageVipBoxes; + final LabelWithSignedNumber labelPercentageTotal; + + final JLabel label1; + final JLabel label2; + final JLabel label3; + + public CapacityPanel() { + super(new GridLayout(7, 3, 3, 3)); + setTitle(EMPTY); + + // Title + labelPlaceType = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PLACE_TYPE); + setFontToBold(labelPlaceType); + add(labelPlaceType); + labelPlaces = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PLACE_TYPE); + setFontToBold(labelPlaces); + add(labelPlaces); + labelPercentage = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PLACE_TYPE); + setFontToBold(labelPercentage); + add(labelPercentage); + + // Terraces + labelTerraces = new JLabel(); + loadImageIcon("gui/bilder/arena/terraces.png").ifPresent(labelTerraces::setIcon); + labelTerraces.setHorizontalTextPosition(SwingConstants.LEADING); + labelTerraces.setHorizontalAlignment(HORIZONTAL_ALIGNMENT_PLACE_TYPE); + add(labelTerraces); + labelCountTerraces = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PLACES); + add(labelCountTerraces); + labelPercentageTerraces = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PERCENTAGE); + add(labelPercentageTerraces); + + // Basic Seating + labelBasicSeating = new JLabel(); + loadImageIcon("gui/bilder/arena/basicseating.png").ifPresent(labelBasicSeating::setIcon); + labelBasicSeating.setHorizontalTextPosition(SwingConstants.LEADING); + labelBasicSeating.setHorizontalAlignment(HORIZONTAL_ALIGNMENT_PLACE_TYPE); + add(labelBasicSeating); + labelCountBasicSeating = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PLACES); + add(labelCountBasicSeating); + labelPercentageBasicSeating = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PERCENTAGE); + add(labelPercentageBasicSeating); + + // Seats Under Roof + labelSeatsUnderRoof = new JLabel(); + loadImageIcon("gui/bilder/arena/seatsunderroof.png").ifPresent(labelSeatsUnderRoof::setIcon); + labelSeatsUnderRoof.setHorizontalTextPosition(SwingConstants.LEADING); + labelSeatsUnderRoof.setHorizontalAlignment(HORIZONTAL_ALIGNMENT_PLACE_TYPE); + add(labelSeatsUnderRoof); + labelCountSeatsUnderRoof = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PLACES); + add(labelCountSeatsUnderRoof); + labelPercentageSeatsUnderRoof = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PERCENTAGE); + add(labelPercentageSeatsUnderRoof); + + // VIP + labelVipBoxes = new JLabel(); + loadImageIcon("gui/bilder/arena/vipboxes.png").ifPresent(labelVipBoxes::setIcon); + labelVipBoxes.setHorizontalTextPosition(SwingConstants.LEADING); + labelVipBoxes.setHorizontalAlignment(HORIZONTAL_ALIGNMENT_PLACE_TYPE); + add(labelVipBoxes); + labelCountVipBoxes = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PLACES); + add(labelCountVipBoxes); + labelPercentageVipBoxes = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PERCENTAGE); + add(labelPercentageVipBoxes); + + // Total + labelTotal = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PLACE_TYPE); + setFontToBold(labelTotal); + add(labelTotal); + labelCountTotal = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PLACES); + setFontToBold(labelCountTotal); + add(labelCountTotal); + labelPercentageTotal = new LabelWithSignedNumber(EMPTY, HORIZONTAL_ALIGNMENT_PERCENTAGE); + setFontToBold(labelPercentageTotal); + add(labelPercentageTotal); + + // Misc + label1 = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PLACE_TYPE); + setFontToBold(label1); + add(label1); + label2 = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PLACES); + setFontToBold(label2); + add(label2); + label3 = new JLabel(EMPTY, HORIZONTAL_ALIGNMENT_PERCENTAGE); + setFontToBold(label3); + add(label3); + + setTranslation(); + } + + public void setTitle(String titel) { + setBorder(BorderFactory.createTitledBorder(titel)); + } + + public void setTranslation() { + labelPlaceType.setText(getLanguageString("ArenaInfoPanel.place_type")); + labelPlaces.setText(getLanguageString("ArenaInfoPanel.places")); + labelPercentage.setText(getLanguageString("ArenaInfoPanel.rate_in_percent")); + + labelTerraces.setToolTipText(getLanguageString("ls.club.arena.terraces")); + if (LONG_MODE) { + labelTerraces.setText(labelTerraces.getToolTipText()); + } + + labelBasicSeating.setToolTipText(getLanguageString("ls.club.arena.basicseating")); + if (LONG_MODE) { + labelBasicSeating.setText(labelBasicSeating.getToolTipText()); + } + + labelSeatsUnderRoof.setToolTipText(getLanguageString("ls.club.arena.seatsunderroof")); + if (LONG_MODE) { + labelSeatsUnderRoof.setText(labelSeatsUnderRoof.getToolTipText()); + } + + labelVipBoxes.setToolTipText(getLanguageString("ls.club.arena.seatsinvipboxes")); + if (LONG_MODE) { + labelVipBoxes.setText(labelVipBoxes.getToolTipText()); + } + + labelTotal.setToolTipText(getLanguageString("Gesamtgroesse")); + if (LONG_MODE) { + labelTotal.setText(labelTotal.getToolTipText() + " " + SUM_SIGN); + } else { + labelTotal.setText(SUM_SIGN); + } + } + + private static String getLanguageString(String key) { + return HOVerwaltung.instance().getLanguageString(key); + } + + private static Optional loadImageIcon(String name) { + try { + return Optional.of(new ImageIcon(ImageIO.read(ClassLoader.getSystemResource(name)))); + } catch (IOException e) { + return Optional.empty(); + } + } + + private static void setFontToBold(JComponent component) { + component.setFont(component.getFont().deriveFont(Font.BOLD)); + } +} diff --git a/src/main/java/tool/arenasizer/LabelWithSignedNumber.java b/src/main/java/tool/arenasizer/LabelWithSignedNumber.java new file mode 100644 index 000000000..fd01f94a0 --- /dev/null +++ b/src/main/java/tool/arenasizer/LabelWithSignedNumber.java @@ -0,0 +1,84 @@ +package tool.arenasizer; + +import core.gui.theme.HOColorName; +import core.gui.theme.ThemeManager; +import core.model.HOVerwaltung; +import core.util.Helper; + +import javax.swing.*; +import java.awt.*; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.NumberFormat; + +import static java.math.BigDecimal.ZERO; +import static org.apache.commons.lang3.StringUtils.EMPTY; + +class LabelWithSignedNumber extends JLabel { + + private final String notAvailableString = HOVerwaltung.instance().getLanguageString("ls.general_label.not_available_abbreviation"); + + public LabelWithSignedNumber(String text, int horizontalAlignment) { + super(text, horizontalAlignment); + } + + public void setNumber(Integer number) { + final var numberformat = Helper.getNumberFormat(false, 0); + if (number != null) { + setForeground(getColor(number)); + setText(formatNumberWithSign(numberformat, number)); + } else { + setForeground(getColor(0)); + setText(notAvailableString); + } + } + + public void setPercentNumber(BigDecimal percentage) { + if (percentage != null) { + setForeground(getColor(percentage)); + setText(formatNumberWithSign(percentage)); + } else { + setForeground(getColor(0)); + setText(notAvailableString); + } + } + + private static Color getColor(int number) { + return getColorFromCompareResult(Integer.compare(number, 0)); + } + + private static Color getColor(BigDecimal number) { + return getColorFromCompareResult(number.compareTo(ZERO)); + } + + private static Color getColorFromCompareResult(int compareResult) { + if (compareResult > 0) { + return ThemeManager.getColor(HOColorName.TABLEENTRY_IMPROVEMENT_FG); + } else if (compareResult < 0) { + return ThemeManager.getColor(HOColorName.TABLEENTRY_DECLINE_FG); + } else { + return ThemeManager.getColor(HOColorName.TABLEENTRY_FG); + } + } + + private static String formatNumberWithSign(NumberFormat numberformat, int number) { + final String prefix = (number > 0) ? "+" : EMPTY; + return prefix + numberformat.format(number); + } + + private static String formatNumberWithSign(BigDecimal percentage) { + final String prefix = (percentage.compareTo(ZERO) > 0) ? "+" : EMPTY; + return prefix + percentageValueString(percentage); + } + + public static String percentString(int w, int g) { + return percentageValueString(BigDecimal.valueOf(w).divide(BigDecimal.valueOf(g), 4, RoundingMode.HALF_DOWN)); + } + + public static String percentageValueString(BigDecimal percentage) { + final BigDecimal percent = percentage + .multiply(BigDecimal.valueOf(100)) + .setScale(1, RoundingMode.HALF_DOWN); + return String.format("%s %%", percent); + } +} \ No newline at end of file diff --git a/src/main/java/tool/arenasizer/Stadium.java b/src/main/java/tool/arenasizer/Stadium.java index f916aa3c8..a4bcce4ca 100644 --- a/src/main/java/tool/arenasizer/Stadium.java +++ b/src/main/java/tool/arenasizer/Stadium.java @@ -1,316 +1,147 @@ package tool.arenasizer; import core.db.AbstractTable; +import core.util.HODateTime; +import lombok.Getter; +import lombok.Setter; import org.apache.commons.lang3.math.NumberUtils; +import java.util.Optional; import java.util.Properties; -/** - * Enthält die Stadiendaten - */ +@Setter +@Getter public class Stadium extends AbstractTable.Storable { - //~ Instance fields ---------------------------------------------------------------------------- - - /** Stadienname */ - private String m_sStadienname = ""; - - /** Stadium Id */ - private int m_iStadiumId; - - /** Wird ausgebaut? */ - private boolean m_bAusbau; - - /** Ausbaukosten */ - private int m_iAusbauKosten; - - /** Ausbau Logen */ - private int m_iAusbauLogen; - - /** Ausbau Sitzplätze */ - private int m_iAusbauSitzplaetze; - - /** Ausbau Stehplätze */ - private int m_iAusbauStehplaetze; - - /** Ausbau Überdachte Sitzplätze */ - private int m_iAusbauUeberdachteSitzplaetze; - - /** Logen */ - private int m_iLogen; - - /** Sitzplätze */ - private int m_iSitzplaetze; - - /** Stehplätze */ - private int m_iStehplaetze; - - /** Überdachte Sitzplätze */ - private int m_iUeberdachteSitzplaetze; - private int hrfId; - - //~ Constructors ------------------------------------------------------------------------------- - - /** - * Creates a new Stadium object. - */ - public Stadium() { - } /** - * Creates a new Stadium object. + * HRF-ID */ - public Stadium(Properties properties) { - m_sStadienname = properties.getProperty("arenaname", ""); - m_iStadiumId = NumberUtils.toInt(properties.getProperty("arenaid"),0); - //m_iGesamtgroesse = NumberUtils.toInt(properties.getProperty("seattotal"),0); - m_iStehplaetze = NumberUtils.toInt(properties.getProperty("antalstaplats"),0); - m_iSitzplaetze = NumberUtils.toInt(properties.getProperty("antalsitt"),0); - m_iUeberdachteSitzplaetze = NumberUtils.toInt(properties.getProperty("antaltak"),0); - m_iLogen = NumberUtils.toInt(properties.getProperty("antalvip"),0); - m_iAusbauStehplaetze = NumberUtils.toInt(properties.getProperty("expandingstaplats"),0); - m_iAusbauSitzplaetze = NumberUtils.toInt(properties.getProperty("expandingsitt"),0); - m_iAusbauUeberdachteSitzplaetze = NumberUtils.toInt(properties.getProperty("expandingtak"),0); - m_iAusbauLogen = NumberUtils.toInt(properties.getProperty("expandingvip"),0); - m_bAusbau = NumberUtils.toInt(properties.getProperty("isexpanding"), 0) > 0; - if (m_bAusbau) { - m_iAusbauKosten = NumberUtils.toInt(properties.getProperty("expandcost"),0); - } - } - - //~ Methods ------------------------------------------------------------------------------------ - - /** - * Setter for property m_bAusbau. - * - * @param m_bAusbau New value of property m_bAusbau. - */ - public final void setAusbau(boolean m_bAusbau) { - this.m_bAusbau = m_bAusbau; - } - - /** - * Getter for property m_bAusbau. - * - * @return Value of property m_bAusbau. - */ - public final boolean isAusbau() { - return m_bAusbau; - } - - /** - * Setter for property m_iAusbauKosten. - * - * @param m_iAusbauKosten New value of property m_iAusbauKosten. - */ - public final void setAusbauKosten(int m_iAusbauKosten) { - this.m_iAusbauKosten = m_iAusbauKosten; - } + private int hrfId; /** - * Getter for property m_iAusbauKosten. - * - * @return Value of property m_iAusbauKosten. + * Arena-ID */ - public final int getAusbauKosten() { - return m_iAusbauKosten; - } + private int arenaId; /** - * Setter for property m_iAusbauLogen. - * - * @param m_iAusbauLogen New value of property m_iAusbauLogen. + * Arena-Name */ - public final void setAusbauLogen(int m_iAusbauLogen) { - this.m_iAusbauLogen = m_iAusbauLogen; - } + private String stadienname = ""; /** - * Getter for property m_iAusbauLogen. - * - * @return Value of property m_iAusbauLogen. + * Terraces */ - public final int getAusbauLogen() { - return m_iAusbauLogen; - } + private int stehplaetze; /** - * Setter for property m_iAusbauSitzplaetze. - * - * @param m_iAusbauSitzplaetze New value of property m_iAusbauSitzplaetze. + * Basic Seating */ - public final void setAusbauSitzplaetze(int m_iAusbauSitzplaetze) { - this.m_iAusbauSitzplaetze = m_iAusbauSitzplaetze; - } + private int sitzplaetze; /** - * Getter for property m_iAusbauSitzplaetze. - * - * @return Value of property m_iAusbauSitzplaetze. + * Seats under Roof */ - public final int getAusbauSitzplaetze() { - return m_iAusbauSitzplaetze; - } + private int ueberdachteSitzplaetze; /** - * Setter for property m_iAusbauStehplaetze. - * - * @param m_iAusbauStehplaetze New value of property m_iAusbauStehplaetze. + * VIP Boxes */ - public final void setAusbauStehplaetze(int m_iAusbauStehplaetze) { - this.m_iAusbauStehplaetze = m_iAusbauStehplaetze; - } + private int logen; /** - * Getter for property m_iAusbauStehplaetze. - * - * @return Value of property m_iAusbauStehplaetze. + * Expansion? */ - public final int getAusbauStehplaetze() { - return m_iAusbauStehplaetze; - } + private boolean ausbau; /** - * Setter for property m_iAusbauUeberdachteSitzplaetze. - * - * @param m_iAusbauUeberdachteSitzplaetze New value of property - * m_iAusbauUeberdachteSitzplaetze. + * Expansion of Terraces */ - public final void setAusbauUeberdachteSitzplaetze(int m_iAusbauUeberdachteSitzplaetze) { - this.m_iAusbauUeberdachteSitzplaetze = m_iAusbauUeberdachteSitzplaetze; - } + private int ausbauStehplaetze; /** - * Getter for property m_iAusbauUeberdachteSitzplaetze. - * - * @return Value of property m_iAusbauUeberdachteSitzplaetze. + * Expansion of Basic Seating */ - public final int getAusbauUeberdachteSitzplaetze() { - return m_iAusbauUeberdachteSitzplaetze; - } - - - ////////////////////////////Accessor//////////////////////////////////////// + private int ausbauSitzplaetze; /** - * Getter for property m_iGesamtgroesse. - * - * @return Value of property m_iGesamtgroesse. + * Expansion of Seats under Roof */ - public final int getGesamtgroesse() { - return getStehplaetze() + getSitzplaetze() + getUeberdachteSitzplaetze() + getLogen(); - } + private int ausbauUeberdachteSitzplaetze; /** - * Setter for property m_iLogen. - * - * @param m_iLogen New value of property m_iLogen. + * Expansion of VIP Boxes */ - public final void setLogen(int m_iLogen) { - this.m_iLogen = m_iLogen; - } + private int ausbauLogen; /** - * Getter for property m_iLogen. - * - * @return Value of property m_iLogen. + * Cost of Expansion */ - public final int getLogen() { - return m_iLogen; - } + private int ausbauKosten; /** - * Setter for property m_iSitzplaetze. - * - * @param m_iSitzplaetze New value of property m_iSitzplaetze. + * Rebuilt date */ - public final void setSitzplaetze(int m_iSitzplaetze) { - this.m_iSitzplaetze = m_iSitzplaetze; - } + @Setter + @Getter + private HODateTime rebuiltDate; /** - * Getter for property m_iSitzplaetze. - * - * @return Value of property m_iSitzplaetze. + * Expansion date */ - public final int getSitzplaetze() { - return m_iSitzplaetze; - } + @Setter + @Getter + private HODateTime expansionDate; - /** - * Setter for property m_sStadienname. - * - * @param m_sStadienname New value of property m_sStadienname. - */ - public final void setStadienname(java.lang.String m_sStadienname) { - this.m_sStadienname = m_sStadienname; + public Stadium() { } - /** - * Getter for property m_sStadienname. - * - * @return Value of property m_sStadienname. - */ - public final java.lang.String getStadienname() { - return m_sStadienname; + public Stadium(Properties properties) { + // 'seattotal' and 'expandingSseatTotal' are currently not read + arenaId = NumberUtils.toInt(properties.getProperty("arenaid"), 0); + stadienname = properties.getProperty("arenaname", ""); + stehplaetze = NumberUtils.toInt(properties.getProperty("antalstaplats"), 0); + sitzplaetze = NumberUtils.toInt(properties.getProperty("antalsitt"), 0); + ueberdachteSitzplaetze = NumberUtils.toInt(properties.getProperty("antaltak"), 0); + logen = NumberUtils.toInt(properties.getProperty("antalvip"), 0); + ausbauStehplaetze = NumberUtils.toInt(properties.getProperty("expandingstaplats"), 0); + ausbauSitzplaetze = NumberUtils.toInt(properties.getProperty("expandingsitt"), 0); + ausbauUeberdachteSitzplaetze = NumberUtils.toInt(properties.getProperty("expandingtak"), 0); + ausbauLogen = NumberUtils.toInt(properties.getProperty("expandingvip"), 0); + ausbau = NumberUtils.toInt(properties.getProperty("isexpanding"), 0) > 0; + if (ausbau) { + ausbauKosten = NumberUtils.toInt(properties.getProperty("expandcost"), 0); + } + rebuiltDate = HODateTime.fromHT(properties.getProperty("rebuiltdate")); + expansionDate = HODateTime.fromHT(properties.getProperty("expansiondate")); } - /** - * Setter for property m_iStehplaetze. - * - * @param m_iStehplaetze New value of property m_iStehplaetze. - */ - public final void setStehplaetze(int m_iStehplaetze) { - this.m_iStehplaetze = m_iStehplaetze; + public int getGesamtgroesse() { + return getStehplaetze() + getSitzplaetze() + getUeberdachteSitzplaetze() + getLogen(); } - /** - * Getter for property m_iStehplaetze. - * - * @return Value of property m_iStehplaetze. - */ - public final int getStehplaetze() { - return m_iStehplaetze; + public Optional getAusbauGesamtgroesse() { + return isAusbau() ? + Optional.of(getAusbauStehplaetze() + getAusbauSitzplaetze() + getAusbauUeberdachteSitzplaetze() + getAusbauLogen()) : + Optional.empty(); } - /** - * Setter for property m_iUeberdachteSitzplaetze. - * - * @param m_iUeberdachteSitzplaetze New value of property m_iUeberdachteSitzplaetze. - */ - public final void setUeberdachteSitzplaetze(int m_iUeberdachteSitzplaetze) { - this.m_iUeberdachteSitzplaetze = m_iUeberdachteSitzplaetze; + public Optional getZukunftGesamtgroesse() { + return getAusbauGesamtgroesse().map(ausbauGesamtgroesse -> ausbauGesamtgroesse + getGesamtgroesse()); } - /** - * Getter for property m_iUeberdachteSitzplaetze. - * - * @return Value of property m_iUeberdachteSitzplaetze. - */ - public final int getUeberdachteSitzplaetze() { - return m_iUeberdachteSitzplaetze; + public Optional getZukunftStehplaetze() { + return isAusbau() ? Optional.of(getStehplaetze() + getAusbauStehplaetze()) : Optional.empty(); } - /** - * Get the Arena ID - * @return arenaId - */ - public int getArenaId () { - return m_iStadiumId; - } - - /** - * Set the Arena ID - * @param arenaId the new value - */ - public void setArenaId (int arenaId) { - this.m_iStadiumId = arenaId; + public Optional getZukunftSitzplaetze() { + return isAusbau() ? Optional.of(getSitzplaetze() + getAusbauSitzplaetze()) : Optional.empty(); } - public int getHrfId() { - return hrfId; + public Optional getZukunftUeberdachteSitzplaetze() { + return isAusbau() ? Optional.of(getUeberdachteSitzplaetze() + getAusbauUeberdachteSitzplaetze()) : Optional.empty(); } - public void setHrfId(int hrfId) { - this.hrfId = hrfId; + public Optional getZukunftLogen() { + return isAusbau() ? Optional.of(getLogen() + getAusbauLogen()) : Optional.empty(); } } diff --git a/src/main/resources/gui/bilder/arena/basicseating.png b/src/main/resources/gui/bilder/arena/basicseating.png new file mode 100644 index 000000000..0c1332794 Binary files /dev/null and b/src/main/resources/gui/bilder/arena/basicseating.png differ diff --git a/src/main/resources/gui/bilder/arena/seatsunderroof.png b/src/main/resources/gui/bilder/arena/seatsunderroof.png new file mode 100644 index 000000000..8d2d146a3 Binary files /dev/null and b/src/main/resources/gui/bilder/arena/seatsunderroof.png differ diff --git a/src/main/resources/gui/bilder/arena/terraces.png b/src/main/resources/gui/bilder/arena/terraces.png new file mode 100644 index 000000000..2c48fe474 Binary files /dev/null and b/src/main/resources/gui/bilder/arena/terraces.png differ diff --git a/src/main/resources/gui/bilder/arena/vipboxes.png b/src/main/resources/gui/bilder/arena/vipboxes.png new file mode 100644 index 000000000..011636cc7 Binary files /dev/null and b/src/main/resources/gui/bilder/arena/vipboxes.png differ diff --git a/src/main/resources/language/English.properties b/src/main/resources/language/English.properties index aa72bb380..4e419b156 100644 --- a/src/main/resources/language/English.properties +++ b/src/main/resources/language/English.properties @@ -70,6 +70,7 @@ ls.core.preferences.misc.timezone=Time Zone # General labels ========================================================= ls.general_label.miscellaneous=miscellaneous +ls.general_label.not_available_abbreviation=n.a. #General button texts ls.button.add=Add @@ -2438,4 +2439,21 @@ ls.color.player_details_stars_fill=Player details stars colors=Colors ls.options.changed.save.question=Options were changed. Do you want to save them? -ls.options.warning=Options changed \ No newline at end of file +ls.options.warning=Options changed +# ArenaInfoPanel +ArenaInfoPanel.place_type=Place type +ArenaInfoPanel.places=Places +ArenaInfoPanel.rate_in_percent=Rate in % +ArenaInfoPanel.last_improvement=Last improvement: +ArenaInfoPanel.completion=Completion: +ArenaInfoPanel.available=Available: +ArenaInfoPanel.construction_in_progress=Construction in progress +ArenaInfoPanel.current=Current +ArenaInfoPanel.expansion=Expansion +ArenaInfoPanel.change_in_percent=Change in % +ArenaInfoPanel.future=Future +ArenaInfoPanel.finished_in_n_days_format=Finished in %s days. +ArenaInfoPanel.days_abbreviation=d +ArenaInfoPanel.hours_abbreviation=h +ArenaInfoPanel.minutes_abbreviation=m +ArenaInfoPanel.seconds_abbreviation=s diff --git a/src/main/resources/language/German.properties b/src/main/resources/language/German.properties index 0c2a958e2..70b31688d 100644 --- a/src/main/resources/language/German.properties +++ b/src/main/resources/language/German.properties @@ -2136,6 +2136,8 @@ ls.team.coachingskill.short = Trainer ls.module.statistics.club.assistant_trainers_level.short = Assistenten # General labels ========================================================= ls.general_label.miscellaneous = Verschiedenes +ls.general_label.not_available_abbreviation=n.v. + # youth module YouthPlayerOverview = Jugendspieler Übersicht YouthTrainingView = Jugend Training @@ -2259,4 +2261,21 @@ ls.player.lastlineup = Position letzter Einsatz ls.player.motherclub.name = Heimatverein ls.player.matchescurrentteam = Tore für aktuellen Verein ls.about.database.folder = Datenbank-Verzeichnis -ls.about.logs.folder = Logging-Verzeichnis \ No newline at end of file +ls.about.logs.folder = Logging-Verzeichnis +# ArenaInfoPanel +ArenaInfoPanel.place_type=Platztyp +ArenaInfoPanel.places=Plätze +ArenaInfoPanel.rate_in_percent=Anteil in % +ArenaInfoPanel.last_improvement=Letzter Umbau: +ArenaInfoPanel.completion=Fertigstellung: +ArenaInfoPanel.available=Verfügbar: +ArenaInfoPanel.construction_in_progress=im Umbau +ArenaInfoPanel.current=Aktuell +ArenaInfoPanel.expansion=Umbau +ArenaInfoPanel.change_in_percent=Veränderung in % +ArenaInfoPanel.future=Zukunft +ArenaInfoPanel.finished_in_n_days_format=Fertigstellung in %s Tagen. +ArenaInfoPanel.days_abbreviation=T +ArenaInfoPanel.hours_abbreviation=S +ArenaInfoPanel.minutes_abbreviation=M +ArenaInfoPanel.seconds_abbreviation=s diff --git a/src/main/resources/release_notes.md b/src/main/resources/release_notes.md index 216fa3ee0..7ef3bd7ce 100644 --- a/src/main/resources/release_notes.md +++ b/src/main/resources/release_notes.md @@ -7,6 +7,8 @@ ### Database * Increase match report column size (#2065) +* Table `STADION`: Added column `REBUILT_DATE` and + `EXPANSION_DATE` ([#2140](https://github.com/ho-dev/HattrickOrganizer/issues/2140)) ### Squad @@ -38,6 +40,8 @@ ### Misc +* Arena sizer: Added the Arena Info Panel (feature [#2140](https://github.com/ho-dev/HattrickOrganizer/issues/2140)) in + the tab with name of the stadium. * Fix #2137: Resolved an issue where the Download Dialog would not reappear after being closed with the 'X' button. The dialog will now correctly reappear when triggered again. diff --git a/src/test/java/core/file/xml/XMLArenaParserTest.java b/src/test/java/core/file/xml/XMLArenaParserTest.java index ba177d3f8..bf4ad206b 100644 --- a/src/test/java/core/file/xml/XMLArenaParserTest.java +++ b/src/test/java/core/file/xml/XMLArenaParserTest.java @@ -1,44 +1,54 @@ package core.file.xml; import core.util.ResourceUtils; +import hattrickdata.Arena; +import hattrickdata.CurrentCapacity; +import hattrickdata.ExpandedCapacity; +import hattrickdata.HattrickDataInfo; +import hattrickdata.League; +import hattrickdata.Region; +import hattrickdata.Team; +import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; import java.io.IOException; -import java.util.Map; +import java.time.LocalDateTime; import static org.assertj.core.api.Assertions.assertThat; class XMLArenaParserTest { + private static final String FILENAME = "arenadetails.xml"; + private static final String VERSION = "1.3"; + @Test void parseArenaFromString_noExpansion() throws IOException { // given final var content = ResourceUtils.getResourceFileAsString("arenaDetails_noExpansion.xml"); - // FileName, Version and UserID are currently not read - final var expected = Map.ofEntries( - Map.entry("FetchedDate", "2024-08-21 01:13:12"), - Map.entry("ArenaID", "2345678"), - Map.entry("ArenaName", "ArenaName"), - Map.entry("TeamID", "3456789"), - Map.entry("TeamName", "TeamName"), - Map.entry("LeagueID", "3"), - Map.entry("LeagueName", "LeagueName"), - Map.entry("RegionID", "227"), - Map.entry("RegionName", "RegionName"), - Map.entry("RebuiltDate", "2024-08-13 00:05:26"), - Map.entry("Terraces", "8000"), - Map.entry("Basic", "3000"), - Map.entry("Roof", "1792"), - Map.entry("VIP", "282"), - Map.entry("Total", "13074"), - Map.entry("isExpanding", "0"), - Map.entry("ExpansionDate", "0"), - Map.entry("ExTerraces", "0"), - Map.entry("ExBasic", "0"), - Map.entry("ExRoof", "0"), - Map.entry("ExVIP", "0"), - Map.entry("ExTotal", "0")); + final var expected = Pair.of( + HattrickDataInfo.builder() + .fileName(FILENAME) + .version(VERSION) + .userId(1234567) + .fetchedDate(LocalDateTime.of(2024, 8, 21, 1, 13, 12)) + .build(), + Arena.builder() + .id(2345678) + .name("ArenaName") + .team(Team.builder().id(3456789).name("TeamName").build()) + .league(League.builder().id(3).name("LeagueName").build()) + .region(Region.builder().id(227).name("RegionName").build()) + .currentCapacity(CurrentCapacity.builder() + .rebuildDate(LocalDateTime.of(2024, 8, 13, 0, 5, 26)) + .terraces(8000) + .basic(3000) + .roof(1792) + .vip(282) + .total(13074) + .build()) + .expandedCapacity(null) + .build()); // when final var result = XMLArenaParser.parseArenaFromString(content); @@ -52,34 +62,40 @@ void parseArenaFromString_withExpansion() throws IOException { // given final var content = ResourceUtils.getResourceFileAsString("arenaDetails_withExpansion.xml"); - // FileName, Version and UserID are currently not read - final var expected = Map.ofEntries( - Map.entry("FetchedDate", "2024-08-21 11:08:22"), - Map.entry("ArenaID", "2345678"), - Map.entry("ArenaName", "ArenaName"), - Map.entry("TeamID", "3456789"), - Map.entry("TeamName", "TeamName"), - Map.entry("LeagueID", "3"), - Map.entry("LeagueName", "LeagueName"), - Map.entry("RegionID", "227"), - Map.entry("RegionName", "RegionName"), - Map.entry("Terraces", "8000"), - Map.entry("Basic", "3000"), - Map.entry("Roof", "1792"), - Map.entry("VIP", "282"), - Map.entry("Total", "13074"), - Map.entry("isExpanding", "1"), - Map.entry("ExpansionDate", "2024-08-30 11:07:17"), - Map.entry("ExTerraces", "226"), - Map.entry("ExBasic", "234"), - Map.entry("ExRoof", "1138"), - Map.entry("ExVIP", "78"), - Map.entry("ExTotal", "1676")); - + final var expected = Pair.of( + HattrickDataInfo.builder() + .fileName(FILENAME) + .version(VERSION) + .userId(1234567) + .fetchedDate(LocalDateTime.of(2024, 8, 21, 11, 8, 22)) + .build(), + Arena.builder() + .id(2345678) + .name("ArenaName") + .team(Team.builder().id(3456789).name("TeamName").build()) + .league(League.builder().id(3).name("LeagueName").build()) + .region(Region.builder().id(227).name("RegionName").build()) + .currentCapacity(CurrentCapacity.builder() + .rebuildDate(null) + .terraces(8000) + .basic(3000) + .roof(1792) + .vip(282) + .total(13074) + .build()) + .expandedCapacity(ExpandedCapacity.builder() + .expansionDate(LocalDateTime.of(2024, 8, 30, 11, 7, 17)) + .terraces(226) + .basic(234) + .roof(1138) + .vip(78) + .total(1676) + .build()) + .build()); // when final var result = XMLArenaParser.parseArenaFromString(content); // then - assertThat(result).isEqualTo(expected).doesNotContainKey("RebuiltDate"); + assertThat(result).isEqualTo(expected); } } \ No newline at end of file diff --git a/src/test/java/tool/arenasizer/StadiumTest.java b/src/test/java/tool/arenasizer/StadiumTest.java new file mode 100644 index 000000000..1c4d4a7a6 --- /dev/null +++ b/src/test/java/tool/arenasizer/StadiumTest.java @@ -0,0 +1,172 @@ +package tool.arenasizer; + +import core.util.HODateTime; +import org.junit.jupiter.api.Test; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +class StadiumTest { + + private static final int TERRACES = 10000; + private static final int BASIC_SEATS = 5000; + private static final int SEATS_UNDER_ROOF = 30000; + private static final int VIP = 1000; + private static final int TOTAL = + TERRACES + BASIC_SEATS + SEATS_UNDER_ROOF + VIP; + + private static final int EXPANSION_TERRACES = 1000; + private static final int EXPANSION_BASIC_SEATS = 500; + private static final int EXPANSION_SEATS_UNDER_ROOF = 300; + private static final int EXPANSION_VIP = 100; + private static final int EXPANSION_TOTAL = + EXPANSION_TERRACES + EXPANSION_BASIC_SEATS + EXPANSION_SEATS_UNDER_ROOF + EXPANSION_VIP; + + private static final int FUTURE_TERRACES = TERRACES + EXPANSION_TERRACES; + private static final int FUTURE_BASIC_SEATS = BASIC_SEATS + EXPANSION_BASIC_SEATS; + private static final int FUTURE_SEATS_UNDER_ROOF = SEATS_UNDER_ROOF + EXPANSION_SEATS_UNDER_ROOF; + private static final int FUTURE_VIP = VIP + EXPANSION_VIP; + private static final int FUTURE_TOTAL = TOTAL + EXPANSION_TOTAL; + + private static final HODateTime REBUILT_DATE = HODateTime.fromHT("2024-08-25 22:00:00"); + private static final HODateTime EXPANSION_DATE = HODateTime.fromHT("2024-01-09 00:00:00"); + + private static Stadium createStadium(boolean expansion) { + Stadium stadium = new Stadium(); + stadium.setStehplaetze(TERRACES); + stadium.setSitzplaetze(BASIC_SEATS); + stadium.setUeberdachteSitzplaetze(SEATS_UNDER_ROOF); + stadium.setLogen(VIP); + + if (expansion) { + stadium.setAusbau(true); + stadium.setAusbauStehplaetze(EXPANSION_TERRACES); + stadium.setAusbauSitzplaetze(EXPANSION_BASIC_SEATS); + stadium.setAusbauUeberdachteSitzplaetze(EXPANSION_SEATS_UNDER_ROOF); + stadium.setAusbauLogen(EXPANSION_VIP); + stadium.setExpansionDate(EXPANSION_DATE); + } else { + stadium.setRebuiltDate(REBUILT_DATE); + } + + return stadium; + } + + @Test + void getGesamtgroesse() { + // given + final var stadium = createStadium(false); + + // when-then + assertThat(stadium.getGesamtgroesse()).isEqualTo(TOTAL); + } + + @Test + void getAusbauGesamtgroesse_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getAusbauGesamtgroesse()).isEqualTo(Optional.of(EXPANSION_TOTAL)); + } + + @Test + void getAusbauGesamtgroesse_ohneAusbau() { + // given + final var stadium = createStadium(false); + + // when-then + assertThat(stadium.getAusbauGesamtgroesse()).isEmpty(); + } + + @Test + void getZukunftGesamtgroesse_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getZukunftGesamtgroesse()).isEqualTo(Optional.of(FUTURE_TOTAL)); + } + + @Test + void getZukunftGesamtgroesse_ohneAusbau() { + // given + final var stadium = createStadium(false); + + // when-then + assertThat(stadium.getZukunftGesamtgroesse()).isEmpty(); + } + + @Test + void getZukunftStehplaetze() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getZukunftStehplaetze()).isEqualTo(Optional.of(FUTURE_TERRACES)); + } + + @Test + void getZukunftSitzplaetze_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getZukunftSitzplaetze()).isEqualTo(Optional.of(FUTURE_BASIC_SEATS)); + } + + @Test + void getZukunftUeberdachteSitzplaetze_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getZukunftUeberdachteSitzplaetze()).isEqualTo(Optional.of(FUTURE_SEATS_UNDER_ROOF)); + } + + @Test + void getZukunftLogen_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getZukunftLogen()).isEqualTo(Optional.of(FUTURE_VIP)); + } + + @Test + void getRebuiltDate_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getRebuiltDate()).isNull(); + } + + @Test + void getRebuiltDate_ohneAusbau() { + // given + final var stadium = createStadium(false); + + // when-then + assertThat(stadium.getRebuiltDate()).isEqualTo(REBUILT_DATE); + } + + @Test + void getExpansionDate_mitAusbau() { + // given + final var stadium = createStadium(true); + + // when-then + assertThat(stadium.getExpansionDate()).isEqualTo(EXPANSION_DATE); + } + + @Test + void getExpansionDate_ohneAusbau() { + // given + final var stadium = createStadium(false); + + // when-then + assertThat(stadium.getExpansionDate()).isNull(); + } +} \ No newline at end of file