Home | History | Annotate | Download | only in duration
      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