🚸 Improve mail with movies from the Savoy
[rhynodge.git] / src / main / kotlin / net / pterodactylus / rhynodge / filters / webpages / savoy / MovieState.kt
diff --git a/src/main/kotlin/net/pterodactylus/rhynodge/filters/webpages/savoy/MovieState.kt b/src/main/kotlin/net/pterodactylus/rhynodge/filters/webpages/savoy/MovieState.kt
new file mode 100644 (file)
index 0000000..ea8f87c
--- /dev/null
@@ -0,0 +1,120 @@
+package net.pterodactylus.rhynodge.filters.webpages.savoy
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import kotlinx.html.a
+import kotlinx.html.body
+import kotlinx.html.div
+import kotlinx.html.dom.serialize
+import kotlinx.html.head
+import kotlinx.html.html
+import kotlinx.html.img
+import kotlinx.html.li
+import kotlinx.html.ol
+import kotlinx.html.section
+import kotlinx.html.span
+import kotlinx.html.style
+import kotlinx.html.title
+import kotlinx.html.ul
+import net.pterodactylus.rhynodge.Reaction
+import net.pterodactylus.rhynodge.states.AbstractState
+import java.time.LocalDateTime
+import java.util.Locale
+
+class MovieState(@JsonProperty val movies: Collection<Movie>, val newMovies: Collection<Movie> = emptySet(), private val triggered: Boolean = false) : AbstractState() {
+
+       private constructor() : this(emptySet())
+
+       override fun summary(reaction: Reaction) =
+               "%s â€“ Programme for %tY-%<tm-%<td".format(reaction.name(), earliestMovie?.earliestPerformance)
+
+       override fun plainText() = ""
+
+       override fun htmlText() = kotlinx.html.dom.createHTMLDocument().html {
+               head {
+                       title { +"Savoy Programme" }
+                       style("text/css") {
+                               +"html { font-family: Roboto; }"
+                               +"section.new-movies > .label { font-family: Impact; background-color: black; padding: 0.5ex; font-size: 200%; color: #ffffee; font-weight: bold; }"
+                               +"section.new-movies ul { padding: 0; margin: 0; }"
+                               +"section.new-movies li.movie { list-style: none; width: 250px; height: 353px; display: inline-block; position: relative; margin: 1ex 1ex 1ex 0ex; }"
+                               +"section.new-movies li.movie img { width: 100%; height: 100%; display: block; position: absolute; z-index: -1; }"
+                               +"section.new-movies li.movie .text { color: white; text-shadow: 2px 2px black; font-weight: bold; font-size: 150%; display: flex; flex-direction: column; justify-content: end; width: 100%; height: 100%; }"
+                               +"section.new-movies li.movie .text .name { padding: 1ex; font-size: 120%; }"
+
+                               +"section.daily-programmes ol { padding: 0; }"
+                               +"section.daily-programmes li { list-style: none; }"
+                               +"section.daily-programmes li.day > .label { font-family: Impact; background-color: black; padding: 0.5ex; font-size: 200%; color: #ffffee; font-weight: bold; }"
+                               +"section.daily-programmes li .performances { display: flex; border-top: 1ex; }"
+                               +"section.daily-programmes li.performance { width: 250px; height: 353px; display: inline-block; margin: 1ex 1ex 1ex 0ex; position: relative; }"
+                               +"section.daily-programmes li.performance a { width: 100%; height: 100%; display: block; text-decoration: none; }"
+                               +"section.daily-programmes li.performance a img { width: 100%; height: 100%; display: block; position: absolute; z-index: -1; }"
+                               +"section.daily-programmes li.performance a .text { color: white; text-shadow: 2px 2px black; font-weight: bold; font-size: 150%; display: flex; flex-direction: column; justify-content: space-between; width: 100%; height: 100%; }"
+                               +"section.daily-programmes li.performance a .text .time { padding: 1ex; text-align: right; }"
+                               +"section.daily-programmes li.performance a .text .name { padding: 1ex; font-size: 120%; }"
+                       }
+               }
+               body {
+                       if (newMovies.isNotEmpty()) {
+                               section("new-movies") {
+                                       div("label") {
+                                               +"New Movies"
+                                       }
+                                       ul {
+                                               newMovies.forEach { movie ->
+                                                       li("movie") {
+                                                               img(src = movie.imageUrl)
+                                                               div("text") {
+                                                                       div("name") {
+                                                                               +(movie.name)
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+                       section("daily-programmes") {
+
+                               ol("days") {
+                                       movies.flatMap { it.performances.map(Performance::getTime).map(LocalDateTime::toLocalDate) }.distinct().sorted().forEach { date ->
+                                               li("day") {
+                                                       attributes += "data-date" to "%tY-%<tm-%<td".format(date)
+                                                       div("label") {
+                                                               +("Programme for %tA, %<tY-%<tm-%<td".format(Locale.ENGLISH, date))
+                                                       }
+                                                       ol("performances") {
+                                                               movies
+                                                                       .flatMap { movie -> movie.performances.map { movie to it } }
+                                                                       .filter { (movie, performances) -> performances.time.toLocalDate() == date }
+                                                                       .sortedBy { (_, performance) -> performance.time }
+                                                                       .forEach { (movie, performance) ->
+                                                                               li("performance") {
+                                                                                       a(href = performance.link) {
+                                                                                               img(src = movie.imageUrl)
+                                                                                               div("text") {
+                                                                                                       div("time") {
+                                                                                                               +("%tH:%<tM".format(performance.time))
+                                                                                                       }
+                                                                                                       div("name") {
+                                                                                                               +(movie.name)
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                               }
+                                                                       }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+       }.serialize()
+
+       override fun triggered() = newMovies.isNotEmpty() || triggered
+
+       private val earliestMovie = movies.minByOrNull { it.earliestPerformance ?: LocalDateTime.MAX }
+       private val Movie.earliestPerformance: LocalDateTime? get() = performances.minOfOrNull(Performance::getTime)
+
+}