/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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. * * OpenFlexo 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 OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.toolbox; import java.text.ParseException; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import org.openflexo.kvc.KVCObject; import org.openflexo.xmlcode.StringConvertable; import org.openflexo.xmlcode.StringEncoder.Converter; public class Duration extends KVCObject implements StringConvertable<Duration>, Cloneable, Comparable<Duration> { public static final DurationStringConverter converter = new DurationStringConverter(); private long value; private DurationUnit unit; public enum DurationUnit implements Comparable<DurationUnit> { MILLIS, SECONDS, MINUTES, HOURS, DAYS, WEEKS, MONTHS, YEARS; public String getSymbol() { if (this == MILLIS) { return "ms"; } else if (this == SECONDS) { return "s"; } else if (this == MINUTES) { return "min"; } else if (this == HOURS) { return "h"; } else if (this == DAYS) { return "d"; } else if (this == WEEKS) { return "w"; } else if (this == MONTHS) { return "m"; } else if (this == YEARS) { return "y"; } return "?"; } public String getLocalizedKey() { if (this == MILLIS) { return "millisecond"; } else if (this == SECONDS) { return "second"; } else if (this == MINUTES) { return "minute"; } else if (this == HOURS) { return "hour"; } else if (this == DAYS) { return "day"; } else if (this == WEEKS) { return "week"; } else if (this == MONTHS) { return "month"; } else if (this == YEARS) { return "year"; } return "?"; } public int getCalendarField() { if (this == MILLIS) { return Calendar.MILLISECOND; } else if (this == SECONDS) { return Calendar.SECOND; } else if (this == MINUTES) { return Calendar.MINUTE; } else if (this == HOURS) { return Calendar.HOUR; } else if (this == DAYS) { return Calendar.DAY_OF_YEAR; } else if (this == WEEKS) { return Calendar.WEEK_OF_YEAR; } else if (this == MONTHS) { return Calendar.MONTH; } else if (this == YEARS) { return Calendar.YEAR; } return -1; } // assert this.ordinality > oppositUnit.ordinality public long getCardinalityOf(DurationUnit oppositeUnit) { if (this == MILLIS) { if (oppositeUnit == MILLIS) { return 1; } } else if (this == SECONDS) { if (oppositeUnit == MILLIS) { return 1000; } else if (oppositeUnit == SECONDS) { return 1; } } else if (this == MINUTES) { if (oppositeUnit == MILLIS) { return 60 * 1000; } else if (oppositeUnit == SECONDS) { return 60; } else if (oppositeUnit == MINUTES) { return 1; } } else if (this == HOURS) { if (oppositeUnit == MILLIS) { return 60 * 60 * 1000; } else if (oppositeUnit == SECONDS) { return 60 * 60; } else if (oppositeUnit == MINUTES) { return 60; } else if (oppositeUnit == HOURS) { return 1; } } else if (this == DAYS) { if (oppositeUnit == MILLIS) { return 24 * 60 * 60 * 1000; } else if (oppositeUnit == SECONDS) { return 24 * 60 * 60; } else if (oppositeUnit == MINUTES) { return 24 * 60; } else if (oppositeUnit == HOURS) { return 24; } else if (oppositeUnit == DAYS) { return 1; } } else if (this == WEEKS) { if (oppositeUnit == MILLIS) { return 7 * 24 * 60 * 60 * 1000; } else if (oppositeUnit == SECONDS) { return 7 * 24 * 60 * 60; } else if (oppositeUnit == MINUTES) { return 7 * 24 * 60; } else if (oppositeUnit == HOURS) { return 7 * 24; } else if (oppositeUnit == DAYS) { return 7; } else if (oppositeUnit == WEEKS) { return 1; } } else if (this == MONTHS) { if (oppositeUnit == MILLIS) { return 30 * 24 * 60 * 60 * 1000; } else if (oppositeUnit == SECONDS) { return 30 * 24 * 60 * 60; } else if (oppositeUnit == MINUTES) { return 30 * 24 * 60; } else if (oppositeUnit == HOURS) { return 30 * 24; } else if (oppositeUnit == DAYS) { return 30; } else if (oppositeUnit == WEEKS) { return 4; } else if (oppositeUnit == MONTHS) { return 1; } } else if (this == YEARS) { if (oppositeUnit == MILLIS) { return 365 * 24 * 60 * 60 * 1000; } else if (oppositeUnit == SECONDS) { return 365 * 24 * 60 * 60; } else if (oppositeUnit == MINUTES) { return 365 * 24 * 60; } else if (oppositeUnit == HOURS) { return 365 * 24; } else if (oppositeUnit == DAYS) { return 365; } else if (oppositeUnit == WEEKS) { return 52; } else if (oppositeUnit == MONTHS) { return 12; } else if (oppositeUnit == YEARS) { return 1; } } return -1; } } public Duration(long aValue, DurationUnit aUnit) { super(); this.value = aValue; this.unit = aUnit; } public Duration() { this(0, DurationUnit.SECONDS); } public boolean isValid() { return unit != null; } public String getStringRepresentation() { return getSerializationRepresentation(); } public String getSerializationRepresentation() { if (unit == null) { return ""; } return value + unit.getSymbol(); } @Override public String toString() { return getStringRepresentation(); } public static class DurationStringConverter extends Converter<Duration> { public DurationStringConverter() { super(Duration.class); } @Override public Duration convertFromString(String aValue) { try { return tryToConvertFromString(aValue); } catch (ParseException e) { // OK, abort return null; } } public Duration tryToConvertFromString(String aValue) throws ParseException { for (DurationUnit unit : DurationUnit.values()) { String unitSymbol = unit.getSymbol(); if (aValue.endsWith(unitSymbol)) { try { long value = Long.parseLong(aValue.substring(0, aValue.length() - unitSymbol.length())); return new Duration(value, unit); } catch (NumberFormatException e) { // OK, abort throw new ParseException("Cannot parse as a Duration: " + aValue, -1); } } } throw new ParseException("Cannot parse as a Duration: " + aValue, -1); } @Override public String convertToString(Duration value) { if (value == null) { return "null"; } return value.getSerializationRepresentation(); } } @Override public DurationStringConverter getConverter() { return converter; } public DurationUnit getUnit() { return unit; } public void setUnit(DurationUnit unit) { this.unit = unit; } public long getValue() { return value; } public void setValue(long value) { this.value = value; } @Override public boolean equals(Object obj) { if (obj instanceof Duration && obj != null) { return getSerializationRepresentation().equals(((Duration) obj).getSerializationRepresentation()); } return false; } @Override public int hashCode() { return getSerializationRepresentation().hashCode(); } @Override public Duration clone() { return new Duration(value, unit); } public static Date datePlusDuration(Date aDate, Duration aDuration) { GregorianCalendar calendar = new GregorianCalendar(Locale.getDefault()); calendar.setTime(aDate); calendar.add(aDuration.getUnit().getCalendarField(), (int) aDuration.getValue()); return calendar.getTime(); } public static Date dateMinusDuration(Date aDate, Duration aDuration) { GregorianCalendar calendar = new GregorianCalendar(Locale.getDefault()); calendar.setTime(aDate); calendar.add(aDuration.getUnit().getCalendarField(), -(int) aDuration.getValue()); return calendar.getTime(); } public static Duration dateMinusDate(Date aDate, Date anOtherDate) { // TODO: not implemented yet System.err.println("org.openflexo.toolbox.Duration.dateMinusDate(Date,Date) NOT IMPLEMENED YET"); return new Duration(1, DurationUnit.SECONDS); } public static Duration durationPlusDuration(Duration aDuration1, Duration aDuration2) { Duration minUnitDuration; Duration maxUnitDuration; if (aDuration1.getUnit().ordinal() <= aDuration2.getUnit().ordinal()) { minUnitDuration = aDuration1; maxUnitDuration = aDuration2; } else { minUnitDuration = aDuration2; maxUnitDuration = aDuration1; } return new Duration(minUnitDuration.getValue() + maxUnitDuration.getValue() * maxUnitDuration.getUnit().getCardinalityOf(minUnitDuration.getUnit()), minUnitDuration.getUnit()); } public static Duration durationMinusDuration(Duration aDuration1, Duration aDuration2) { Duration minUnitDuration; Duration maxUnitDuration; if (aDuration1.getUnit().ordinal() <= aDuration2.getUnit().ordinal()) { minUnitDuration = aDuration1; maxUnitDuration = aDuration2; } else { minUnitDuration = aDuration2; maxUnitDuration = aDuration1; } return new Duration(minUnitDuration.getValue() - maxUnitDuration.getValue() * maxUnitDuration.getUnit().getCardinalityOf(minUnitDuration.getUnit()), minUnitDuration.getUnit()); } public boolean lessThan(Duration aDuration) { return compareTo(aDuration) < 0; } public boolean lessOrEqualsThan(Duration aDuration) { return compareTo(aDuration) <= 0; } public boolean greaterThan(Duration aDuration) { return compareTo(aDuration) > 0; } public boolean greaterOrEqualsThan(Duration aDuration) { return compareTo(aDuration) >= 0; } @Override public int compareTo(Duration o) { int returned = getUnit().compareTo(o.getUnit()); if (returned != 0) { return returned; } return new Long(getValue()).compareTo(new Long(o.getValue())); } }