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