package de.tud.kom.socom.web.client.util;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import de.tud.kom.socom.web.client.sharedmodels.SimpleEntry;
/** provides some methods to convert absolute Date or Time objects to relative String representations
*
* @author jkonert
*
*/
public abstract class DateTimeUtils
{
public static enum Units
{ // in future change it to support months and years as well.. by using Date and Calendar objects..
DAYS(null,1),
HOURS(DAYS,24),
MINUTES(HOURS,60),
SECONDS(MINUTES,60),
MILLISECONDS(SECONDS, 1000);
private Units nextUnit;
private int factor;
private Units(Units nextUnit, int factor)
{
this.nextUnit = nextUnit;
this.factor = factor;
}
/** may return NULL if end of units is reached
*
* @return
*/
public Units getNextUnit() {
return nextUnit;
}
public int getFactor() {
return factor;
}
/** returns the value converted to nextUnit
*
* @param value
* @return
*/
public long toNextUnit(long value)
{
return (value/getFactor());
}
/** returns the rest of this current Unit by subtracting all values of nextUnit() from value
*
* @param value
* @return
*/
public long toNextUnitRest(long value)
{
return value - (toNextUnit(value)*getFactor());
}
public static Units getMAXUnit()
{
return DAYS;
}
}
private static final Map<Units, String[]> unitsDE = new HashMap<Units, String[]>();
static
{
unitsDE.put(Units.MILLISECONDS, new String[]{" Millisekunden", " Millisekunde", "ms","ms"});
unitsDE.put(Units.SECONDS, new String[]{" Sekunden", " Sekunde", " sek", "s"});
unitsDE.put(Units.MINUTES, new String[]{" Minuten", " Minute", "min", "m"});
unitsDE.put(Units.HOURS, new String[]{" Stunden", " Stunde", " Std","h"});
unitsDE.put(Units.DAYS, new String[]{" Tage", " Tag", " Tage", "d"});
}
private static final String fewDE = "wenigen";
private static final String LONGSEPERATOR = ", ";
private static final String SHORTSEPERATOR = " ";
/** only supports GERMAN output by now..
* returns a String encoding the given date with two units relatively to now(). e.g. ("12 Minuten, 1 Sekunde").
*
* */
public static final String toStringRelative(Date date)
{
//FIXME returns something like: "wenigen Minuten, 21 Sekunden." or "39 Minuten, wenigen Sekunden."
return toStringRelative(date, new int[] {0,1}, LONGSEPERATOR, true);
}
/** only supports GERMAN output by now..
* returns a String encoding the given date with two units relatively to now(). e.g. ("12 Min, 1 Sek").
*
* */
public static String toShortStringRelative(Date date)
{
return toStringRelative(date, new int[] {2,2}, LONGSEPERATOR, false);
}
/** only supports GERMAN output by now..
* returns a String encoding the given date with two units relatively to now(). e.g. ("12m 1s").
*
* */
public static String toVeryShortStringRelative(Date date)
{
return toStringRelative(date, new int[] {3,3}, SHORTSEPERATOR, false);
}
/**
*
* @param date
* @param indexesToUse two numbers as array: first number indicates which index of Unit strings to use for plural forms, the second for single forms (e.g. Milliseconds and Millisecond)
* @return
*/
private static final String toStringRelative(Date date, int[] indexesToUse, String seperator, boolean allowTexts)
{
long diff = (new Date().getTime()-date.getTime());
if (diff < 0) diff *= (-1);
SimpleEntry<Units,Long> startEntry = new SimpleEntry<Units, Long>(Units.SECONDS, Units.MILLISECONDS.toNextUnit(diff));
@SuppressWarnings("unchecked")
SimpleEntry<Units, Long>[] result = new SimpleEntry[2];
result[0] = startEntry;
result = getTwoBiggestUnits(result);
StringBuilder sb = new StringBuilder();
if (result[0] != null)
{
formatResult(result[0], indexesToUse, allowTexts, sb);
}
if (result[1] != null)
{
sb.append(seperator);
formatResult(result[1], indexesToUse, allowTexts, sb);
}
return sb.toString();
}
private static void formatResult(SimpleEntry<Units, Long> simpleEntry, int[] indexesToUse, boolean allowTexts,
StringBuilder sb) {
long value = simpleEntry.getValue();
if (value == 0)
{
sb.append(simpleEntry.getValue());
sb.append(unitsDE.get(simpleEntry.getKey())[indexesToUse[0]]);
}
else if (simpleEntry.getValue() == 1)
{
sb.append(simpleEntry.getValue());
sb.append(unitsDE.get(simpleEntry.getKey())[indexesToUse[1]]);
}
else if (allowTexts && value < 4)
{
sb.append(fewDE);
sb.append(unitsDE.get(simpleEntry.getKey())[indexesToUse[0]]);
}
else
{
sb.append(simpleEntry.getValue());
sb.append(unitsDE.get(simpleEntry.getKey())[indexesToUse[0]]);
}
}
private static SimpleEntry<Units, Long>[] getTwoBiggestUnits(SimpleEntry<Units, Long>[] simpleEntries) {
SimpleEntry<Units, Long> e1 = simpleEntries[0];
// there is nothing to convert to bigger Unit(s)
if (e1 == null || e1.getValue() == 0) return simpleEntries;
// we reached the max of units or the smaller unit is already zero
if (simpleEntries[1] != null && simpleEntries[1].getKey().equals(Units.getMAXUnit())) return simpleEntries;
Units current = e1.getKey();
Long nextValue = current.toNextUnit(e1.getValue());
// it makes no sense to calculate higher units..
if (nextValue == 0 || current.getNextUnit() == null) return simpleEntries;
SimpleEntry<Units, Long> e2 = new SimpleEntry<Units,Long>(current.getNextUnit(),nextValue);
long rest = current.toNextUnitRest(e1.getValue());
e1.setValue(rest);
// shift and add
simpleEntries[1] = e1;
simpleEntries[0] = e2;
return getTwoBiggestUnits(simpleEntries);
}
}