Update years in copyright line
[Sone.git] / src / main / java / net / pterodactylus / sone / web / ajax / GetTimesAjaxPage.java
1 /*
2  * Sone - GetTimesAjaxPage.java - Copyright © 2010–2015 David Roden
3  *
4  * This program is free software: you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License as published by the Free Software
6  * Foundation, either version 3 of the License, or (at your option) any later
7  * version.
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  * details.
13  *
14  * You should have received a copy of the GNU General Public License along with
15  * this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 package net.pterodactylus.sone.web.ajax;
19
20 import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance;
21
22 import java.text.DateFormat;
23 import java.text.SimpleDateFormat;
24 import java.util.Date;
25 import java.util.concurrent.TimeUnit;
26
27 import net.pterodactylus.sone.data.Post;
28 import net.pterodactylus.sone.data.PostReply;
29 import net.pterodactylus.sone.web.WebInterface;
30 import net.pterodactylus.sone.web.page.FreenetRequest;
31
32 import com.fasterxml.jackson.databind.node.ObjectNode;
33 import com.google.common.base.Optional;
34
35 /**
36  * Ajax page that returns a formatted, relative timestamp for replies or posts.
37  *
38  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
39  */
40 public class GetTimesAjaxPage extends JsonPage {
41
42         /** Formatter for tooltips. */
43         private static final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy, HH:mm:ss");
44
45         /**
46          * Creates a new get times AJAX page.
47          *
48          * @param webInterface
49          *            The Sone web interface
50          */
51         public GetTimesAjaxPage(WebInterface webInterface) {
52                 super("getTimes.ajax", webInterface);
53         }
54
55         /**
56          * {@inheritDoc}
57          */
58         @Override
59         protected JsonReturnObject createJsonObject(FreenetRequest request) {
60                 String allIds = request.getHttpRequest().getParam("posts");
61                 ObjectNode postTimes = new ObjectNode(instance);
62                 if (allIds.length() > 0) {
63                         String[] ids = allIds.split(",");
64                         for (String id : ids) {
65                                 Optional<Post> post = webInterface.getCore().getPost(id);
66                                 if (!post.isPresent()) {
67                                         continue;
68                                 }
69                                 ObjectNode postTime = new ObjectNode(instance);
70                                 Time time = getTime(post.get().getTime());
71                                 postTime.put("timeText", time.getText());
72                                 postTime.put("refreshTime", TimeUnit.MILLISECONDS.toSeconds(time.getRefresh()));
73                                 synchronized (dateFormat) {
74                                         postTime.put("tooltip", dateFormat.format(new Date(post.get().getTime())));
75                                 }
76                                 postTimes.put(id, postTime);
77                         }
78                 }
79                 ObjectNode replyTimes = new ObjectNode(instance);
80                 allIds = request.getHttpRequest().getParam("replies");
81                 if (allIds.length() > 0) {
82                         String[] ids = allIds.split(",");
83                         for (String id : ids) {
84                                 Optional<PostReply> reply = webInterface.getCore().getPostReply(id);
85                                 if (!reply.isPresent()) {
86                                         continue;
87                                 }
88                                 ObjectNode replyTime = new ObjectNode(instance);
89                                 Time time = getTime(reply.get().getTime());
90                                 replyTime.put("timeText", time.getText());
91                                 replyTime.put("refreshTime", TimeUnit.MILLISECONDS.toSeconds(time.getRefresh()));
92                                 synchronized (dateFormat) {
93                                         replyTime.put("tooltip", dateFormat.format(new Date(reply.get().getTime())));
94                                 }
95                                 replyTimes.put(id, replyTime);
96                         }
97                 }
98                 return createSuccessJsonObject().put("postTimes", postTimes).put("replyTimes", replyTimes);
99         }
100
101         /**
102          * {@inheritDoc}
103          */
104         @Override
105         protected boolean needsFormPassword() {
106                 return false;
107         }
108
109         /**
110          * {@inheritDoc}
111          */
112         @Override
113         protected boolean requiresLogin() {
114                 return false;
115         }
116
117         //
118         // PRIVATE METHODS
119         //
120
121         /**
122          * Returns the formatted relative time for a given time.
123          *
124          * @param time
125          *            The time to format the difference from (in milliseconds)
126          * @return The formatted age
127          */
128         private Time getTime(long time) {
129                 return getTime(webInterface, time);
130         }
131
132         //
133         // STATIC METHODS
134         //
135
136         /**
137          * Returns the formatted relative time for a given time.
138          *
139          * @param webInterface
140          *            The Sone web interface (for l10n access)
141          * @param time
142          *            The time to format the difference from (in milliseconds)
143          * @return The formatted age
144          */
145         public static Time getTime(WebInterface webInterface, long time) {
146                 if (time == 0) {
147                         return new Time(webInterface.getL10n().getString("View.Sone.Text.UnknownDate"), TimeUnit.HOURS.toMillis(12));
148                 }
149                 long age = System.currentTimeMillis() - time;
150                 String text;
151                 long refresh;
152                 if (age < 0) {
153                         text = webInterface.getL10n().getDefaultString("View.Time.InTheFuture");
154                         refresh = TimeUnit.MINUTES.toMillis(5);
155                 } else if (age < TimeUnit.SECONDS.toMillis(20)) {
156                         text = webInterface.getL10n().getDefaultString("View.Time.AFewSecondsAgo");
157                         refresh = TimeUnit.SECONDS.toMillis(10);
158                 } else if (age < TimeUnit.SECONDS.toMillis(45)) {
159                         text = webInterface.getL10n().getString("View.Time.HalfAMinuteAgo");
160                         refresh = TimeUnit.SECONDS.toMillis(20);
161                 } else if (age < TimeUnit.SECONDS.toMillis(90)) {
162                         text = webInterface.getL10n().getString("View.Time.AMinuteAgo");
163                         refresh = TimeUnit.MINUTES.toMillis(1);
164                 } else if (age < TimeUnit.MINUTES.toMillis(30)) {
165                         text = webInterface.getL10n().getString("View.Time.XMinutesAgo", "min", String.valueOf(TimeUnit.MILLISECONDS.toMinutes(age + TimeUnit.SECONDS.toMillis(30))));
166                         refresh = TimeUnit.MINUTES.toMillis(1);
167                 } else if (age < TimeUnit.MINUTES.toMillis(45)) {
168                         text = webInterface.getL10n().getString("View.Time.HalfAnHourAgo");
169                         refresh = TimeUnit.MINUTES.toMillis(10);
170                 } else if (age < TimeUnit.MINUTES.toMillis(90)) {
171                         text = webInterface.getL10n().getString("View.Time.AnHourAgo");
172                         refresh = TimeUnit.HOURS.toMillis(1);
173                 } else if (age < TimeUnit.HOURS.toMillis(21)) {
174                         text = webInterface.getL10n().getString("View.Time.XHoursAgo", "hour", String.valueOf(TimeUnit.MILLISECONDS.toHours(age + TimeUnit.MINUTES.toMillis(30))));
175                         refresh = TimeUnit.HOURS.toMillis(1);
176                 } else if (age < TimeUnit.HOURS.toMillis(42)) {
177                         text = webInterface.getL10n().getString("View.Time.ADayAgo");
178                         refresh = TimeUnit.DAYS.toMillis(1);
179                 } else if (age < TimeUnit.DAYS.toMillis(6)) {
180                         text = webInterface.getL10n().getString("View.Time.XDaysAgo", "day", String.valueOf(TimeUnit.MILLISECONDS.toDays(age + TimeUnit.HOURS.toMillis(12))));
181                         refresh = TimeUnit.DAYS.toMillis(1);
182                 } else if (age < TimeUnit.DAYS.toMillis(11)) {
183                         text = webInterface.getL10n().getString("View.Time.AWeekAgo");
184                         refresh = TimeUnit.DAYS.toMillis(1);
185                 } else if (age < TimeUnit.DAYS.toMillis(28)) {
186                         text = webInterface.getL10n().getString("View.Time.XWeeksAgo", "week", String.valueOf((TimeUnit.MILLISECONDS.toHours(age) + 84) / (7 * 24)));
187                         refresh = TimeUnit.DAYS.toMillis(1);
188                 } else if (age < TimeUnit.DAYS.toMillis(42)) {
189                         text = webInterface.getL10n().getString("View.Time.AMonthAgo");
190                         refresh = TimeUnit.DAYS.toMillis(1);
191                 } else if (age < TimeUnit.DAYS.toMillis(330)) {
192                         text = webInterface.getL10n().getString("View.Time.XMonthsAgo", "month", String.valueOf((TimeUnit.MILLISECONDS.toDays(age) + 15) / 30));
193                         refresh = TimeUnit.DAYS.toMillis(1);
194                 } else if (age < TimeUnit.DAYS.toMillis(540)) {
195                         text = webInterface.getL10n().getString("View.Time.AYearAgo");
196                         refresh = TimeUnit.DAYS.toMillis(7);
197                 } else {
198                         text = webInterface.getL10n().getString("View.Time.XYearsAgo", "year", String.valueOf((long) ((TimeUnit.MILLISECONDS.toDays(age) + 182.64) / 365.28)));
199                         refresh = TimeUnit.DAYS.toMillis(7);
200                 }
201                 return new Time(text, refresh);
202         }
203
204         /**
205          * Container for a formatted time.
206          *
207          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
208          */
209         public static class Time {
210
211                 /** The formatted time. */
212                 private final String text;
213
214                 /** The time after which to refresh the time. */
215                 private final long refresh;
216
217                 /**
218                  * Creates a new formatted time container.
219                  *
220                  * @param text
221                  *            The formatted time
222                  * @param refresh
223                  *            The time after which to refresh the time (in milliseconds)
224                  */
225                 public Time(String text, long refresh) {
226                         this.text = text;
227                         this.refresh = refresh;
228                 }
229
230                 /**
231                  * Returns the formatted time.
232                  *
233                  * @return The formatted time
234                  */
235                 public String getText() {
236                         return text;
237                 }
238
239                 /**
240                  * Returns the time after which to refresh the time.
241                  *
242                  * @return The time after which to refresh the time (in milliseconds)
243                  */
244                 public long getRefresh() {
245                         return refresh;
246                 }
247
248                 /**
249                  * {@inheritDoc}
250                  */
251                 @Override
252                 public String toString() {
253                         return text;
254                 }
255
256         }
257
258 }