🎨 Replace Sinfest filter with Kotlin version
[rhynodge.git] / src / main / kotlin / net / pterodactylus / rhynodge / webpages / weather / WeatherState.kt
1 package net.pterodactylus.rhynodge.webpages.weather
2
3 import com.fasterxml.jackson.annotation.JsonGetter
4 import com.fasterxml.jackson.annotation.JsonProperty
5 import kotlinx.html.body
6 import kotlinx.html.div
7 import kotlinx.html.h1
8 import kotlinx.html.head
9 import kotlinx.html.html
10 import kotlinx.html.img
11 import kotlinx.html.stream.createHTML
12 import kotlinx.html.style
13 import kotlinx.html.unsafe
14 import net.pterodactylus.rhynodge.states.AbstractState
15 import java.text.DateFormat
16 import java.time.Instant
17 import java.time.ZoneId
18 import java.time.ZonedDateTime
19 import java.time.temporal.ChronoUnit
20 import java.util.Locale
21
22 /**
23  * Contains a weather state.
24  *
25  * @author [David â€˜Bombe’ Roden](mailto:bombe@pterodactylus.net)
26  */
27 class WeatherState(val service: String, val dateTime: ZonedDateTime) : AbstractState(true), Iterable<HourState> {
28
29         constructor(@JsonProperty("service") service: String, @JsonProperty("dateTime") time: Long) :
30                         this(service, Instant.ofEpochMilli(time).atZone(ZoneId.of("Europe/Berlin")))
31
32         @JsonProperty("hours")
33         val hours: List<HourState> = mutableListOf()
34
35         @get:JsonGetter("dateTime")
36         val timeMillis = dateTime.toInstant().toEpochMilli()
37
38         operator fun plusAssign(hourState: HourState) {
39                 (hours as MutableList<HourState>).add(hourState)
40         }
41
42         override fun iterator(): Iterator<HourState> {
43                 return hours.iterator()
44         }
45
46         override fun equals(other: Any?): Boolean {
47                 other as? WeatherState ?: return false
48                 return (dateTime == other.dateTime) and (hours == other.hours)
49         }
50
51         override fun plainText(): String=""
52
53         override fun htmlText(): String =
54                         createHTML().html {
55                                 head {
56                                         style("text/css") {
57                                                 unsafe {
58                                                         +".weather-states { display: table; } "
59                                                         +".hour-state, .header { display: table-row; } "
60                                                         +".hour-state > div { display: table-cell; padding: 0em 0.5em; text-align: center; } "
61                                                         +".header > div { display: table-cell; padding: 0em 0.5em; font-weight: bold; text-align: center; } "
62                                                 }
63                                         }
64                                 }
65                                 body {
66                                         val startTime = dateTime.toInstant()
67                                         h1 { +"The Weather (according to wetter.de) on %s".format(dateFormatter.format(startTime.toEpochMilli())) }
68                                         val showFeltTemperature = any { it.feltTemperature != null }
69                                         val showGustSpeed = any { it.gustSpeed != null }
70                                         val showHumidity = any { it.humidity != null }
71                                         div("weather-states") {
72                                                 div("header") {
73                                                         div { +"Time" }
74                                                         div { +"Temperature" }
75                                                         if (showHumidity) {
76                                                                 div { +"feels like" }
77                                                         }
78                                                         div { +"Chance of Rain" }
79                                                         div { +"Amount" }
80                                                         div { +"Wind from" }
81                                                         div { +"Speed" }
82                                                         if (showGustSpeed) {
83                                                                 div { +"Gusts" }
84                                                         }
85                                                         if (showHumidity) {
86                                                                 div { +"Humidity" }
87                                                         }
88                                                         div { +"Description" }
89                                                         div { +"Image" }
90                                                 }
91                                                 forEach {
92                                                         div("hour-state") {
93                                                                 div("time") { +"%tH:%<tM".format(startTime.plus(it.hourIndex.toLong(), ChronoUnit.HOURS).toEpochMilli()) }
94                                                                 div("temperature") { +"${it.temperature} Â°C" }
95                                                                 if (showFeltTemperature) {
96                                                                         div("felt-temperature") { +if (it.feltTemperature != null) "(${it.feltTemperature} Â°C)" else "" }
97                                                                 }
98                                                                 div("rain-probability") { +"${it.rainProbability.times(100).toInt()}%" }
99                                                                 div("rain-amount") { +"${it.rainAmount.minDigits()} l/m²" }
100                                                                 div("wind-direction") { +it.windDirection.arrow }
101                                                                 div("wind-speed") { +"${it.windSpeed} km/h" }
102                                                                 if (showGustSpeed) {
103                                                                         div("gust-speed") { +if (it.gustSpeed != null) "(up to ${it.gustSpeed} km/h)" else "" }
104                                                                 }
105                                                                 if (showHumidity) {
106                                                                         div("humidity") { +if (it.humidity != null) "${it.humidity.times(100).toInt()}%" else "" }
107                                                                 }
108                                                                 div("description") { +it.description }
109                                                                 div("image") { img(src = it.image) }
110                                                         }
111                                                 }
112                                         }
113                                 }
114                         }.toString()
115
116 }
117
118 private val dateFormatter: DateFormat =
119         DateFormat.getDateInstance(DateFormat.LONG, Locale.ENGLISH)
120
121 private fun Double.minDigits(): String =
122                 toString().replace(Regex("\\.0*$"), "")