/**
* Copyright 2008 Mathias Doenitz, http://lis.to/
*
* This file is part of the lis.to java desktop client. The lis.to java desktop client is free software: you can
* redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* The lis.to java desktop client is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with the lis.to java desktop client.
* If not, see http://www.gnu.org/licenses/
*/
package listo.client;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import listo.utils.exceptions.IllegalFormattingException;
import listo.utils.guice.CalendarDayScoped;
import listo.utils.types.Cal;
import listo.utils.types.DateTime;
import org.apache.commons.lang.StringUtils;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@CalendarDayScoped
public class Formatter {
private static final Pattern PATTERN_ON_TIME = Pattern.compile(
"\\A(?:on.*)|(?:0)", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_MIN_BEFORE = Pattern.compile(
"\\A(?:-(\\d+))|(?:(\\d+).*before)", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_MIN_AFTER = Pattern.compile(
"\\A(?:\\+(\\d+))|(?:(\\d+).*after)", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_MIN_AGO = Pattern.compile(
"\\A(?:\\-\\-(\\d+))|(?:(\\d+).*ago)", Pattern.CASE_INSENSITIVE);
private static final Pattern PATTERN_IN_MIN = Pattern.compile(
"\\A(?:\\+\\+(\\d+))|(?:in\\s(\\d+).*)", Pattern.CASE_INSENSITIVE);
private final Cal today = new Cal().beginningOfDay();
private final DateFormat dateFormat;
private final DateFormat shortDateFormat;
private final String[] weekdays;
private final String[] shortWeekdays;
private final List<String> next9Text;
private final List<String> next9TextLowered = Lists.newArrayList();
private final List<DateTime> next9Date = Lists.newArrayList();
@Inject
public Formatter(Lang lang) {
dateFormat = lang.getDateFormat();
shortDateFormat = lang.getShortDateFormat();
next9Text = Lists.newArrayList(lang.get("days.today"), lang.get("days.tomorrow"));
weekdays = StringUtils.split(lang.get("days.weekdays"), ',');
shortWeekdays = StringUtils.split(lang.get("days.shortWeekdays"), ',');
int today = this.today.get(Calendar.DAY_OF_WEEK);
int todayIx = toDaysIndex(today);
int todayPlus1 = this.today.add(Calendar.DATE, 1).get(Calendar.DAY_OF_WEEK);
int todayPlus1Ix = toDaysIndex(todayPlus1);
int todayPlus2 = this.today.add(Calendar.DATE, 2).get(Calendar.DAY_OF_WEEK);
int todayPlus2Ix = toDaysIndex(todayPlus2);
next9Text.addAll(Arrays.asList(weekdays).subList(todayPlus2Ix, weekdays.length));
next9Text.addAll(Arrays.asList(weekdays).subList(0, todayIx));
next9Text.add("Next_" + weekdays[todayIx]);
next9Text.add("Next_" + weekdays[todayPlus1Ix]);
for (int i = 0; i < next9Text.size(); i++) {
next9Date.add(this.today.add(Calendar.DATE, i).getDateTime());
next9TextLowered.add(next9Text.get(i).toLowerCase());
}
}
private static int toDaysIndex(int calendarDOW) {
return (calendarDOW + 7 - Calendar.MONDAY) % 7;
}
public String toDowString(DateTime dateTime) {
return toDowString(new Cal(dateTime));
}
public String toDowString(Cal cal) {
return weekdays[toDaysIndex(cal.get(Calendar.DAY_OF_WEEK))];
}
public String toShortDowString(DateTime dateTime) {
return toShortDowString(new Cal(dateTime));
}
public String toShortDowString(Cal cal) {
return shortWeekdays[toDaysIndex(cal.get(Calendar.DAY_OF_WEEK))];
}
public DateTime fromNext9DaysString(String text) {
int ix = next9TextLowered.indexOf(text.toLowerCase());
return ix >= 0 ? next9Date.get(ix) : null;
}
public String toNext9DaysString(DateTime dateTime) {
return toNext9DaysString(new Cal(dateTime));
}
public String toNext9DaysString(Cal cal) {
int ix = next9Date.indexOf(cal.beginningOfDay().getDateTime());
return ix >= 0 ? next9Text.get(ix) : null;
}
private String toShort(DateTime dateTime) {
return dateTime.format(
today.add(Calendar.DATE, -90).before(dateTime) &&
today.add(Calendar.DATE, 180).after(dateTime) ? shortDateFormat : dateFormat
);
}
public String toShortDateString(DateTime dateTime) {
String option = toNext9DaysString(dateTime);
return option != null ? option : toShort(dateTime);
}
public String toLongDateString(DateTime dateTime) {
String text = toNext9DaysString(dateTime);
return text != null ?
String.format("%s (%s)", text, dateTime.format(shortDateFormat)) :
String.format("%s (%s)", toShort(dateTime), toShortDowString(dateTime));
}
public DateTime fromShortDateString(String text) {
DateTime option = fromNext9DaysString(text);
if (option != null) return option;
// try a full parse
try {
return DateTime.parse(text, dateFormat);
} catch (Exception e) {
// ignore
}
// we might don't have the year in the string, so try to deduce it
int thisYear = today.get(Calendar.YEAR);
Cal cal = new Cal(DateTime.parse(text, shortDateFormat)).set(Calendar.YEAR, thisYear);
if (today.add(Calendar.DATE, -90).after(cal)) return cal.set(Calendar.YEAR, thisYear + 1).getDateTime();
if (today.add(Calendar.DATE, 180).before(cal)) return cal.set(Calendar.YEAR, thisYear - 1).getDateTime();
return cal.getDateTime();
}
public String toLongReminderString(DateTime due, Integer reminder) {
if (reminder == null) return null;
Integer inMin = null;
if (due != null) {
DateTime popupTime = new Cal(due).add(Calendar.MINUTE, reminder).getDateTime();
inMin = (int) ((popupTime.getTicks() - new DateTime().getTicks()) / (1000 * 60));
}
if (reminder < 0 && (inMin == null || inMin >= 60 || inMin < -60)) return String.format("%s min before", -reminder);
if (reminder == 0 && (inMin == null || inMin >= 60 || inMin < -60)) return "on time";
if (reminder > 0 && (inMin == null || inMin > reminder || inMin < -60)) return String.format("%s min after", reminder);
if (inMin == null) throw new IllegalStateException();
if (inMin < 0) return String.format("%s min ago", -inMin);
return String.format("in %s min", inMin);
}
public String toShortReminderString(DateTime due, Integer reminder) {
if (reminder == null) return null;
Integer inMin = null;
if (due != null) {
DateTime popupTime = new Cal(due).add(Calendar.MINUTE, reminder).getDateTime();
inMin = (int) ((popupTime.getTicks() - new DateTime().getTicks()) / (1000 * 60));
}
if (reminder < 0 && (inMin == null || inMin >= 60 || inMin < -60)) return String.format("-%s", -reminder);
if (reminder == 0 && (inMin == null || inMin >= 60 || inMin < -60)) return "0";
if (reminder > 0 && (inMin == null || inMin > reminder || inMin < -60)) return String.format("-%s", reminder);
if (inMin == null) throw new IllegalStateException();
if (inMin < 0) return String.format("--%s", -inMin);
return String.format("++%s", inMin);
}
public Integer fromReminderString(String text, DateTime due) {
if (StringUtils.isEmpty(text)) return null;
text = text.toLowerCase();
if (PATTERN_ON_TIME.matcher(text).matches()) return 0;
try {
Matcher matcher = PATTERN_MIN_BEFORE.matcher(text);
if (matcher.matches()) {
return -Integer.parseInt(matcher.group(1) != null ? matcher.group(1) : matcher.group(2));
}
matcher = PATTERN_MIN_AFTER.matcher(text);
if (matcher.matches()) {
return Integer.parseInt(matcher.group(1) != null ? matcher.group(1) : matcher.group(2));
}
matcher = PATTERN_MIN_AGO.matcher(text);
if (matcher.matches()) {
String match = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
DateTime popupTime = new Cal().add(Calendar.MINUTE, -Integer.parseInt(match)).getDateTime();
return (int) ((popupTime.getTicks() - due.getTicks()) / (1000 * 60)) + 1;
}
matcher = PATTERN_IN_MIN.matcher(text);
if (matcher.matches()) {
String match = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
DateTime popupTime = new Cal().add(Calendar.MINUTE, Integer.parseInt(match)).getDateTime();
return (int) ((popupTime.getTicks() - due.getTicks()) / (1000 * 60)) + 1;
}
}
catch (NumberFormatException e) {
// ignore
}
throw new IllegalFormattingException();
}
}
|