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..dead6ec3a 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 -> HODateTime.toDbTimestamp(((Stadium) p).getExpansionDate())).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..6e5c341c0 100644 --- a/src/main/java/core/file/hrf/HRFStringBuilder.java +++ b/src/main/java/core/file/hrf/HRFStringBuilder.java @@ -12,15 +12,26 @@ import core.model.match.MatchTeamAttitude; import core.model.match.StyleOfPlay; import core.model.player.IMatchRoleID; +import core.util.HODateTime; 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.util.List; import java.util.Map; +import java.util.Optional; + +import static org.apache.commons.lang3.StringUtils.EMPTY; public class HRFStringBuilder { + + private static final String HO_DATE_TIME_NOT_SET = EMPTY; + private StringBuilder basicsStringBuilder; private StringBuilder clubStringBuilder; private StringBuilder economyStringBuilder; @@ -60,10 +71,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 +91,30 @@ 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(HO_DATE_TIME_NOT_SET)); + appendKeyValue(arenaStringBuilder, "ExpansionDate", Optional.ofNullable(arenaDataMap.get("ExpansionDate")).orElse(HO_DATE_TIME_NOT_SET)); + } + + /** + * 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(HODateTime::toHT).orElse(HO_DATE_TIME_NOT_SET)); + appendKeyValue(arenaStringBuilder, "ExpansionDate", arena.getExpandedCapacity().map(ExpandedCapacity::getExpansionDate).map(HODateTime::toHT).orElse(HO_DATE_TIME_NOT_SET)); } /** 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..91ef7a502 100644 --- a/src/main/java/core/file/xml/XMLArenaParser.java +++ b/src/main/java/core/file/xml/XMLArenaParser.java @@ -1,13 +1,17 @@ package core.file.xml; +import core.util.HODateTime; import core.util.HOLogger; +import hattrickdata.*; +import org.apache.commons.lang3.tuple.Pair; import org.w3c.dom.Document; import org.w3c.dom.Element; -import java.util.Map; - public class XMLArenaParser { + 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 +38,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(HODateTime.fromHT(XMLManager.getFirstChildNodeValue(element))); + + 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(HODateTime.fromHT(XMLManager.getFirstChildNodeValue(element))); } 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(HODateTime.fromHT(XMLManager.getFirstChildNodeValue(element))); 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/gui/LabelWithSignedNumber.java b/src/main/java/core/gui/LabelWithSignedNumber.java new file mode 100644 index 000000000..624a672be --- /dev/null +++ b/src/main/java/core/gui/LabelWithSignedNumber.java @@ -0,0 +1,87 @@ +package core.gui; + +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; +import static org.apache.commons.lang3.compare.ComparableUtils.is; + +public class LabelWithSignedNumber extends JLabel { + + private static final String PLUS_SIGN = "+"; + + 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) ? PLUS_SIGN : EMPTY; + return prefix + numberformat.format(number); + } + + private static String formatNumberWithSign(BigDecimal percentage) { + final String prefix = is(percentage).greaterThan(ZERO) ? PLUS_SIGN : 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_UP)); + } + + public static String percentageValueString(BigDecimal percentage) { + final BigDecimal percent = percentage + .multiply(BigDecimal.valueOf(100)) + .setScale(1, RoundingMode.HALF_UP); + return String.format("%s %%", percent); + } +} \ No newline at end of file diff --git a/src/main/java/core/net/OnlineWorker.java b/src/main/java/core/net/OnlineWorker.java index 417c317cf..7e4a128b8 100644 --- a/src/main/java/core/net/OnlineWorker.java +++ b/src/main/java/core/net/OnlineWorker.java @@ -797,8 +797,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().id()); } 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 a4f9dcbcd..a4950ce8e 100644 --- a/src/main/java/core/util/HODateTime.java +++ b/src/main/java/core/util/HODateTime.java @@ -2,11 +2,15 @@ import core.model.HOVerwaltung; import org.jetbrains.annotations.NotNull; + +import java.math.BigDecimal; +import java.math.RoundingMode; import java.sql.Timestamp; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.time.temporal.ChronoUnit; +import java.util.concurrent.TimeUnit; public class HODateTime implements Comparable { @@ -32,7 +36,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 +48,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 * @@ -383,6 +395,26 @@ public HTWeek toLocaleHTWeek() { return ret; } + public static BigDecimal daysFromNow(HODateTime to, int scale) { + return daysBetween(HODateTime.now(), to, scale); + } + + public static BigDecimal daysToNow(HODateTime from, int scale) { + return daysBetween(from, HODateTime.now(), scale); + } + + public static BigDecimal daysBetween(HODateTime from, HODateTime to, int scale) { + return BigDecimal.valueOf(between(from, to).toMillis()) + .divide(BigDecimal.valueOf(TimeUnit.DAYS.toMillis(1)), scale, RoundingMode.HALF_UP); + } + + public HODateTime nextLocalDay() { + final var localDate = getLocalDateTime().toLocalDate(); + final var nextDay = localDate.plusDays(1); + final var newInstant = Instant.from(nextDay.atStartOfDay(DEFAULT_TIMEZONE)); + return new HODateTime(newInstant); + } + public static class HODuration implements Comparable{ public int seasons; public int days; diff --git a/src/main/java/core/util/HumanDuration.java b/src/main/java/core/util/HumanDuration.java new file mode 100644 index 000000000..fc6e5b99e --- /dev/null +++ b/src/main/java/core/util/HumanDuration.java @@ -0,0 +1,67 @@ +package core.util; + +import core.model.TranslationFacility; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +import java.time.Duration; +import java.util.ArrayList; + +@Builder +@EqualsAndHashCode +@Getter +public class HumanDuration { + + private static final String DURATION_SUB_FORMAT = "%s%s"; + + private long days; + private long hours; + private long minutes; + private long seconds; + + public static HumanDuration of(Duration duration) { + return fromSeconds(duration.toSeconds()); + } + + public static HumanDuration fromSeconds(long duration) { + long seconds = duration; + final long days = seconds / 86400L; + seconds -= days * 86400L; + final long hours = seconds / 3600L; + seconds -= hours * 3600L; + final long minutes = seconds / 60L; + seconds -= minutes * 60L; + return HumanDuration.builder() + .days(days) + .hours(hours) + .minutes(minutes) + .seconds(seconds) + .build(); + } + + public String toHumanString() { + ArrayList strings = new ArrayList<>(); + if (days != 0) { + final var unit = getLanguageString("Duration.days_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, days, unit)); + } + if (hours != 0) { + final var unit = getLanguageString("Duration.hours_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, hours, unit)); + } + if (minutes != 0) { + final var unit = getLanguageString("Duration.minutes_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, minutes, unit)); + } + if (seconds != 0) { + final var unit = getLanguageString("Duration.seconds_abbreviation"); + strings.add(String.format(DURATION_SUB_FORMAT, seconds, unit)); + } + return String.join(", ", strings); + } + + private static String getLanguageString(String key) { + return TranslationFacility.tr(key); + } +} 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..ab449884b --- /dev/null +++ b/src/main/java/hattrickdata/CurrentCapacity.java @@ -0,0 +1,22 @@ +package hattrickdata; + +import core.util.HODateTime; +import lombok.*; +import lombok.experimental.SuperBuilder; + +import java.util.Optional; + +@Getter +@SuperBuilder() +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class CurrentCapacity extends Capacity { + + private HODateTime 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..9955ce7c2 --- /dev/null +++ b/src/main/java/hattrickdata/ExpandedCapacity.java @@ -0,0 +1,16 @@ +package hattrickdata; + +import core.util.HODateTime; +import lombok.*; +import lombok.experimental.SuperBuilder; + +@Getter +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ExpandedCapacity extends Capacity { + + private HODateTime expansionDate; +} diff --git a/src/main/java/hattrickdata/HattrickDataInfo.java b/src/main/java/hattrickdata/HattrickDataInfo.java new file mode 100644 index 000000000..5b5e437a3 --- /dev/null +++ b/src/main/java/hattrickdata/HattrickDataInfo.java @@ -0,0 +1,11 @@ +package hattrickdata; + +import core.util.HODateTime; +import lombok.Builder; + +@Builder +public record HattrickDataInfo(String fileName, + String version, + int userId, + HODateTime fetchedDate) { +} diff --git a/src/main/java/hattrickdata/League.java b/src/main/java/hattrickdata/League.java new file mode 100644 index 000000000..a44a65e06 --- /dev/null +++ b/src/main/java/hattrickdata/League.java @@ -0,0 +1,7 @@ +package hattrickdata; + +import lombok.Builder; + +@Builder +public record League(int id, String name) { +} diff --git a/src/main/java/hattrickdata/Region.java b/src/main/java/hattrickdata/Region.java new file mode 100644 index 000000000..39c8fe177 --- /dev/null +++ b/src/main/java/hattrickdata/Region.java @@ -0,0 +1,7 @@ +package hattrickdata; + +import lombok.Builder; + +@Builder +public record Region(int id, String name) { +} diff --git a/src/main/java/hattrickdata/Team.java b/src/main/java/hattrickdata/Team.java new file mode 100644 index 000000000..1e66d59ea --- /dev/null +++ b/src/main/java/hattrickdata/Team.java @@ -0,0 +1,7 @@ +package hattrickdata; + +import lombok.Builder; + +@Builder +public record Team(int id, 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..5271874d7 --- /dev/null +++ b/src/main/java/tool/arenasizer/ArenaInfoPanel.java @@ -0,0 +1,144 @@ +package tool.arenasizer; + +import core.model.HOVerwaltung; +import core.util.HODateTime; +import core.util.Helper; +import core.util.HumanDuration; + +import javax.swing.*; +import java.awt.*; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.Optional; + +import static core.gui.LabelWithSignedNumber.percentString; +import static org.apache.commons.lang3.StringUtils.EMPTY; + +public class ArenaInfoPanel extends JPanel { + + 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_UP) : null); + expandedCapacityPanel.labelPercentageBasicSeating.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauSitzplaetze()).divide(BigDecimal.valueOf(stadium.getSitzplaetze()), 3, RoundingMode.HALF_UP) : null); + expandedCapacityPanel.labelPercentageSeatsUnderRoof.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauUeberdachteSitzplaetze()).divide(BigDecimal.valueOf(stadium.getUeberdachteSitzplaetze()), 3, RoundingMode.HALF_UP) : null); + expandedCapacityPanel.labelPercentageVipBoxes.setPercentNumber(stadium.isAusbau() ? BigDecimal.valueOf(stadium.getAusbauLogen()).divide(BigDecimal.valueOf(stadium.getLogen()), 3, RoundingMode.HALF_UP) : null); + expandedCapacityPanel.labelPercentageTotal.setPercentNumber(stadium.getAusbauGesamtgroesse().map(expansionTotal -> BigDecimal.valueOf(expansionTotal).divide(BigDecimal.valueOf(stadium.getGesamtgroesse()), 3, RoundingMode.HALF_UP)).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(HODateTime::nextLocalDay) + .map(HODateTime::toLocaleDate) + .orElse(EMPTY)); + + setTranslation(); + } + + 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 boolean building = expansionDate.isAfter(HODateTime.now()); + if (building) { + final String text = toDurationString(expansionDate); + final String toolTipText = String.format( + getLanguageString("ArenaInfoPanel.finished_in_n_days_format"), + HODateTime.daysFromNow(expansionDate, 1)); + labelExpansionFinished.setText(text); + labelExpansionFinished.setToolTipText(toolTipText); + } else { + labelExpansionFinished.setText(String.format(getLanguageString("ArenaInfoPanel.built"))); + labelExpansionFinished.setToolTipText(null); + } + }, + () -> { + labelExpansionFinished.setText(EMPTY); + labelExpansionFinished.setToolTipText(null); + } + ); + } + + private static String getLanguageString(String key) { + return HOVerwaltung.instance().getLanguageString(key); + } + + private static String toDurationString(HODateTime hoDateTime) { + return HumanDuration.of(HODateTime.between(HODateTime.now(), hoDateTime)).toHumanString(); + } +} \ 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 411aaed07..6adba2cbe 100644 --- a/src/main/java/tool/arenasizer/ArenaSizerDialog.java +++ b/src/main/java/tool/arenasizer/ArenaSizerDialog.java @@ -5,6 +5,8 @@ import javax.swing.*; import java.awt.*; +import java.awt.BorderLayout; +import java.awt.FlowLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -13,9 +15,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(TranslationFacility.tr("ls.button.apply")); @@ -27,7 +29,6 @@ public ArenaSizerDialog(JFrame owner){ } private void initialize() { - setSize(900,430); setLayout(new BorderLayout()); setTitle(TranslationFacility.tr("ArenaSizer")); add(getToolbar(), BorderLayout.NORTH); @@ -41,6 +42,8 @@ private void initialize() { add(centerPanel,BorderLayout.CENTER); + pack(); + setLocationByPlatform(true); } private JPanel getToolbar(){ @@ -68,18 +71,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(){ @@ -87,30 +90,18 @@ private JTabbedPane getTabbedPane(){ tabbedPane = new JTabbedPane(); HOVerwaltung hoV = HOVerwaltung.instance(); tabbedPane.addTab(TranslationFacility.tr("Stadion"), getArenaPanel()); - tabbedPane.addTab(hoV.getModel().getStadium().getStadienname(), getInfoPanel()); + tabbedPane.addTab(hoV.getModel().getStadium().getStadienname(), getArenaInfoPanel()); tabbedPane.addTab(TranslationFacility.tr("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..60a0b9188 --- /dev/null +++ b/src/main/java/tool/arenasizer/CapacityPanel.java @@ -0,0 +1,184 @@ +package tool.arenasizer; + +import core.gui.LabelWithSignedNumber; +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 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(getLanguageString("ArenaInfoPanel.total_seats_and_sum_sign")); + } else { + labelTotal.setText(getLanguageString("ArenaInfoPanel.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/Stadium.java b/src/main/java/tool/arenasizer/Stadium.java index 12b08beac..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(String m_sStadienname) { - this.m_sStadienname = m_sStadienname; + public Stadium() { } - /** - * Getter for property m_sStadienname. - * - * @return Value of property m_sStadienname. - */ - public final 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..d8bfa3ede 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,24 @@ 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.built=Build! +Duration.days_abbreviation=d +Duration.hours_abbreviation=h +Duration.minutes_abbreviation=m +Duration.seconds_abbreviation=s +ArenaInfoPanel.sum_sign=∑ +ArenaInfoPanel.total_seats_and_sum_sign=Total Seats ∑ diff --git a/src/main/resources/language/German.properties b/src/main/resources/language/German.properties index 0c2a958e2..c67e35578 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,24 @@ 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.built=Ausgebaut! +Duration.days_abbreviation=T +Duration.hours_abbreviation=S +Duration.minutes_abbreviation=M +Duration.seconds_abbreviation=s +ArenaInfoPanel.sum_sign=∑ +ArenaInfoPanel.total_seats_and_sum_sign=Gesamtgrösse ∑ 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..884d79b32 100644 --- a/src/test/java/core/file/xml/XMLArenaParserTest.java +++ b/src/test/java/core/file/xml/XMLArenaParserTest.java @@ -1,44 +1,48 @@ package core.file.xml; +import core.util.HODateTime; import core.util.ResourceUtils; +import hattrickdata.*; +import org.apache.commons.lang3.tuple.Pair; import org.junit.jupiter.api.Test; import java.io.IOException; -import java.util.Map; 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(HODateTime.fromHT("2024-08-21 01: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(HODateTime.fromHT("2024-08-13 00:05:26")) + .terraces(8000) + .basic(3000) + .roof(1792) + .vip(282) + .total(13074) + .build()) + .expandedCapacity(null) + .build()); // when final var result = XMLArenaParser.parseArenaFromString(content); @@ -52,34 +56,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(HODateTime.fromHT("2024-08-21 11:08: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(HODateTime.fromHT("2024-08-30 11:07: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/core/util/HODateTimeTest.java b/src/test/java/core/util/HODateTimeTest.java index a522f4def..11c2742e6 100644 --- a/src/test/java/core/util/HODateTimeTest.java +++ b/src/test/java/core/util/HODateTimeTest.java @@ -5,17 +5,24 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; +import static java.math.BigDecimal.ONE; +import static java.math.BigDecimal.ZERO; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.assertj.core.data.Offset.offset; +import static org.junit.jupiter.params.provider.Arguments.of; class HODateTimeTest { @@ -129,6 +136,169 @@ private static HODateTime generate(int i, LocalDateTime localDateTime) { return fromLocalDateTime(localDateTime.plusDays(i)); } + @Test + void daysFromNow_future() { + // given + final var future = HODateTime.now().plus(1, ChronoUnit.DAYS); + + // when + final var result = HODateTime.daysFromNow(future, 1); + + // then + assertThat(result).isGreaterThanOrEqualTo(ONE.setScale(1, RoundingMode.HALF_DOWN)); + } + + @Test + void daysFromNow_past_approx() { + // given + final var past = HODateTime.now().minus(43200, ChronoUnit.SECONDS); + + // when + final var result = HODateTime.daysFromNow(past, 5); + + // then + assertThat(result).isLessThan(BigDecimal.valueOf(-0.49999).setScale(5, RoundingMode.HALF_DOWN)); + } + + @Test + void daysToNow_future() { + // given + final var future = HODateTime.now().plus(1, ChronoUnit.DAYS); + + // when + final var result = HODateTime.daysToNow(future, 1); + + // then + assertThat(result).isLessThanOrEqualTo(ONE.negate().setScale(1, RoundingMode.HALF_DOWN)); + } + + @Test + void daysToNow_past_approx() { + // given + final var past = HODateTime.now().minus(43200, ChronoUnit.SECONDS); + + // when + final var result = HODateTime.daysToNow(past, 5); + + // then + assertThat(result).isGreaterThan(BigDecimal.valueOf(0.49999).setScale(5, RoundingMode.HALF_DOWN)); + } + + @Test + void daysBetween_with_now_results_zero() { + // given + final var now = HODateTime.now(); + + // when + final var result = HODateTime.daysBetween(now, now, 1); + + // then + assertThat(result).isEqualByComparingTo(ZERO); + } + + @Test + void calculateDistanceInDays_toOneDayInFuture_results_one() { + // given + final var from = HODateTime.now(); + final var to = from.plus(1, ChronoUnit.DAYS); + + // when + final var result = HODateTime.daysBetween(from, to, 1); + + // then + assertThat(result).isEqualTo(ONE.setScale(1, RoundingMode.HALF_DOWN)); + } + + @Test + void calculateDistanceInDays_toOneDayInPast_results_minusOne() { + // given + final var from = HODateTime.now(); + final var to = from.minus(1, ChronoUnit.DAYS); + + // when + final var result = HODateTime.daysBetween(from, to, 1); + + // then + assertThat(result).isEqualTo(ONE.negate().setScale(1, RoundingMode.HALF_UP)); + } + + @Test + void calculateDistanceInDays_with_one_day_in_past_results_one() { + // given + final var from = HODateTime.now(); + final var to = from.plus(46530, ChronoUnit.SECONDS); + + // when + final var result = HODateTime.daysBetween(from, to, 1); + + // then + assertThat(result).isEqualTo(BigDecimal.valueOf(0.5).setScale(1, RoundingMode.HALF_UP)); + } + + @Test + void calculateDistanceInDays_with_82080_secs_in_future_results_one() { + // given + final var from = HODateTime.now(); + final var to = from.plus(82080, ChronoUnit.SECONDS); + + // when + final var result = HODateTime.daysBetween(from, to, 1); + + // then + assertThat(result).isEqualTo(ONE.setScale(1, RoundingMode.HALF_UP)); + } + + @Test + void calculateDistanceInDays_with_81216_secs_in_future_results_zero_point_nine() { + // given + final var from = HODateTime.now(); + final var to = from.plus(81216, ChronoUnit.SECONDS); + + // when + final var result = HODateTime.daysBetween(from, to, 1); + + // then + assertThat(result).isEqualTo(BigDecimal.valueOf(0.9).setScale(1, RoundingMode.HALF_UP)); + } + + static Stream nextLocalDay() { + return Stream.of( + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 29, 23, 59, 59)), LocalDate.of(2024, 8, 30).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 0, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 1, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 2, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 3, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 4, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 5, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 6, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 7, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 8, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 9, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 10, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 11, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 12, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 13, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 14, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 15, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 16, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 17, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 18, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 19, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 20, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 21, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 22, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 23, 0, 0)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 30, 23, 59, 59)), LocalDate.of(2024, 8, 31).atStartOfDay()), + of(fromLocalDateTime(LocalDateTime.of(2024, 8, 31, 0, 0, 0)), LocalDate.of(2024, 9, 1).atStartOfDay()) + ); + } + + @ParameterizedTest + @MethodSource + void nextLocalDay(HODateTime hoDateTime, LocalDateTime expected) { + assertThat(hoDateTime.nextLocalDay().getLocalDateTime()).isEqualTo(expected); + } + private static HODateTime fromLocalDateTime(LocalDateTime localDateTime) { final var zonedDateTime = ZonedDateTime.of(localDateTime, ZoneId.systemDefault()); zonedDateTime.withZoneSameInstant(HODateTime.DEFAULT_TIMEZONE); diff --git a/src/test/java/core/util/HumanDurationTest.java b/src/test/java/core/util/HumanDurationTest.java new file mode 100644 index 000000000..eeb0bc601 --- /dev/null +++ b/src/test/java/core/util/HumanDurationTest.java @@ -0,0 +1,74 @@ +package core.util; + +import core.model.TranslationFacility; +import core.model.Translator; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.time.Duration; +import java.util.stream.Stream; + +import static org.apache.commons.lang3.StringUtils.EMPTY; +import static org.assertj.core.api.Assertions.assertThat; + +class HumanDurationTest { + + private static Stream secondsAndHumanDurations() { + return Stream.of( + Arguments.of(3600L * 2L + 60L * 3L + 4L, HumanDuration.builder().hours(2).minutes(3).seconds(4).build()), + Arguments.of(86400L + 60L * 3L + 4L, HumanDuration.builder().days(1).minutes(3).seconds(4).build()), + Arguments.of(86400L + 3600L * 2L + 4L, HumanDuration.builder().days(1).hours(2).seconds(4).build()), + Arguments.of(86400L + 3600L * 2L + 60L * 3L, HumanDuration.builder().days(1).hours(2).minutes(3).build()), + Arguments.of(86400L + 3600L * 2L + 60L * 3L + 4L, HumanDuration.builder().days(1).hours(2).minutes(3).seconds(4).build()), + Arguments.of(0L, HumanDuration.builder().build()) + ); + } + + private static Stream humanDurationToString() { + return Stream.of( + Arguments.of(HumanDuration.builder().hours(2).minutes(3).seconds(4).build(), "2h, 3m, 4s"), + Arguments.of(HumanDuration.builder().days(1).minutes(3).seconds(4).build(), "1d, 3m, 4s"), + Arguments.of(HumanDuration.builder().days(1).hours(2).seconds(4).build(), "1d, 2h, 4s"), + Arguments.of(HumanDuration.builder().days(1).hours(2).minutes(3).build(), "1d, 2h, 3m"), + Arguments.of(HumanDuration.builder().days(1).hours(2).minutes(3).seconds(4).build(), "1d, 2h, 3m, 4s"), + Arguments.of(HumanDuration.builder().build(), EMPTY) + ); + } + + @ParameterizedTest + @MethodSource("secondsAndHumanDurations") + void of(long durationInSeconds, HumanDuration expected) { + // given + final Duration duration = Duration.ofSeconds(durationInSeconds); + + // when + final HumanDuration result = HumanDuration.of(duration); + + // then + assertThat(result).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("secondsAndHumanDurations") + void fromSeconds(long durationInSeconds, HumanDuration expected) { + // when + final HumanDuration result = HumanDuration.fromSeconds(durationInSeconds); + + // then + assertThat(result).isEqualTo(expected); + } + + @ParameterizedTest + @MethodSource("humanDurationToString") + void toHumanString(HumanDuration humanDuration, String expected) { + // given + TranslationFacility.setTranslator(Translator.load(Translator.LANGUAGE_DEFAULT)); + + // when + final var result = humanDuration.toHumanString(); + + // then + 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