From 604d2384cf198d1c9541c4dafd5e8a6a04f652b7 Mon Sep 17 00:00:00 2001 From: Robert Vokac Date: Sat, 23 Mar 2024 16:31:36 +0100 Subject: [PATCH] ProgressWeather was finished --- .../org/nanoboot/utils/timecalc/app/Main.java | 8 + .../utils/timecalc/swing/common/Widget.java | 14 +- .../timecalc/swing/common/WidgetMenu.java | 2 +- .../timecalc/swing/progress/AnalogClock.java | 5 +- .../swing/progress/ProgressWeather.java | 164 ------ .../swing/progress/WeatherForecast.java | 136 ----- .../swing/progress/weather/Cloudiness.java | 43 ++ .../progress/weather/ProgressWeather.java | 296 ++++++++++ .../progress/weather/WeatherForecast.java | 555 ++++++++++++++++++ .../timecalc/swing/windows/MainWindow.java | 2 +- .../timecalc/utils/common/FileConstants.java | 2 +- .../timecalc/utils/common/NumberFormats.java | 2 + .../utils/timecalc/utils/common/Utils.java | 1 + 13 files changed, 923 insertions(+), 307 deletions(-) delete mode 100644 modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/ProgressWeather.java delete mode 100644 modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/WeatherForecast.java create mode 100644 modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/Cloudiness.java create mode 100644 modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/ProgressWeather.java create mode 100644 modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/WeatherForecast.java diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/app/Main.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/app/Main.java index a1df8ed..7082a32 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/app/Main.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/app/Main.java @@ -1,6 +1,8 @@ package org.nanoboot.utils.timecalc.app; +import java.io.File; import java.io.IOException; +import org.nanoboot.utils.timecalc.utils.common.FileConstants; /** * @author Robert Vokac @@ -9,6 +11,12 @@ import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { +// for(File f:FileConstants.CLIMATE_TXT.getParentFile().listFiles()) { +// if(f.getName().contains("weather")) { +// System.out.println("Going to delete: " + f.getAbsolutePath()); +// f.delete(); +// } +// } TimeCalcApp timeCalcApp = new TimeCalcApp(); timeCalcApp.start(args); } diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java index 6068b93..d918420 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/Widget.java @@ -31,6 +31,7 @@ import java.awt.event.MouseMotionListener; import java.util.List; import java.util.Locale; import java.util.function.Consumer; +import javax.swing.JMenuItem; /** * @author Robert Vokac @@ -170,7 +171,7 @@ public class Widget extends JPanel implements private void showPopup(MouseEvent e) { if(widgetMenu == null) { widgetMenu = new WidgetMenu(widget, createRefreshConsumer()); - List additionalMenus = createAdditionalMenus(); + List additionalMenus = createAdditionalMenus(); if(additionalMenus != null) { additionalMenus.forEach(m-> widgetMenu.add(m)); } @@ -191,7 +192,7 @@ public class Widget extends JPanel implements protected Consumer createRefreshConsumer() { return null; } - protected List createAdditionalMenus() { + protected List createAdditionalMenus() { return null; } @@ -242,12 +243,21 @@ public class Widget extends JPanel implements if (visibleProperty.isDisabled() || hidden) { if(hidden) { + if(this.smileyIcon != null) { + this.remove(this.smileyIcon); + this.smileyIcon = null; + } + if(this.smileyIcon2 != null) { + this.remove(this.smileyIcon2); + this.smileyIcon2 = null; + } if (mouseOver) { Color currentColor = brush.getColor(); brush.setColor(VERY_LIGHT_GRAY); brush.fillRect(1, 1, getWidth() - 2, getHeight() - 2); brush.setColor(currentColor); } + brush.drawString("Show", (int) (getWidth() * 0.5 - 10), (int) (getHeight() * 0.5 - 10)); } //nothing to do return; diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java index bf51c56..47db0d2 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/common/WidgetMenu.java @@ -4,7 +4,7 @@ import org.nanoboot.utils.timecalc.app.TimeCalcException; import org.nanoboot.utils.timecalc.entity.WidgetType; import org.nanoboot.utils.timecalc.swing.progress.AnalogClock; import org.nanoboot.utils.timecalc.swing.progress.Battery; -import org.nanoboot.utils.timecalc.swing.progress.ProgressWeather; +import org.nanoboot.utils.timecalc.swing.progress.weather.ProgressWeather; import javax.swing.JMenu; import javax.swing.JMenuItem; diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java index 268c79a..801acdd 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/AnalogClock.java @@ -27,6 +27,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; import java.util.function.Consumer; +import javax.swing.JMenuItem; //https://kodejava.org/how-do-i-write-a-simple-analog-clock-using-java-2d/ public class AnalogClock extends Widget { @@ -107,7 +108,7 @@ public class AnalogClock extends Widget { private TMenuItem secondHandMenuItem; private TMenuItem minuteHandMenuItem; private TMenuItem hourHandMenuItem; - private List menuItems = null; + private List menuItems = null; public AnalogClock() { typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT)); @@ -421,7 +422,7 @@ public class AnalogClock extends Widget { } @Override - public List createAdditionalMenus() { + public List createAdditionalMenus() { if(menuItems == null) { menuItems = new ArrayList<>(); JMenu hands = new JMenu("Hands"); diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/ProgressWeather.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/ProgressWeather.java deleted file mode 100644 index 920b1b5..0000000 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/ProgressWeather.java +++ /dev/null @@ -1,164 +0,0 @@ -package org.nanoboot.utils.timecalc.swing.progress; - -import org.nanoboot.utils.timecalc.app.GetProperty; -import org.nanoboot.utils.timecalc.entity.Visibility; -import org.nanoboot.utils.timecalc.entity.WidgetType; -import org.nanoboot.utils.timecalc.swing.common.SwingUtils; -import org.nanoboot.utils.timecalc.swing.common.Widget; -import org.nanoboot.utils.timecalc.swing.windows.MainWindow; -import org.nanoboot.utils.timecalc.utils.common.DateFormats; -import org.nanoboot.utils.timecalc.utils.common.FileConstants; -import org.nanoboot.utils.timecalc.utils.common.TTime; -import org.nanoboot.utils.timecalc.utils.common.Utils; -import org.nanoboot.utils.timecalc.utils.property.Property; - -import javax.swing.Timer; -import java.awt.Color; -import java.awt.Font; -import java.awt.Graphics; -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.stream.Collectors; - -/** - * @author Robert Vokac - * @since 21.02.2024 - */ -public class ProgressWeather extends Widget implements GetProperty { - - private final Time time; - - public ProgressWeather(Time time) { - this.time = time; - setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11)); - - setFocusable(false); - setForeground(Color.GRAY); - setBackground(MainWindow.BACKGROUND_COLOR); - this.typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT)); - - new Timer(100, e -> { - Visibility visibility - = Visibility.valueOf(visibilityProperty.getValue()); - setForeground( - visibility.isStronglyColored() - || mouseOver - ? Color.BLACK : Color.LIGHT_GRAY); - }).start(); - - } - - private static Map> forecastsForYears = new HashMap<>(); - @Override - public void paintWidget(Graphics brush) { - - Visibility visibility - = Visibility.valueOf(visibilityProperty.getValue()); - - brush.setColor(visibility.isStronglyColored() ? Color.BLUE - : visibility.isWeaklyColored() ? Color.GRAY - : Color.LIGHT_GRAY); - brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT); - int year = time.yearProperty.getValue(); - if(!forecastsForYears.containsKey(year)) { - File weatherFile = new File(FileConstants.WEATHER_TXT.getParentFile(), - String.valueOf(year) + '_' + FileConstants.WEATHER_TXT.getName()); - System.out.println(weatherFile.getAbsolutePath()); - if (!weatherFile.exists()) { - List forecasts = WeatherForecast.createForecast(); - Utils.writeTextToFile(weatherFile, - forecasts.stream().map(w -> w.toCsv()).collect( - Collectors.joining("\n"))); - } - List forecasts = new ArrayList<>(); - try { - Arrays.stream(Utils.readTextFromFile(weatherFile).split("\n")).filter(line -> !line.isEmpty()).forEach(line -> forecasts.add(new WeatherForecast().fromCsv(line))); - } catch (IOException e) { - System.out.println("Loading file failed: " + weatherFile + " " + e - .getMessage()); - e.printStackTrace(); - return; - } - forecastsForYears.put(year, forecasts); - } - List forecasts = forecastsForYears.get(year); - - - int currentSecond = time.secondProperty.getValue(); - Calendar cal = time.asCalendar(); - int add = (currentSecond % 14); - switch (add) { - case 0: - add = 0; break; - case 1: - add = 0; break; - case 2: - add = 1; break; - case 3: - add = 1; break; - case 4: - add = 2; break; - case 5: - add = 2; break; - case 6: - add = 3; break; - case 7: - add = 3; break; - case 8: - add = 4; break; - case 9: - add = 4; break; - case 10: - add = 5; break; - case 11: - add = 5; break; - case 12: - add = 6; break; - case 13: - add = 6; break; - default: - add = 7; break; - - } - - add = add / 2; - if (add > 0) { - cal.add(Calendar.DAY_OF_MONTH, add); - } - int currentDayOfWeek = time.dayOfWeekProperty.getValue(); - int forecastDayOfWeek = currentDayOfWeek + add; -// String dayOfWeekAsString = DayOfWeekTC.forNumber(forecastDayOfWeek).name(); -// dayOfWeekAsString = dayOfWeekAsString.substring(0,1).toUpperCase(Locale.ROOT) + dayOfWeekAsString.substring(1, dayOfWeekAsString.length()); - WeatherForecast weatherForecast = forecasts.stream().filter(f -> f.getDate().equals(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()))).findFirst().orElse(new WeatherForecast()); - - int rowHeight = 25; - int row = 10; - brush.drawString(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()), SwingUtils.MARGIN, SwingUtils.MARGIN + row); - row = row + rowHeight; - brush.drawString(DateFormats.DATE_TIME_FORMATTER_DAY_OF_WEEK.format(cal.getTime()), SwingUtils.MARGIN, SwingUtils.MARGIN + row); - row = row + rowHeight; - brush.drawString(weatherForecast.asPrettyString(new TTime(time.hourProperty.getValue(), - time.minuteProperty.getValue(), - time.secondProperty.getValue(), - time.millisecondProperty.getValue()).toTotalMilliseconds() / 1000d / 60d / 60d), SwingUtils.MARGIN, SwingUtils.MARGIN + row); - row = row + rowHeight; - - } - - @Override - public Property getVisibilityProperty() { - return visibilityProperty; - } - - @Override - public Property getVisibilitySupportedColoredProperty() { - return visibilitySupportedColoredProperty; - } -} diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/WeatherForecast.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/WeatherForecast.java deleted file mode 100644 index 7607735..0000000 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/WeatherForecast.java +++ /dev/null @@ -1,136 +0,0 @@ -package org.nanoboot.utils.timecalc.swing.progress; - -import lombok.Getter; -import org.nanoboot.utils.timecalc.utils.common.FileConstants; -import org.nanoboot.utils.timecalc.utils.common.NumberFormats; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; - -/** - * @author pc00289 - * @since 22.03.2024 - */ -@Getter -public class WeatherForecast { -//01:00-4:00 - minimum -//13:00-16:00 - maximum -//20240101.minTempC= -//20240101.maxTempC= -// 20240101.minTempTime= -//20240101.maxTempTime= -//20240101.wind={m/s} -//20240101.cloudiness={0.0 - 1.0} -//20240101.thunder={0.0 - 1.0} -//20240101.rain={mm} -//20240101.snow={mm} -//#20240101.sunrise=7:53 -//#20240101.sunset=16:02 - private String date; - private double minimumCelsius; - private double maximumCelsius; - private double minimumCelsiusTime; - private double maximumCelsiusTime; - private double wind; - private double cloudiness; - private double thunder; - private double rain; - private double snow; - public static List createForecast() { - List list = new ArrayList<>(); - - Properties climateProperties = new Properties(); - if(FileConstants.CLIMATE_TXT.exists()) { - try { - climateProperties.load(new FileInputStream(FileConstants.CLIMATE_TXT)); - } catch (IOException e) { - e.printStackTrace(); - System.out.println("Loading file failed: " + FileConstants.WEATHER_TXT + " " + e.getMessage()); - return list; - } - } else { - System.out.println("File does not exist: " + FileConstants.CLIMATE_TXT); - return list; - } - - double min1= Double.valueOf(climateProperties.getProperty("1.min", "0")); - double min2= Double.valueOf(climateProperties.getProperty("2.min", "1")); - double min3= Double.valueOf(climateProperties.getProperty("3.min", "2")); - double min4= Double.valueOf(climateProperties.getProperty("4.min", "4")); - double min5= Double.valueOf(climateProperties.getProperty("5.min", "6")); - double min6= Double.valueOf(climateProperties.getProperty("6.min", "8")); - double min7= Double.valueOf(climateProperties.getProperty("7.min", "8")); - double min8= Double.valueOf(climateProperties.getProperty("8.min", "6")); - double min9= Double.valueOf(climateProperties.getProperty("9.min", "4")); - double min10= Double.valueOf(climateProperties.getProperty("10.min", "2")); - double min11= Double.valueOf(climateProperties.getProperty("11.min", "1")); - double min12= Double.valueOf(climateProperties.getProperty("12.min", "0")); - - return list; - } - public String toCsv() { - StringBuilder sb = new StringBuilder(); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(minimumCelsius)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(maximumCelsius)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(minimumCelsiusTime)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(maximumCelsiusTime)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(wind)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(cloudiness)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(thunder)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(rain)).append('\t'); - sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(snow)); - return sb.toString(); - } - public WeatherForecast fromCsv(String csv) { - String[] values = csv.split("\t"); - - int i = 0; - minimumCelsius = Double.valueOf(values[i++]); - maximumCelsius = Double.valueOf(values[i++]); - minimumCelsiusTime = Double.valueOf(values[i++]); - maximumCelsiusTime = Double.valueOf(values[i++]); - wind = Double.valueOf(values[i++]); - cloudiness = Double.valueOf(values[i++]); - thunder = Double.valueOf(values[i++]); - rain = Double.valueOf(values[i++]); - snow = Double.valueOf(values[i++]); - - return this; - } - public String asPrettyString(double forHour) { - return "14°C, wind 7/s, rain 2mm, cloudy"; - } -} - -/* -climate.txt -1.max=18.8 -2.max=22.0 -3.max=26.2 -4.max=31.8 -5.max=35.0 -6.max=38.9 -7.max=40.2 -8.max=40.4 -9.max=37.4 -10.max=30,3 -11.max=24,0 -12.max=19.8 -1.min=-36.2 -2.min=-42.2 -3.min=-32.0 -4.min=-22.0 -5.min=-13.1 -6.min=-8.3 -7.min=-6.9 -8.min=-5.0 -9.min=-10.5 -10.min=-19.9 -11.min=-25.4 -12.min=-34.0 - */ diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/Cloudiness.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/Cloudiness.java new file mode 100644 index 0000000..8c4a797 --- /dev/null +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/Cloudiness.java @@ -0,0 +1,43 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template + */ +package org.nanoboot.utils.timecalc.swing.progress.weather; + +import lombok.Getter; +import org.nanoboot.utils.timecalc.utils.common.NumberFormats; + +/** + * + * @author robertvokac + */ +public enum Cloudiness { + CLOUDY("Cloudy", 7d/8d), + MOSTLY_CLOUDY("Mostly cloudy", 5d/8d), + PARTLY_CLOUDY("Partly cloudy+sunny", 3d/8d), + MOSTLY_SUNNY("Mostly clear+sunny", 1d/8d), + SUNNY("Clear/Sunny", 0/8); + @Getter + private String description; + private double ifMoreOrEqual; + Cloudiness(String description, double ifMoreOrEqual) { + this.description = description; + this.ifMoreOrEqual = ifMoreOrEqual; + } + public static Cloudiness forValue(double value) { + for (Cloudiness c : Cloudiness.values()) { + if (value >= c.ifMoreOrEqual) { + return c; + } + } + throw new IllegalStateException("Unsupported value: " + NumberFormats.FORMATTER_TWO_DECIMAL_PLACES.format(value)); + } + +// Cloudy: 90-100% sky covered +// Mostly cloudy: 70-80% sky covered +// Partly Cloudy/Partly Sunny: 30-60% sky covered +// Mostly Clear/Mostly Sunny: 10-30% sky covered +// Clear/Sunny: 0-10% sky covered + + +} diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/ProgressWeather.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/ProgressWeather.java new file mode 100644 index 0000000..abece03 --- /dev/null +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/ProgressWeather.java @@ -0,0 +1,296 @@ +package org.nanoboot.utils.timecalc.swing.progress.weather; + +import org.nanoboot.utils.timecalc.app.GetProperty; +import org.nanoboot.utils.timecalc.entity.Visibility; +import org.nanoboot.utils.timecalc.entity.WidgetType; +import org.nanoboot.utils.timecalc.swing.common.SwingUtils; +import org.nanoboot.utils.timecalc.swing.common.Widget; +import org.nanoboot.utils.timecalc.swing.windows.MainWindow; +import org.nanoboot.utils.timecalc.utils.common.DateFormats; +import org.nanoboot.utils.timecalc.utils.common.FileConstants; +import org.nanoboot.utils.timecalc.utils.common.TTime; +import org.nanoboot.utils.timecalc.utils.common.Utils; +import org.nanoboot.utils.timecalc.utils.property.Property; + +import javax.swing.Timer; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.stream.Collectors; +import javax.swing.JMenuItem; +import org.nanoboot.utils.timecalc.swing.progress.Time; +import org.nanoboot.utils.timecalc.utils.common.NumberFormats; + +/** + * @author Robert Vokac + * @since 21.02.2024 + */ +public class ProgressWeather extends Widget implements GetProperty { + + private final Time time; + private int lastAdd = 0; + + private List menuItems = null; + private boolean information; + + public ProgressWeather(Time time) { + this.time = time; + setFont(new Font(Font.MONOSPACED, Font.PLAIN, 11)); + + setFocusable(false); + setForeground(Color.GRAY); + setBackground(MainWindow.BACKGROUND_COLOR); + this.typeProperty.setValue(WidgetType.DAY.name().toLowerCase(Locale.ROOT)); + + new Timer(100, e -> { + Visibility visibility + = Visibility.valueOf(visibilityProperty.getValue()); + setForeground( + visibility.isStronglyColored() + || mouseOver + ? Color.BLACK : Color.LIGHT_GRAY); + }).start(); + + } + + private static Map> forecastsForYears = new HashMap<>(); + + @Override + public void paintWidget(Graphics brush) { + + Visibility visibility + = Visibility.valueOf(visibilityProperty.getValue()); + + brush.setColor(visibility.isStronglyColored() ? Color.BLUE + : visibility.isWeaklyColored() ? Color.GRAY + : Color.LIGHT_GRAY); + brush.setFont(SwingUtils.MEDIUM_MONOSPACE_FONT); + int year = time.yearProperty.getValue(); + if (!forecastsForYears.containsKey(year)) { + File weatherFile = new File(FileConstants.WEATHER_CSV.getParentFile(), + String.valueOf(year) + '_' + FileConstants.WEATHER_CSV.getName()); + System.out.println(weatherFile.getAbsolutePath()); + if (!weatherFile.exists()) { + List forecasts = WeatherForecast.createForecast(year); + + Utils.writeTextToFile( + weatherFile, + "Date\tMinC\tMaxC\tMinTime\tMaxTime\tWind\tCloudiness\tThunder\tRain\tSnow\tHumidity\tHearOrColdWave\tStartC\tEndC\n" + + forecasts.stream().map(w -> w.toCsv()).collect( + Collectors.joining("\n"))); + } + List forecasts = new ArrayList<>(); + try { + Arrays.stream(Utils.readTextFromFile(weatherFile).split("\n")) + .filter(line -> !line.startsWith("Date")) + .filter(line -> !line.isEmpty()).forEach(line -> forecasts.add(new WeatherForecast().fromCsv(line))); + } catch (IOException e) { + System.out.println("Loading file failed: " + weatherFile + " " + e + .getMessage()); + e.printStackTrace(); + return; + } + forecastsForYears.put(year, forecasts); + + } + List forecasts = forecastsForYears.get(year); + +// if(!w){ +// w= true; +// List temperature = new ArrayList<>(); +// forecasts.stream().forEach(f -> { +// +// for (int hour = 0; hour < 24; hour++) { +// //for (int minute = 0; minute < 60; minute = minute + 30) { +// int minute = 0; +// double forHour = ((double)(new TTime(hour, minute).toTotalMilliseconds() / 1000d / 60d / 60d)); +// temperature.add(f.getCelsiusForHour(forHour)); +// //} +// } +// }); +// StringBuilder sb = new StringBuilder(); +// temperature.stream().forEach(t -> sb.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(t)).append("\n")); +// Utils.writeTextToFile(new File("t.csv"), sb.toString()); +// } + int currentSecond = time.secondProperty.getValue(); + Calendar cal = time.asCalendar(); + int add = (currentSecond % 21); + if (paused) { + add = lastAdd; + } else { + if (add < 3) { + add = 0; + } else if (add < 6) { + add = 1; + } else if (add < 9) { + add = 2; + } else if (add < 12) { + add = 3; + } else if (add < 15) { + add = 4; + } else if (add < 18) { + add = 5; + } else if (add < 21) { + add = 6; + } + this.lastAdd = add; + } + if (add > 0) { + cal.add(Calendar.DAY_OF_MONTH, add); + } + int currentDayOfWeek = time.dayOfWeekProperty.getValue(); + int forecastDayOfWeek = currentDayOfWeek + add; +// String dayOfWeekAsString = DayOfWeekTC.forNumber(forecastDayOfWeek).name(); +// dayOfWeekAsString = dayOfWeekAsString.substring(0,1).toUpperCase(Locale.ROOT) + dayOfWeekAsString.substring(1, dayOfWeekAsString.length()); + WeatherForecast wf = forecasts.stream().filter(f -> f.getDate().equals(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()))).findFirst().orElse(new WeatherForecast()); + + if(information) { + information = false; + StringBuilder sb = new StringBuilder(); + sb.append("Date: ").append(wf.getDate()).append("\n"); + sb + .append("Start: ") + .append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getStartCelsius())) + .append(" °C at 00:00") + .append("\n"); + sb + .append("Minimum: ") + .append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getMinimumCelsius())) + .append(" °C at ").append(TTime.ofMilliseconds((int) (wf.getMinimumCelsiusTime() * 1000d * 60d * 60d)).toString().substring(0, 5)) + .append("\n"); + sb + .append("Maximum: ") + .append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getMaximumCelsius())) + .append(" °C at ").append(TTime.ofMilliseconds((int) (wf.getMinimumCelsiusTime() * 1000d * 60d * 60d)).toString().substring(0, 5)) + .append("\n"); + sb + .append("End: ") + .append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getEndCelsius())) + .append(" °C at 24:00") + .append("\n"); + sb.append("Wind: ").append((int)wf.getWind()).append(" m/s\n"); + sb.append("Cloudiness: ").append(Cloudiness.forValue(wf.getCloudiness()).getDescription().toLowerCase()).append("\n"); + if(wf.getThunder() > 0d) { + sb.append("Thunder strenth: ").append(NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES.format(wf.getThunder() * 100d)).append("%\n"); + } + sb.append("Rain: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getRain())).append(" mm\n"); + if(wf.getSnow() > 0d) { + sb.append("Snow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(wf.getSnow())).append(" mm\n"); + } + sb.append("Humidity: ").append((int)(wf.getHumidity() * 100d * 0.6)).append(" %\n"); + if(wf.getHeatOrColdWave() < 0.5d) { + sb.append("Cold Wave: ").append(NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES.format(100d - (wf.getHeatOrColdWave() * 2 * 100d))).append(" %\n"); + } else { + sb.append("Heat Wave: ").append(NumberFormats.FORMATTER_ZERO_DECIMAL_PLACES.format((wf.getHeatOrColdWave() - 0.5d) * 2 * 100d)).append(" %\n"); + } + WeatherForecast f1 = forecasts.get(forecasts.indexOf(wf) + 1); + WeatherForecast f2 = forecasts.get(forecasts.indexOf(wf) + 2); + WeatherForecast f3 = forecasts.get(forecasts.indexOf(wf) + 3); + WeatherForecast f4 = forecasts.get(forecasts.indexOf(wf) + 4); + WeatherForecast f5 = forecasts.get(forecasts.indexOf(wf) + 5); + WeatherForecast f6 = forecasts.get(forecasts.indexOf(wf) + 6); + sb.append("Tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f1.getMaximumCelsius())).append(" °C\n"); + sb.append("Day after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f2.getMaximumCelsius())).append(" °C\n"); + sb.append(" 2 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f3.getMaximumCelsius())).append(" °C\n"); + sb.append(" 3 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f4.getMaximumCelsius())).append(" °C\n"); + sb.append(" 4 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f5.getMaximumCelsius())).append(" °C\n"); + sb.append(" 5 days after tomorrow: ").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(f6.getMaximumCelsius())).append(" °C\n"); + + Utils.showNotification(sb.toString(), 30000, 400); + } + String[] array = wf.asPrettyString(add > 0 ? -1 : new TTime(time.hourProperty.getValue(), + time.minuteProperty.getValue(), + time.secondProperty.getValue(), + time.millisecondProperty.getValue()).toTotalMilliseconds() / 1000d / 60d / 60d).split(WeatherForecast.DOUBLE_COLON); + List list = null; + for (String a : array) { + if (a.length() >= 14) { + list = new ArrayList<>(); + break; + } + } + if (list != null) { + for (String a : array) { + if (a.length() >= 14) { + list.add(a.substring(0, 14)); + list.add(a.substring(14, a.length())); + } else { + list.add(a); + } + } + array = new String[list.size()]; + for (int i = 0; i < list.size(); i++) { + array[i] = list.get(i); + } + } + + int rowHeight = 12; + int row = 0; + brush.drawString(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime()), 0, SwingUtils.MARGIN + row); + row = row + 12; + brush.drawString(DateFormats.DATE_TIME_FORMATTER_DAY_OF_WEEK.format(cal.getTime()), 0, SwingUtils.MARGIN + row); + row = row + rowHeight + 10; + brush.drawString(array[0], 0, SwingUtils.MARGIN + row); + row = row + rowHeight; + brush.drawString(array.length < 2 ? "" : array[1], 0, SwingUtils.MARGIN + row); + row = row + rowHeight; + brush.drawString(array.length < 3 ? "" : array[2], 0, SwingUtils.MARGIN + row); + row = row + rowHeight; + if (array.length >= 4) { + brush.drawString(array[3], 0, SwingUtils.MARGIN + row); + row = row + rowHeight; + } + if (array.length >= 5) { + brush.drawString(array[4], 0, SwingUtils.MARGIN + row); + row = row + rowHeight; + } + this.setToolTipText(wf.toString()); + } + + //private boolean w = false; + + @Override + public Property getVisibilityProperty() { + return visibilityProperty; + } + + @Override + public Property getVisibilitySupportedColoredProperty() { + return visibilitySupportedColoredProperty; + } + + @Override + public List createAdditionalMenus() { + if (this.menuItems == null) { + menuItems = new ArrayList<>(); + JMenuItem pauseResume = new JMenuItem("Pause/Resume"); + pauseResume.addActionListener(e -> paused = !paused); + menuItems.add(pauseResume); + + JMenuItem now = new JMenuItem("Now"); + now.addActionListener(e -> { + lastAdd = 0; + paused = true; + }); + menuItems.add(now); + + JMenuItem info = new JMenuItem("Info"); + info.addActionListener(e -> { + information = true; + }); + menuItems.add(info); + + } + return this.menuItems; + } + private boolean paused = false; +} diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/WeatherForecast.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/WeatherForecast.java new file mode 100644 index 0000000..b55941d --- /dev/null +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/progress/weather/WeatherForecast.java @@ -0,0 +1,555 @@ +package org.nanoboot.utils.timecalc.swing.progress.weather; + +import lombok.Getter; +import lombok.Setter; +import org.nanoboot.utils.timecalc.utils.common.FileConstants; +import org.nanoboot.utils.timecalc.utils.common.NumberFormats; + +import java.io.FileInputStream; +import java.io.IOException; +import java.time.LocalDate; +import java.time.Month; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import lombok.ToString; +import org.nanoboot.utils.timecalc.utils.common.DateFormats; + +/** + * @author pc00289 + * @since 22.03.2024 + */ +@Getter +@Setter +@ToString +public class WeatherForecast { +//01:00-4:00 - minimum +//13:00-16:00 - maximum +//20240101.minTempC= +//20240101.maxTempC= +// 20240101.minTempTime= +//20240101.maxTempTime= +//20240101.wind={m/s} +//20240101.cloudiness={0.0 - 1.0} +//20240101.thunder={0.0 - 1.0} +//20240101.rain={mm} +//20240101.snow={mm} +//#20240101.sunrise=7:53 +//#20240101.sunset=16:02 + + public static final String DOUBLE_COLON = "::"; + + private String date; + private double minimumCelsius; + private double maximumCelsius; + private double minimumCelsiusTime; + private double maximumCelsiusTime; + private double wind; + private double cloudiness; + private double thunder; + private double rain; + private double snow; + private double humidity; + private double heatOrColdWave; + private double startCelsius; + private double endCelsius; + + public static List createForecast(int year) { + List list = new ArrayList<>(); + + Properties climateProperties = new Properties(); + if (FileConstants.CLIMATE_TXT.exists()) { + try { + climateProperties.load(new FileInputStream(FileConstants.CLIMATE_TXT)); + } catch (IOException e) { + e.printStackTrace(); + System.out.println("Loading file failed: " + FileConstants.WEATHER_CSV + " " + e.getMessage()); + //return list; + } + } else { + System.out.println("File does not exist: " + FileConstants.CLIMATE_TXT); + //return list; + } + + double min1 = Double.valueOf(climateProperties.getProperty("1.min", "-20")) + 10; + double min2 = Double.valueOf(climateProperties.getProperty("2.min", "-16")) + 10; + double min3 = Double.valueOf(climateProperties.getProperty("3.min", "-12")) + 10; + double min4 = Double.valueOf(climateProperties.getProperty("4.min", "-8")) + 10; + double min5 = Double.valueOf(climateProperties.getProperty("5.min", "-4")) + 10; + double min6 = Double.valueOf(climateProperties.getProperty("6.min", "-2")) + 10; + double min7 = Double.valueOf(climateProperties.getProperty("7.min", "0")) + 10; + double min8 = Double.valueOf(climateProperties.getProperty("8.min", "0")) + 10; + double min9 = Double.valueOf(climateProperties.getProperty("9.min", "-2")) + 10; + double min10 = Double.valueOf(climateProperties.getProperty("10.min", "-4")) + 10; + double min11 = Double.valueOf(climateProperties.getProperty("11.min", "-8")) + 10; + double min12 = Double.valueOf(climateProperties.getProperty("12.min", "-16")) + 10; + + double max1 = Double.valueOf(climateProperties.getProperty("1.max", "20")); + double max2 = Double.valueOf(climateProperties.getProperty("2.max", "15")); + double max3 = Double.valueOf(climateProperties.getProperty("3.max", "20")); + double max4 = Double.valueOf(climateProperties.getProperty("4.max", "25")); + double max5 = Double.valueOf(climateProperties.getProperty("5.max", "30")); + double max6 = Double.valueOf(climateProperties.getProperty("6.max", "35")); + double max7 = Double.valueOf(climateProperties.getProperty("7.max", "40")); + double max8 = Double.valueOf(climateProperties.getProperty("8.max", "40")); + double max9 = Double.valueOf(climateProperties.getProperty("9.max", "35")); + double max10 = Double.valueOf(climateProperties.getProperty("10.max", "30")); + double max11 = Double.valueOf(climateProperties.getProperty("11.max", "25")); + double max12 = Double.valueOf(climateProperties.getProperty("12.max", "20")); + + Map> minExpected = new HashMap<>(); + Map> maxExpected = new HashMap<>(); + Calendar cal_ = Calendar.getInstance(); + cal_.set(Calendar.YEAR, 2021); + cal_.set(Calendar.MONTH, 0); + cal_.set(Calendar.DAY_OF_MONTH, 1); + + while (cal_.get(Calendar.YEAR) == 2021) { + int month = cal_.get(Calendar.MONTH) + 1; + int dayOfMonth = cal_.get(Calendar.DAY_OF_MONTH); + double min = 0d; + double max = 0d; + + double minStart = 0d; + double minEnd = 0d; + double maxStart = 0d; + double maxEnd = 0d; + double transition = 0d; + LocalDate today = LocalDate.of(2021, Month.of(month), dayOfMonth); + + LocalDate startDay = null; + LocalDate endDay = null; + + if ((month == 12 && dayOfMonth >= 16) || (month == 1 && dayOfMonth <= 15)) { + minStart = min12; + minEnd = min1; + maxStart = max12; + maxEnd = max1; + startDay = LocalDate.of(2020, Month.DECEMBER, 16); + endDay = LocalDate.of(2021, Month.JANUARY, 15); + + } + if ((month == 1 && dayOfMonth >= 16) || (month == 2 && dayOfMonth <= 14)) { + minStart = min1; + minEnd = min2; + maxStart = max1; + maxEnd = max2; + startDay = LocalDate.of(2021, Month.of(1), 16); + endDay = LocalDate.of(2021, Month.of(2), 14); + } + if ((month == 2 && dayOfMonth >= 15) || (month == 3 && dayOfMonth <= 15)) { + minStart = min2; + minEnd = min3; + maxStart = max2; + maxEnd = max3; + startDay = LocalDate.of(2021, Month.of(2), 15); + endDay = LocalDate.of(2021, Month.of(3), 16); + } + if ((month == 3 && dayOfMonth >= 16) || (month == 4 && dayOfMonth <= 15)) { + minStart = min3; + minEnd = min4; + maxStart = max3; + maxEnd = max4; + startDay = LocalDate.of(2021, Month.of(3), 16); + endDay = LocalDate.of(2021, Month.of(4), 15); + } + if ((month == 4 && dayOfMonth >= 16) || (month == 5 && dayOfMonth <= 15)) { + minStart = min4; + minEnd = min5; + maxStart = max4; + maxEnd = max5; + startDay = LocalDate.of(2021, Month.of(4), 16); + endDay = LocalDate.of(2021, Month.of(5), 15); + } + if ((month == 5 && dayOfMonth >= 16) || (month == 6 && dayOfMonth <= 15)) { + minStart = min5; + minEnd = min6; + maxStart = max5; + maxEnd = max6; + startDay = LocalDate.of(2021, Month.of(5), 16); + endDay = LocalDate.of(2021, Month.of(6), 15); + } + if ((month == 6 && dayOfMonth >= 16) || (month == 7 && dayOfMonth <= 15)) { + minStart = min6; + minEnd = min7; + maxStart = max6; + maxEnd = max7; + startDay = LocalDate.of(2021, Month.of(6), 16); + endDay = LocalDate.of(2021, Month.of(7), 15); + } + if ((month == 7 && dayOfMonth >= 16) || (month == 8 && dayOfMonth <= 15)) { + minStart = min7; + minEnd = min8; + maxStart = max7; + maxEnd = max8; + startDay = LocalDate.of(2021, Month.of(7), 16); + endDay = LocalDate.of(2021, Month.of(8), 15); + } + if ((month == 8 && dayOfMonth >= 16) || (month == 9 && dayOfMonth <= 15)) { + minStart = min8; + minEnd = min9; + maxStart = max8; + maxEnd = max9; + startDay = LocalDate.of(2021, Month.of(8), 16); + endDay = LocalDate.of(2021, Month.of(9), 15); + } + if ((month == 9 && dayOfMonth >= 16) || (month == 10 && dayOfMonth <= 15)) { + minStart = min9; + minEnd = min10; + maxStart = max9; + maxEnd = max10; + startDay = LocalDate.of(2021, Month.of(9), 16); + endDay = LocalDate.of(2021, Month.of(10), 15); + } + if ((month == 10 && dayOfMonth >= 16) || (month == 11 && dayOfMonth <= 15)) { + minStart = min10; + minEnd = min11; + maxStart = max10; + maxEnd = max11; + startDay = LocalDate.of(2021, Month.of(10), 16); + endDay = LocalDate.of(2021, Month.of(11), 15); + } + if ((month == 11 && dayOfMonth >= 16) || (month == 12 && dayOfMonth <= 15)) { + minStart = min11; + minEnd = min12; + maxStart = max11; + maxEnd = max12; + startDay = LocalDate.of(2021, Month.of(11), 16); + endDay = LocalDate.of(2021, Month.of(12), 15); + } + + double daysBetween = ChronoUnit.DAYS.between(startDay, endDay) + 1; + double daysDone = ChronoUnit.DAYS.between(startDay, today) + 1; + if (daysDone > 365) { + daysDone = daysDone - 365; + } + transition = daysDone / daysBetween; + if (!minExpected.containsKey(month)) { + minExpected.put(month, new HashMap()); + } + if (!maxExpected.containsKey(month)) { + maxExpected.put(month, new HashMap()); + } + double minDiff = Math.abs(minEnd - minStart); + double maxDiff = Math.abs(maxEnd - maxStart); + + double minAdd = (minDiff * transition * (minStart < maxEnd ? 1 : (-1))); + double maxAdd = (maxDiff * transition * (maxStart < maxEnd ? 1 : (-1))); + min = minStart + minAdd; + max = maxStart + maxAdd; + +// System.out.print("\n" + month + "-" + dayOfMonth + ": "); +// System.out.print(" minStart= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minStart)); +// System.out.print(" minEnd= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minEnd)); +// System.out.print(" maxStart= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maxStart)); +// System.out.print(" maxEnd= " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maxEnd)); +// System.out.println(" min and max: " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(min) + " " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(max)); +// System.out.println(" min and max diff: " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minDiff) + " " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maxDiff)); +// System.out.println("transition=" + transition); +// System.out.println("daysDone=" + daysDone + " daysBetween=" + daysBetween); +// System.out.println("startDay=" + startDay.toString()); +// System.out.println("endDay=" + endDay.toString()); + minExpected.get(month).put(dayOfMonth, min); + maxExpected.get(month).put(dayOfMonth, max); + + cal_.add(Calendar.DAY_OF_MONTH, 1); + } + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, 0); + cal.set(Calendar.DAY_OF_MONTH, 1); + double humidity = Math.random() * 0.6; + double heatOrColdWave = Math.random(); + int tooMuchHumidityDays = 0; + int tooMuchHeatDays = 0; + int tooMuchColdDays = 0; + double windiness = Math.random(); + List maxCLastWeekAverage = new ArrayList(); + List minCLastWeekAverage = new ArrayList(); + double endCelsius = Double.MIN_VALUE; + while (cal.get(Calendar.YEAR) == year) { + if (humidity > 0.7) { + ++tooMuchHumidityDays; + } + if (heatOrColdWave > 0.8) { + ++tooMuchHeatDays; + } + if (heatOrColdWave < 0.3) { + ++tooMuchColdDays; + } + if (tooMuchHumidityDays > 5) { + if (Math.random() > 0.5) { + humidity = Math.random() * 0.15; + } + } + if (tooMuchHeatDays > 5) { + if (Math.random() > 0.5) { + heatOrColdWave = Math.random() * 0.1; + } + } + if (tooMuchColdDays > 5) { + if (Math.random() > 0.5) { + heatOrColdWave = Math.random() * 0.9; + } + } + if (Math.random() > 0.75) { + humidity = humidity + Math.random() * 0.3 * (Math.random() > 0.9 ? (-1) : 1); + if (humidity > 1.0) { + humidity = 1.0; + } + if (humidity < 0.0) { + humidity = 0.0; + } + } + if (Math.random() > 0.95) { + humidity = 0.9 + Math.random() * 0.1; + } + if (Math.random() > 0.75) { + heatOrColdWave = heatOrColdWave + Math.random() * 0.1 * (Math.random() > 0.9 ? (-1) : 1); + if (heatOrColdWave > 1.0) { + heatOrColdWave = 1.0; + } + if (heatOrColdWave < 0.0) { + heatOrColdWave = 0.0; + } + if (heatOrColdWave > 0.85 && Math.random() > 0.25) { + heatOrColdWave = 0.85; + } + if (heatOrColdWave < 0.15 && Math.random() > 0.25) { + heatOrColdWave = 0.15; + } + } + + int month = cal.get(Calendar.MONTH) + 1; + int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH); + WeatherForecast forecast = new WeatherForecast(); + list.add(forecast); + forecast.setDate(DateFormats.DATE_TIME_FORMATTER_YYYYMMDD.format(cal.getTime())); + forecast.setMaximumCelsius(maxExpected.get(month).get((month == 2 && dayOfMonth == 29) ? 28 : dayOfMonth)); + forecast.setMinimumCelsius(minExpected.get(month).get((month == 2 && dayOfMonth == 29) ? 28 : dayOfMonth)); + double maxE = forecast.getMaximumCelsius(); + double minE = forecast.getMinimumCelsius(); + double maxExpectedCelsius = forecast.getMaximumCelsius(); + double minExpectedCelsius = forecast.getMinimumCelsius(); + + if (Math.random() > 0.4) { + if (minE < -10) { + minE = minE + 10 + 10 * Math.random(); + } + if (maxE > 40) { + maxE = maxE - 10 - 10 * Math.random(); + } + } + if (minE < -10 && Math.random() > 0.5) { + heatOrColdWave = 0.7 + Math.random() * 0.2; + } + if (maxE > 38 && Math.random() > 0.5) { + heatOrColdWave = 0.1 + Math.random() * 0.1; + } + if (maxExpectedCelsius - 10 > maxCLastWeekAverage.stream().mapToDouble(e -> Double.valueOf(e)).average().orElse(maxExpectedCelsius - 10)) { + heatOrColdWave = heatOrColdWave + ((1.0d - heatOrColdWave) / 2d); + } else { + heatOrColdWave = heatOrColdWave / 2d; + } + if (minExpectedCelsius + 10 > minCLastWeekAverage.stream().mapToDouble(e -> Double.valueOf(e)).average().orElse(minExpectedCelsius + 10)) { + heatOrColdWave = heatOrColdWave + ((1.0d - heatOrColdWave) / 2d); + } else { + heatOrColdWave = heatOrColdWave / 2d; + } + double mediumHalf = minE + Math.abs(maxE - minE) / 2; + forecast.setMaximumCelsius(mediumHalf + heatOrColdWave * 1.1 * mediumHalf); + forecast.setMinimumCelsius(minE + heatOrColdWave * 1.5 * mediumHalf); + windiness = Math.random(); + if (Math.random() > 0.9 && windiness < 0.15) { + windiness = 0d; + } + forecast.setWind(windiness * (Math.random() > 0.95 ? 40 : Math.random() * 150)); + forecast.setCloudiness(Math.random() > 0.3 ? humidity : Math.random()); + if (forecast.getMaximumCelsius() > 25 && Math.random() > 0.9) { + forecast.setThunder(Math.random()); + } + if (humidity > 0.2) { + if (forecast.getMinimumCelsius() > 3) { + forecast.setRain(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1)); + } + if (forecast.getMinimumCelsius() < 0) { + forecast.setSnow(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1)); + } + if (forecast.getMinimumCelsius() > 0 && forecast.getMinimumCelsius() < 3) { + if (Math.random() > 0.5) { + forecast.setRain(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1)); + } else { + forecast.setSnow(humidity * Math.random() * 50 * (Math.random() > 0.90 ? Math.random() * 10 : 1)); + } + } + } + forecast.setHumidity(humidity); + forecast.setHeatOrColdWave(heatOrColdWave); + forecast.setMaximumCelsiusTime(12.0 + Math.random() * 5); + forecast.setMinimumCelsiusTime(02.0 + Math.random() * 4); + + maxCLastWeekAverage.add(forecast.getMaximumCelsius()); + minCLastWeekAverage.add(forecast.getMinimumCelsius()); + while (maxCLastWeekAverage.size() > 7) { + maxCLastWeekAverage.remove(0); + } + while (minCLastWeekAverage.size() > 7) { + minCLastWeekAverage.remove(0); + } + if(endCelsius == Double.MIN_VALUE) { + forecast.setStartCelsius(forecast.getMinimumCelsius() + Math.random() * 8); + } else { + forecast.setStartCelsius(endCelsius); + } + forecast.setEndCelsius(forecast.getMinimumCelsius() + Math.random() * 5); + endCelsius = forecast.getEndCelsius(); + + // private String date; +// private double minimumCelsius; +// private double maximumCelsius; +// private double minimumCelsiusTime; +// private double maximumCelsiusTime; +// private double wind; +// private double cloudiness; +// private double thunder; +// private double rain; +// private double snow; + cal.add(Calendar.DAY_OF_MONTH, 1); + } + return list; + } + + public String toCsv() { + StringBuilder sb = new StringBuilder(); + sb.append(date).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(minimumCelsius)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(maximumCelsius)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(minimumCelsiusTime)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(maximumCelsiusTime)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(wind)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(cloudiness)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(thunder)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(rain)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(snow)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(humidity)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(heatOrColdWave)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(startCelsius)).append('\t'); + sb.append(NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(endCelsius)); + return sb.toString(); + } + + public WeatherForecast fromCsv(String csv) { + String[] values = csv.split("\t"); + + int i = 0; + date = values[i++]; + minimumCelsius = Double.valueOf(values[i++]); + maximumCelsius = Double.valueOf(values[i++]); + minimumCelsiusTime = Double.valueOf(values[i++]); + maximumCelsiusTime = Double.valueOf(values[i++]); + wind = Double.valueOf(values[i++]); + cloudiness = Double.valueOf(values[i++]); + thunder = Double.valueOf(values[i++]); + rain = Double.valueOf(values[i++]); + snow = Double.valueOf(values[i++]); + humidity = Double.valueOf(values[i++]); + heatOrColdWave = Double.valueOf(values[i++]); + startCelsius = Double.valueOf(values[i++]); + endCelsius = Double.valueOf(values[i++]); + + return this; + } + + public String asPrettyString() { + return asPrettyString(-1); + } + + public String asPrettyString(double forHour) { + StringBuilder sb = new StringBuilder(); + sb.append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(maximumCelsius)).append("°C/").append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(minimumCelsius)).append("°C").append(DOUBLE_COLON); + if (forHour >= 0d) { + double value = getCelsiusForHour(forHour); + sb.append("Now: " + NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(value)).append("°C").append(DOUBLE_COLON); + } + // + sb + .append((int) Math.floor(this.wind)) + .append("m/s"); + if (snow == 0d) { + sb + .append("🌧") + .append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(rain)) + .append("mm").append(DOUBLE_COLON); + } else { + sb + .append("❄") + .append(NumberFormats.FORMATTER_ONE_DECIMAL_PLACE.format(snow)) + .append("mm").append(DOUBLE_COLON); + } + sb + .append(Cloudiness.forValue(cloudiness).getDescription().toLowerCase()) + .append(DOUBLE_COLON); + return sb.toString(); +// return "14°C::wind 7/s::rain 2mm::cloudy"; + } + + public Double getCelsiusForHour(double forHour) { + if(forHour > 24) { + throw new UnsupportedOperationException("Hour must less than 24: " + NumberFormats.FORMATTER_FIVE_DECIMAL_PLACES.format(forHour)); + } + double minTime = this.minimumCelsiusTime; + double maxTime = this.maximumCelsiusTime; + if (maxTime < minTime) { + minTime = 4d; + maxTime = 14d; + } + double endTime = 24d; + double value = 0d; + if (forHour < minTime) { + return this.startCelsius - ((this.startCelsius - this.minimumCelsius) * forHour / minTime); + } + if (forHour >= minTime && forHour <= maxTime) { + return minimumCelsius + ((forHour - minTime) / (maxTime - minTime)) * (maximumCelsius - minimumCelsius); + } + if (forHour > maxTime) { + return maximumCelsius - (((forHour - maxTime) / (endTime - maxTime)) * (maximumCelsius - this.endCelsius)); + } + throw new IllegalStateException(); + } +} + + + + +/* +climate.txt +1.max=18.8 +2.max=22.0 +3.max=26.2 +4.max=31.8 +5.max=35.0 +6.max=38.9 +7.max=40.2 +8.max=40.4 +9.max=37.4 +10.max=30.3 +11.max=24.0 +12.max=19.8 +1.min=-36.2 +2.min=-42.2 +3.min=-32.0 +4.min=-22.0 +5.min=-13.1 +6.min=-8.3 +7.min=-6.9 +8.min=-5.0 +9.min=-10.5 +10.min=-19.9 +11.min=-25.4 +12.min=-34.0 + */ diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/windows/MainWindow.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/windows/MainWindow.java index 94a8ce0..8d582ed 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/windows/MainWindow.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/swing/windows/MainWindow.java @@ -37,7 +37,7 @@ import org.nanoboot.utils.timecalc.swing.progress.ProgressLife; import org.nanoboot.utils.timecalc.swing.progress.ProgressMoney; import org.nanoboot.utils.timecalc.swing.progress.ProgressSquare; import org.nanoboot.utils.timecalc.swing.progress.ProgressSwing; -import org.nanoboot.utils.timecalc.swing.progress.ProgressWeather; +import org.nanoboot.utils.timecalc.swing.progress.weather.ProgressWeather; import org.nanoboot.utils.timecalc.swing.progress.Time; import org.nanoboot.utils.timecalc.swing.progress.WalkingHumanProgress; import org.nanoboot.utils.timecalc.swing.progress.WeekBattery; diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/FileConstants.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/FileConstants.java index 9a8800a..95eee2b 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/FileConstants.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/FileConstants.java @@ -18,7 +18,7 @@ public class FileConstants { public static final File JOKES_TXT = new File(TC_DIRECTORY, "time-calc-jokes.txt"); public static final File DB_FILE = new File(FileConstants.TC_DIRECTORY.getAbsolutePath() + "/" + "time-calc.sqlite3"); public static final File CLIMATE_TXT = new File(TC_DIRECTORY, "climate.txt"); - public static final File WEATHER_TXT = new File(TC_DIRECTORY, "weather.txt"); + public static final File WEATHER_CSV = new File(TC_DIRECTORY, "weather.csv"); private FileConstants() { //Not meant to be instantiated. } diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/NumberFormats.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/NumberFormats.java index da49c56..f359b4c 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/NumberFormats.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/NumberFormats.java @@ -11,6 +11,8 @@ public class NumberFormats { public static final NumberFormat FORMATTER_ZERO_DECIMAL_PLACES = new DecimalFormat("#00"); + public static final NumberFormat FORMATTER_ONE_DECIMAL_PLACE + = new DecimalFormat("#0.0"); public static final NumberFormat FORMATTER_TWO_DECIMAL_PLACES = new DecimalFormat("#0.00"); public static final NumberFormat FORMATTER_FIVE_DECIMAL_PLACES diff --git a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/Utils.java b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/Utils.java index 20820e8..3c5303c 100644 --- a/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/Utils.java +++ b/modules/time-calc-app/src/main/java/org/nanoboot/utils/timecalc/utils/common/Utils.java @@ -225,6 +225,7 @@ public class Utils { if (height != 0) { toaster.setToasterHeight(height); } + toaster.setToasterWidth(400); toaster.showToaster(message); }