17935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/*
27935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert******************************************************************************
37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* Copyright (C) 2007-2014, International Business Machines Corporation and   *
47935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert* others. All Rights Reserved.                                               *
57935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert******************************************************************************
67935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert*/
77935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
87935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.impl.duration;
97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Date;
117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TimeZone;
127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/**
147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Core implementation class for DurationFormatter.
157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */
167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertclass BasicDurationFormatter implements DurationFormatter {
177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  private PeriodFormatter formatter;
187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  private PeriodBuilder builder;
197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  private DateFormatter fallback;
207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  private long fallbackLimit;
217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  private String localeName;
227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  private TimeZone timeZone;
237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  /**
257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert   * Creates a basic duration formatter with the given formatter,
267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert   * builder, and fallback.  It's up to the caller to ensure that
277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert   * the locales and timezones of these are in sync.
287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert   */
297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  public BasicDurationFormatter(PeriodFormatter formatter,
307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                PeriodBuilder builder,
317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                DateFormatter fallback,
327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                long fallbackLimit) {
337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.formatter = formatter;
347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.builder = builder;
357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.fallback = fallback;
367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.fallbackLimit = fallbackLimit < 0 ? 0 : fallbackLimit;
377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  protected BasicDurationFormatter(PeriodFormatter formatter,
407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                   PeriodBuilder builder,
417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                   DateFormatter fallback,
427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                   long fallbackLimit,
437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                   String localeName,
447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                   TimeZone timeZone) {
457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.formatter = formatter;
467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.builder = builder;
477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.fallback = fallback;
487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.fallbackLimit = fallbackLimit;
497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.localeName = localeName;
507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    this.timeZone = timeZone;
517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  public String formatDurationFromNowTo(Date targetDate) {
547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    long now = System.currentTimeMillis();
557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    long duration = targetDate.getTime() - now;
567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return formatDurationFrom(duration, now);
577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  public String formatDurationFromNow(long duration) {
607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return formatDurationFrom(duration, System.currentTimeMillis());
617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  public String formatDurationFrom(long duration, long referenceDate) {
647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    String s = doFallback(duration, referenceDate);
657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    if (s == null) {
667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      Period p = doBuild(duration, referenceDate);
677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      s = doFormat(p);
687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return s;
707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  public DurationFormatter withLocale(String locName) {
737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    if (!locName.equals(localeName)) {
747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      PeriodFormatter newFormatter = formatter.withLocale(locName);
757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      PeriodBuilder newBuilder = builder.withLocale(locName);
767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      DateFormatter newFallback = fallback == null
777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          ? null
787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          : fallback.withLocale(locName);
797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      return new BasicDurationFormatter(newFormatter, newBuilder,
807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        newFallback, fallbackLimit,
817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        locName, timeZone);
827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return this;
847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  public DurationFormatter withTimeZone(TimeZone tz) {
877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    if (!tz.equals(timeZone)) {
887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      PeriodBuilder newBuilder = builder.withTimeZone(tz);
897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      DateFormatter newFallback = fallback == null
907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          ? null
917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert          : fallback.withTimeZone(tz);
927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      return new BasicDurationFormatter(formatter, newBuilder,
937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        newFallback, fallbackLimit,
947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert                                        localeName, tz);
957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return this;
977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  protected String doFallback(long duration, long referenceDate) {
1007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    if (fallback != null
1017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        && fallbackLimit > 0
1027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert        && Math.abs(duration) >= fallbackLimit) {
1037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      return fallback.format(referenceDate + duration);
1047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return null;
1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  protected Period doBuild(long duration, long referenceDate) {
1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return builder.createWithReferenceDate(duration, referenceDate);
1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert
1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  protected String doFormat(Period period) {
1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    if (!period.isSet()) {
1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert      throw new IllegalArgumentException("period is not set");
1157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    }
1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert    return formatter.format(period);
1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert  }
1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert}
119