1 /* GENERATED SOURCE. DO NOT MODIFY. */
2 // © 2016 and later: Unicode, Inc. and others.
3 // License & terms of use: http://www.unicode.org/copyright.html#License
4 /*
5 ******************************************************************************
6 * Copyright (C) 2007-2010, International Business Machines Corporation and *
7 * others. All Rights Reserved. *
8 ******************************************************************************
9 */
10
11 package ohos.global.icu.impl.duration;
12
13 import ohos.global.icu.impl.duration.BasicPeriodFormatterFactory.Customizations;
14 import ohos.global.icu.impl.duration.impl.DataRecord.ECountVariant;
15 import ohos.global.icu.impl.duration.impl.DataRecord.EMilliSupport;
16 import ohos.global.icu.impl.duration.impl.DataRecord.ESeparatorVariant;
17 import ohos.global.icu.impl.duration.impl.DataRecord.ETimeDirection;
18 import ohos.global.icu.impl.duration.impl.DataRecord.ETimeLimit;
19 import ohos.global.icu.impl.duration.impl.PeriodFormatterData;
20
21 /**
22 * Core implementation class for PeriodFormatter.
23 */
24 class BasicPeriodFormatter implements PeriodFormatter {
25 private BasicPeriodFormatterFactory factory;
26 private String localeName;
27 private PeriodFormatterData data;
28 private Customizations customs;
29
BasicPeriodFormatter(BasicPeriodFormatterFactory factory, String localeName, PeriodFormatterData data, Customizations customs)30 BasicPeriodFormatter(BasicPeriodFormatterFactory factory,
31 String localeName,
32 PeriodFormatterData data,
33 Customizations customs) {
34 this.factory = factory;
35 this.localeName = localeName;
36 this.data = data;
37 this.customs = customs;
38 }
39
40 @Override
format(Period period)41 public String format(Period period) {
42 if (!period.isSet()) {
43 throw new IllegalArgumentException("period is not set");
44 }
45 return format(period.timeLimit, period.inFuture, period.counts);
46 }
47
48 @Override
withLocale(String locName)49 public PeriodFormatter withLocale(String locName) {
50 if (!this.localeName.equals(locName)) {
51 PeriodFormatterData newData = factory.getData(locName);
52 return new BasicPeriodFormatter(factory, locName, newData,
53 customs);
54 }
55 return this;
56 }
57
format(int tl, boolean inFuture, int[] counts)58 private String format(int tl, boolean inFuture, int[] counts) {
59 int mask = 0;
60 for (int i = 0; i < counts.length; ++i) {
61 if (counts[i] > 0) {
62 mask |= 1 << i;
63 }
64 }
65
66 // if the data does not allow formatting of zero periods,
67 // remove these from consideration. If the result has no
68 // periods set, return null to indicate we could not format
69 // the duration.
70 if (!data.allowZero()) {
71 for (int i = 0, m = 1; i < counts.length; ++i, m <<= 1) {
72 if ((mask & m) != 0 && counts[i] == 1) {
73 mask &= ~m;
74 }
75 }
76 if (mask == 0) {
77 return null;
78 }
79 }
80
81 // if the data does not allow milliseconds but milliseconds are
82 // set, merge them with seconds and force display of seconds to
83 // decimal with 3 places.
84 boolean forceD3Seconds = false;
85 if (data.useMilliseconds() != EMilliSupport.YES &&
86 (mask & (1 << TimeUnit.MILLISECOND.ordinal)) != 0) {
87 int sx = TimeUnit.SECOND.ordinal;
88 int mx = TimeUnit.MILLISECOND.ordinal;
89 int sf = 1 << sx;
90 int mf = 1 << mx;
91 switch (data.useMilliseconds()) {
92 case EMilliSupport.WITH_SECONDS: {
93 // if there are seconds, merge with seconds, otherwise leave alone
94 if ((mask & sf) != 0) {
95 counts[sx] += (counts[mx]-1)/1000;
96 mask &= ~mf;
97 forceD3Seconds = true;
98 }
99 } break;
100 case EMilliSupport.NO: {
101 // merge with seconds, reset seconds before use just in case
102 if ((mask & sf) == 0) {
103 mask |= sf;
104 counts[sx] = 1;
105 }
106 counts[sx] += (counts[mx]-1)/1000;
107 mask &= ~mf;
108 forceD3Seconds = true;
109 } break;
110 }
111 }
112
113 // get the first and last units that are set.
114 int first = 0;
115 int last = counts.length - 1;
116 while (first < counts.length && (mask & (1 << first)) == 0) ++first;
117 while (last > first && (mask & (1 << last)) == 0) --last;
118
119 // determine if there is any non-zero unit
120 boolean isZero = true;
121 for (int i = first; i <= last; ++i) {
122 if (((mask & (1 << i)) != 0) && counts[i] > 1) {
123 isZero = false;
124 break;
125 }
126 }
127
128 StringBuffer sb = new StringBuffer();
129
130 // if we've been requested to not display a limit, or there are
131 // no non-zero units, do not display the limit.
132 if (!customs.displayLimit || isZero) {
133 tl = ETimeLimit.NOLIMIT;
134 }
135
136 // if we've been requested to not display the direction, or there
137 // are no non-zero units, do not display the direction.
138 int td;
139 if (!customs.displayDirection || isZero) {
140 td = ETimeDirection.NODIRECTION;
141 } else {
142 td = inFuture ? ETimeDirection.FUTURE : ETimeDirection.PAST;
143 }
144
145 // format the initial portion of the string before the units.
146 // record whether we need to use a digit prefix (because the
147 // initial portion forces it)
148 boolean useDigitPrefix = data.appendPrefix(tl, td, sb);
149
150 // determine some formatting params and initial values
151 boolean multiple = first != last;
152 boolean wasSkipped = true; // no initial skip marker
153 boolean skipped = false;
154 boolean countSep = customs.separatorVariant != ESeparatorVariant.NONE;
155
156 // loop for formatting the units
157 for (int i = first, j = i; i <= last; i = j) {
158 if (skipped) {
159 // we didn't format the previous unit
160 data.appendSkippedUnit(sb);
161 skipped = false;
162 wasSkipped = true;
163 }
164
165 while (++j < last && (mask & (1 << j)) == 0) {
166 skipped = true; // skip
167 }
168
169 TimeUnit unit = TimeUnit.units[i];
170 int count = counts[i] - 1;
171
172 int cv = customs.countVariant;
173 if (i == last) {
174 if (forceD3Seconds) {
175 cv = ECountVariant.DECIMAL3;
176 }
177 // else leave unchanged
178 } else {
179 cv = ECountVariant.INTEGER;
180 }
181 boolean isLast = i == last;
182 boolean mustSkip = data.appendUnit(unit, count, cv, customs.unitVariant,
183 countSep, useDigitPrefix, multiple, isLast, wasSkipped, sb);
184 skipped |= mustSkip;
185 wasSkipped = false;
186
187 if (customs.separatorVariant != ESeparatorVariant.NONE && j <= last) {
188 boolean afterFirst = i == first;
189 boolean beforeLast = j == last;
190 boolean fullSep = customs.separatorVariant == ESeparatorVariant.FULL;
191 useDigitPrefix = data.appendUnitSeparator(unit, fullSep, afterFirst, beforeLast, sb);
192 } else {
193 useDigitPrefix = false;
194 }
195 }
196 data.appendSuffix(tl, td, sb);
197
198 return sb.toString();
199 }
200 }
201