• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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