4ee0fd88b1dfd4f8b4983dabc24df874dc568f48
[rhynodge.git] / src / main / kotlin / net / pterodactylus / rhynodge / filters / webpages / savoy / MovieState.kt
1 package net.pterodactylus.rhynodge.filters.webpages.savoy
2
3 import com.fasterxml.jackson.annotation.JsonProperty
4 import kotlinx.html.a
5 import kotlinx.html.body
6 import kotlinx.html.div
7 import kotlinx.html.dom.serialize
8 import kotlinx.html.head
9 import kotlinx.html.html
10 import kotlinx.html.img
11 import kotlinx.html.li
12 import kotlinx.html.ol
13 import kotlinx.html.section
14 import kotlinx.html.style
15 import kotlinx.html.title
16 import kotlinx.html.ul
17 import net.pterodactylus.rhynodge.Reaction
18 import net.pterodactylus.rhynodge.states.AbstractState
19 import java.time.LocalDateTime
20 import java.util.Locale
21
22 class MovieState(@JsonProperty val movies: Collection<Movie>, val newMovies: Collection<Movie> = emptySet(), private val triggered: Boolean = false) : AbstractState() {
23
24         private constructor() : this(emptySet())
25
26         override fun summary(reaction: Reaction) =
27                 "%s – Programme for %tY-%<tm-%<td".format(reaction.name(), earliestMovie?.earliestPerformance)
28
29         override fun plainText() = ""
30
31         override fun htmlText() = kotlinx.html.dom.createHTMLDocument().html {
32                 head {
33                         title { +"Savoy Programme" }
34                         style("text/css") {
35                                 +"html { font-family: 'Recursive Sans Linear Static', Roboto, serif; }"
36                                 +"section.new-movies > .label { font-family: Impact, sans-serif; background-color: black; padding: 0.5ex; font-size: 200%; color: #ffffee; font-weight: bold; }"
37                                 +"section.new-movies ul { padding: 0; margin: 0; }"
38                                 +"section.new-movies li.movie { list-style: none; width: 250px; height: 353px; display: inline-block; position: relative; margin: 1ex 1ex 1ex 0ex; }"
39                                 +"section.new-movies li.movie img { width: 100%; height: 100%; display: block; position: absolute; z-index: -1; }"
40                                 +"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%; }"
41                                 +"section.new-movies li.movie .text .name { padding: 1ex; font-size: 120%; }"
42
43                                 +"section.daily-programmes ol { padding: 0; }"
44                                 +"section.daily-programmes li { list-style: none; }"
45                                 +"section.daily-programmes li.day > .label { font-family: Impact, sans-serif; background-color: black; padding: 0.5ex; font-size: 200%; color: #ffffee; font-weight: bold; }"
46                                 +"section.daily-programmes li .performances { display: flex; border-top: 1ex; }"
47                                 +"section.daily-programmes li.performance { width: 250px; height: 353px; display: inline-block; margin: 1ex 1ex 1ex 0ex; position: relative; }"
48                                 +"section.daily-programmes li.performance a { width: 100%; height: 100%; display: block; text-decoration: none; }"
49                                 +"section.daily-programmes li.performance a img { width: 100%; height: 100%; display: block; position: absolute; z-index: -1; }"
50                                 +"section.daily-programmes li.performance a .text { color: white; text-shadow: 2px 2px black; font-weight: bold; font-size: 150%; width: 100%; height: 100%; }"
51                                 +"section.daily-programmes li.performance a .text .time { padding: 1ex; text-align: right; }"
52                                 +"section.daily-programmes li.performance a .text .type { padding: 0ex 1ex 1ex 1ex; text-align: right; }"
53                                 +"section.daily-programmes li.performance a .text .name { padding: 1ex; font-size: 120%; bottom: 0px; position: absolute; }"
54                         }
55                 }
56                 body {
57                         if (newMovies.isNotEmpty()) {
58                                 section("new-movies") {
59                                         div("label") {
60                                                 +"New Movies"
61                                         }
62                                         ul {
63                                                 newMovies.forEach { movie ->
64                                                         li("movie") {
65                                                                 img(src = movie.imageUrl)
66                                                                 div("text") {
67                                                                         div("name") {
68                                                                                 +(movie.name)
69                                                                         }
70                                                                 }
71                                                         }
72                                                 }
73                                         }
74                                 }
75                         }
76
77                         section("daily-programmes") {
78
79                                 ol("days") {
80                                         movies.flatMap { it.performances.map(Performance::getTime).map(LocalDateTime::toLocalDate) }.distinct().sorted().forEach { date ->
81                                                 li("day") {
82                                                         attributes += "data-date" to "%tY-%<tm-%<td".format(date)
83                                                         div("label") {
84                                                                 +("Programme for %tA, %<tY-%<tm-%<td".format(Locale.ENGLISH, date))
85                                                         }
86                                                         ol("performances") {
87                                                                 movies
88                                                                         .flatMap { movie -> movie.performances.map { movie to it } }
89                                                                         .filter { (movie, performances) -> performances.time.toLocalDate() == date }
90                                                                         .sortedBy { (_, performance) -> performance.time }
91                                                                         .forEach { (movie, performance) ->
92                                                                                 li("performance") {
93                                                                                         a(href = performance.link) {
94                                                                                                 img(src = movie.imageUrl)
95                                                                                                 div("text") {
96                                                                                                         div("time") {
97                                                                                                                 +("%tH:%<tM".format(performance.time))
98                                                                                                         }
99                                                                                                         div("type") {
100                                                                                                                 +performance.type
101                                                                                                         }
102                                                                                                         div("name") {
103                                                                                                                 +(movie.name)
104                                                                                                         }
105                                                                                                 }
106                                                                                         }
107                                                                                 }
108                                                                         }
109                                                         }
110                                                 }
111                                         }
112                                 }
113                         }
114                 }
115
116         }.serialize()
117
118         override fun triggered() = newMovies.isNotEmpty() || triggered
119
120         private val earliestMovie = movies.minByOrNull { it.earliestPerformance ?: LocalDateTime.MAX }
121         private val Movie.earliestPerformance: LocalDateTime? get() = performances.minOfOrNull(Performance::getTime)
122
123 }