Merge branch 'release-0.6.6'
[Sone.git] / src / main / java / net / pterodactylus / sone / web / ajax / GetTimesAjaxPage.java
1 /*
2  * Sone - GetTimesAjaxPage.java - Copyright © 2010–2011 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 java.text.DateFormat;
21 import java.text.SimpleDateFormat;
22 import java.util.Date;
23
24 import net.pterodactylus.sone.data.Post;
25 import net.pterodactylus.sone.data.Reply;
26 import net.pterodactylus.sone.web.WebInterface;
27 import net.pterodactylus.util.json.JsonObject;
28 import net.pterodactylus.util.number.Digits;
29
30 /**
31  * Ajax page that returns a formatted, relative timestamp for replies or posts.
32  *
33  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
34  */
35 public class GetTimesAjaxPage extends JsonPage {
36
37         /** Formatter for tooltips. */
38         private static final DateFormat dateFormat = new SimpleDateFormat("MMM d, yyyy, HH:mm:ss");
39
40         /**
41          * Creates a new get times AJAX page.
42          *
43          * @param webInterface
44          *            The Sone web interface
45          */
46         public GetTimesAjaxPage(WebInterface webInterface) {
47                 super("getTimes.ajax", webInterface);
48         }
49
50         /**
51          * {@inheritDoc}
52          */
53         @Override
54         protected JsonObject createJsonObject(Request request) {
55                 long now = System.currentTimeMillis();
56                 String allIds = request.getHttpRequest().getParam("posts");
57                 JsonObject postTimes = new JsonObject();
58                 if (allIds.length() > 0) {
59                         String[] ids = allIds.split(",");
60                         for (String id : ids) {
61                                 Post post = webInterface.getCore().getPost(id, false);
62                                 if (post == null) {
63                                         continue;
64                                 }
65                                 JsonObject postTime = new JsonObject();
66                                 Time time = getTime(post.getTime());
67                                 postTime.put("timeText", time.getText());
68                                 postTime.put("refreshTime", time.getRefresh() / Time.SECOND);
69                                 postTime.put("tooltip", dateFormat.format(new Date(post.getTime())));
70                                 postTimes.put(id, postTime);
71                         }
72                 }
73                 JsonObject replyTimes = new JsonObject();
74                 allIds = request.getHttpRequest().getParam("replies");
75                 if (allIds.length() > 0) {
76                         String[] ids = allIds.split(",");
77                         for (String id : ids) {
78                                 Reply reply = webInterface.getCore().getReply(id, false);
79                                 if (reply == null) {
80                                         continue;
81                                 }
82                                 long age = now - reply.getTime();
83                                 JsonObject replyTime = new JsonObject();
84                                 Time time = getTime(age);
85                                 replyTime.put("timeText", time.getText());
86                                 replyTime.put("refreshTime", time.getRefresh() / Time.SECOND);
87                                 replyTime.put("tooltip", dateFormat.format(new Date(reply.getTime())));
88                                 replyTimes.put(id, replyTime);
89                         }
90                 }
91                 return createSuccessJsonObject().put("postTimes", postTimes).put("replyTimes", replyTimes);
92         }
93
94         /**
95          * {@inheritDoc}
96          */
97         @Override
98         protected boolean needsFormPassword() {
99                 return false;
100         }
101
102         /**
103          * {@inheritDoc}
104          */
105         @Override
106         protected boolean requiresLogin() {
107                 return false;
108         }
109
110         //
111         // PRIVATE METHODS
112         //
113
114         /**
115          * Returns the formatted relative time for a given time.
116          *
117          * @param time
118          *            The time to format the difference from (in milliseconds)
119          * @return The formatted age
120          */
121         private Time getTime(long time) {
122                 return getTime(webInterface, time);
123         }
124
125         //
126         // STATIC METHODS
127         //
128
129         /**
130          * Returns the formatted relative time for a given time.
131          *
132          * @param webInterface
133          *            The Sone web interface (for l10n access)
134          * @param time
135          *            The time to format the difference from (in milliseconds)
136          * @return The formatted age
137          */
138         public static Time getTime(WebInterface webInterface, long time) {
139                 if (time == 0) {
140                         return new Time(webInterface.getL10n().getString("View.Sone.Text.UnknownDate"), 12 * Time.HOUR);
141                 }
142                 long age = System.currentTimeMillis() - time;
143                 String text;
144                 long refresh;
145                 if (age < 0) {
146                         text = webInterface.getL10n().getDefaultString("View.Time.InTheFuture");
147                         refresh = 5 * Time.MINUTE;
148                 } else if (age < 20 * Time.SECOND) {
149                         text = webInterface.getL10n().getDefaultString("View.Time.AFewSecondsAgo");
150                         refresh = 10 * Time.SECOND;
151                 } else if (age < 45 * Time.SECOND) {
152                         text = webInterface.getL10n().getString("View.Time.HalfAMinuteAgo");
153                         refresh = 20 * Time.SECOND;
154                 } else if (age < 90 * Time.SECOND) {
155                         text = webInterface.getL10n().getString("View.Time.AMinuteAgo");
156                         refresh = Time.MINUTE;
157                 } else if (age < 30 * Time.MINUTE) {
158                         text = webInterface.getL10n().getString("View.Time.XMinutesAgo", "min", String.valueOf((int) (Digits.round(age, Time.MINUTE) / Time.MINUTE)));
159                         refresh = 1 * Time.MINUTE;
160                 } else if (age < 45 * Time.MINUTE) {
161                         text = webInterface.getL10n().getString("View.Time.HalfAnHourAgo");
162                         refresh = 10 * Time.MINUTE;
163                 } else if (age < 90 * Time.MINUTE) {
164                         text = webInterface.getL10n().getString("View.Time.AnHourAgo");
165                         refresh = Time.HOUR;
166                 } else if (age < 21 * Time.HOUR) {
167                         text = webInterface.getL10n().getString("View.Time.XHoursAgo", "hour", String.valueOf((int) (Digits.round(age, Time.HOUR) / Time.HOUR)));
168                         refresh = Time.HOUR;
169                 } else if (age < 42 * Time.HOUR) {
170                         text = webInterface.getL10n().getString("View.Time.ADayAgo");
171                         refresh = Time.DAY;
172                 } else if (age < 6 * Time.DAY) {
173                         text = webInterface.getL10n().getString("View.Time.XDaysAgo", "day", String.valueOf((int) (Digits.round(age, Time.DAY) / Time.DAY)));
174                         refresh = Time.DAY;
175                 } else if (age < 11 * Time.DAY) {
176                         text = webInterface.getL10n().getString("View.Time.AWeekAgo");
177                         refresh = Time.DAY;
178                 } else if (age < 4 * Time.WEEK) {
179                         text = webInterface.getL10n().getString("View.Time.XWeeksAgo", "week", String.valueOf((int) (Digits.round(age, Time.WEEK) / Time.WEEK)));
180                         refresh = Time.DAY;
181                 } else if (age < 6 * Time.WEEK) {
182                         text = webInterface.getL10n().getString("View.Time.AMonthAgo");
183                         refresh = Time.DAY;
184                 } else if (age < 11 * Time.MONTH) {
185                         text = webInterface.getL10n().getString("View.Time.XMonthsAgo", "month", String.valueOf((int) (Digits.round(age, Time.MONTH) / Time.MONTH)));
186                         refresh = Time.DAY;
187                 } else if (age < 18 * Time.MONTH) {
188                         text = webInterface.getL10n().getString("View.Time.AYearAgo");
189                         refresh = Time.WEEK;
190                 } else {
191                         text = webInterface.getL10n().getString("View.Time.XYearsAgo", "year", String.valueOf((int) (Digits.round(age, Time.YEAR) / Time.YEAR)));
192                         refresh = Time.WEEK;
193                 }
194                 return new Time(text, refresh);
195         }
196
197         /**
198          * Container for a formatted time.
199          *
200          * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
201          */
202         public static class Time {
203
204                 /** Number of milliseconds in a second. */
205                 private static final long SECOND = 1000;
206
207                 /** Number of milliseconds in a minute. */
208                 private static final long MINUTE = 60 * SECOND;
209
210                 /** Number of milliseconds in an hour. */
211                 private static final long HOUR = 60 * MINUTE;
212
213                 /** Number of milliseconds in a day. */
214                 private static final long DAY = 24 * HOUR;
215
216                 /** Number of milliseconds in a week. */
217                 private static final long WEEK = 7 * DAY;
218
219                 /** Number of milliseconds in a 30-day month. */
220                 private static final long MONTH = 30 * DAY;
221
222                 /** Number of milliseconds in a year. */
223                 private static final long YEAR = 365 * DAY;
224
225                 /** The formatted time. */
226                 private final String text;
227
228                 /** The time after which to refresh the time. */
229                 private final long refresh;
230
231                 /**
232                  * Creates a new formatted time container.
233                  *
234                  * @param text
235                  *            The formatted time
236                  * @param refresh
237                  *            The time after which to refresh the time (in milliseconds)
238                  */
239                 public Time(String text, long refresh) {
240                         this.text = text;
241                         this.refresh = refresh;
242                 }
243
244                 /**
245                  * Returns the formatted time.
246                  *
247                  * @return The formatted time
248                  */
249                 public String getText() {
250                         return text;
251                 }
252
253                 /**
254                  * Returns the time after which to refresh the time.
255                  *
256                  * @return The time after which to refresh the time (in milliseconds)
257                  */
258                 public long getRefresh() {
259                         return refresh;
260                 }
261
262                 /**
263                  * {@inheritDoc}
264                  */
265                 @Override
266                 public String toString() {
267                         return text;
268                 }
269
270         }
271
272 }