1/*
2******************************************************************************
3* Copyright (C) 2007-2009, International Business Machines Corporation and   *
4* others. All Rights Reserved.                                               *
5******************************************************************************
6*/
7
8package com.ibm.icu.impl.duration;
9
10import java.util.Locale;
11import java.util.TimeZone;
12
13/**
14 * Abstract factory object used to create DurationFormatters.
15 * DurationFormatters are immutable once created.
16 * <p>
17 * Setters on the factory mutate the factory and return it,
18 * for chaining.
19 * <p>
20 * Subclasses override getFormatter to return a custom
21 * DurationFormatter.
22 */
23class BasicDurationFormatterFactory implements DurationFormatterFactory {
24  private BasicPeriodFormatterService ps;
25  private PeriodFormatter formatter;
26  private PeriodBuilder builder;
27  private DateFormatter fallback;
28  private long fallbackLimit;
29  private String localeName;
30  private TimeZone timeZone;
31  private BasicDurationFormatter f; // cache
32
33  /**
34   * Create a default formatter for the current locale and time zone.
35   */
36  BasicDurationFormatterFactory(BasicPeriodFormatterService ps) {
37    this.ps = ps;
38    this.localeName = Locale.getDefault().toString();
39    this.timeZone = TimeZone.getDefault();
40  }
41
42  /**
43   * Set the period formatter used by the factory.  New formatters created
44   * with this factory will use the given period formatter.
45   *
46   * @return this BasicDurationFormatterFactory
47   */
48  public DurationFormatterFactory setPeriodFormatter(
49      PeriodFormatter formatter) {
50    if (formatter != this.formatter) {
51      this.formatter = formatter;
52      reset();
53    }
54    return this;
55  }
56
57  /**
58   * Set the builder used by the factory.  New formatters created
59   * with this factory will use the given locale.
60   *
61   * @param builder the builder to use
62   * @return this BasicDurationFormatterFactory
63   */
64  public DurationFormatterFactory setPeriodBuilder(PeriodBuilder builder) {
65    if (builder != this.builder) {
66      this.builder = builder;
67      reset();
68    }
69    return this;
70  }
71
72  /**
73   * Set a fallback formatter for durations over a given limit.
74   *
75   * @param fallback the fallback formatter to use, or null
76   * @return this BasicDurationFormatterFactory
77   */
78  public DurationFormatterFactory setFallback(DateFormatter fallback) {
79    boolean doReset = fallback == null
80        ? this.fallback != null
81        : !fallback.equals(this.fallback);
82    if (doReset) {
83      this.fallback = fallback;
84      reset();
85    }
86    return this;
87  }
88
89  /**
90   * Set a fallback limit for durations over a given limit.
91   *
92   * @param fallbackLimit the fallback limit to use, or 0 if none is desired.
93   * @return this BasicDurationFormatterFactory
94   */
95  public DurationFormatterFactory setFallbackLimit(long fallbackLimit) {
96    if (fallbackLimit < 0) {
97      fallbackLimit = 0;
98    }
99    if (fallbackLimit != this.fallbackLimit) {
100      this.fallbackLimit = fallbackLimit;
101      reset();
102    }
103    return this;
104  }
105
106  /**
107   * Set the name of the locale that will be used when
108   * creating new formatters.
109   *
110   * @param localeName the name of the Locale
111   * @return this BasicDurationFormatterFactory
112   */
113  public DurationFormatterFactory setLocale(String localeName) {
114    if (!localeName.equals(this.localeName)) {
115      this.localeName = localeName;
116      if (builder != null) {
117          builder = builder.withLocale(localeName);
118      }
119      if (formatter != null) {
120          formatter = formatter.withLocale(localeName);
121      }
122      reset();
123    }
124    return this;
125  }
126
127  /**
128   * Set the name of the locale that will be used when
129   * creating new formatters.
130   *
131   * @param timeZone The time zone to use.
132   * @return this BasicDurationFormatterFactory
133   */
134  public DurationFormatterFactory setTimeZone(TimeZone timeZone) {
135    if (!timeZone.equals(this.timeZone)) {
136      this.timeZone = timeZone;
137      if (builder != null) {
138          builder = builder.withTimeZone(timeZone);
139      }
140      reset();
141    }
142    return this;
143  }
144
145  /**
146   * Return a formatter based on this factory's current settings.
147   *
148   * @return a BasicDurationFormatter
149   */
150  public DurationFormatter getFormatter() {
151    if (f == null) {
152      if (fallback != null) {
153        fallback = fallback.withLocale(localeName).withTimeZone(timeZone);
154      }
155      formatter = getPeriodFormatter();
156      builder = getPeriodBuilder();
157
158      f = createFormatter();
159    }
160    return f;
161  }
162
163  /**
164   * Return the current period formatter.
165   *
166   * @return the current period formatter
167   */
168  public PeriodFormatter getPeriodFormatter() {
169    if (formatter == null) {
170      formatter = ps.newPeriodFormatterFactory()
171          .setLocale(localeName)
172          .getFormatter();
173    }
174    return formatter;
175  }
176
177  /**
178   * Return the current builder.
179   *
180   * @return the current builder
181   */
182  public PeriodBuilder getPeriodBuilder() {
183    if (builder == null) {
184      builder = ps.newPeriodBuilderFactory()
185          .setLocale(localeName)
186          .setTimeZone(timeZone)
187          .getSingleUnitBuilder();
188    }
189    return builder;
190  }
191
192  /**
193   * Return the current fallback formatter.
194   *
195   * @return the fallback formatter, or null if there is no fallback
196   * formatter
197   */
198  public DateFormatter getFallback() {
199    return fallback;
200  }
201
202  /**
203   * Return the current fallback formatter limit
204   *
205   * @return the limit, or 0 if there is no fallback.
206   */
207  public long getFallbackLimit() {
208    return fallback == null ? 0 : fallbackLimit;
209  }
210
211  /**
212   * Return the current locale name.
213   *
214   * @return the current locale name
215   */
216  public String getLocaleName() {
217    return localeName;
218  }
219
220  /**
221   * Return the current locale name.
222   *
223   * @return the current locale name
224   */
225  public TimeZone getTimeZone() {
226    return timeZone;
227  }
228
229  /**
230   * Create the formatter.  All local fields are already initialized.
231   */
232  protected BasicDurationFormatter createFormatter() {
233    return new BasicDurationFormatter(formatter, builder, fallback,
234                                      fallbackLimit, localeName,
235                                      timeZone);
236  }
237
238  /**
239   * Clear the cached formatter.  Subclasses must call this if their
240   * state has changed. This is automatically invoked by setBuilder,
241   * setFormatter, setFallback, setLocaleName, and setTimeZone
242   */
243  protected void reset() {
244    f = null;
245  }
246}
247