Home | History | Annotate | Download | only in number
      1 //  2017 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html#License
      3 package com.ibm.icu.impl.number;
      4 
      5 public class Padder {
      6     public static final String FALLBACK_PADDING_STRING = "\u0020"; // i.e. a space
      7 
      8     public enum PadPosition {
      9       BEFORE_PREFIX,
     10       AFTER_PREFIX,
     11       BEFORE_SUFFIX,
     12       AFTER_SUFFIX;
     13 
     14       public static PadPosition fromOld(int old) {
     15         switch (old) {
     16           case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX:
     17             return PadPosition.BEFORE_PREFIX;
     18           case com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX:
     19             return PadPosition.AFTER_PREFIX;
     20           case com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX:
     21             return PadPosition.BEFORE_SUFFIX;
     22           case com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX:
     23             return PadPosition.AFTER_SUFFIX;
     24           default:
     25             throw new IllegalArgumentException("Don't know how to map " + old);
     26         }
     27       }
     28 
     29       public int toOld() {
     30         switch (this) {
     31           case BEFORE_PREFIX:
     32             return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_PREFIX;
     33           case AFTER_PREFIX:
     34             return com.ibm.icu.text.DecimalFormat.PAD_AFTER_PREFIX;
     35           case BEFORE_SUFFIX:
     36             return com.ibm.icu.text.DecimalFormat.PAD_BEFORE_SUFFIX;
     37           case AFTER_SUFFIX:
     38             return com.ibm.icu.text.DecimalFormat.PAD_AFTER_SUFFIX;
     39           default:
     40             return -1; // silence compiler errors
     41         }
     42       }
     43     }
     44 
     45     /* like package-private */ public static final Padder NONE = new Padder(null, -1, null);
     46 
     47     String paddingString;
     48     int targetWidth;
     49     PadPosition position;
     50 
     51     public Padder(String paddingString, int targetWidth, PadPosition position) {
     52         // TODO: Add a few default instances
     53         this.paddingString = (paddingString == null) ? FALLBACK_PADDING_STRING : paddingString;
     54         this.targetWidth = targetWidth;
     55         this.position = (position == null) ? PadPosition.BEFORE_PREFIX : position;
     56     }
     57 
     58     public static Padder none() {
     59         return NONE;
     60     }
     61 
     62     public static Padder codePoints(int cp, int targetWidth, PadPosition position) {
     63         // TODO: Validate the code point
     64         if (targetWidth >= 0) {
     65             String paddingString = String.valueOf(Character.toChars(cp));
     66             return new Padder(paddingString, targetWidth, position);
     67         } else {
     68             throw new IllegalArgumentException("Padding width must not be negative");
     69         }
     70     }
     71 
     72     public boolean isValid() {
     73         return targetWidth > 0;
     74     }
     75 
     76     public int padAndApply(Modifier mod1, Modifier mod2, NumberStringBuilder string, int leftIndex, int rightIndex) {
     77         int modLength = mod1.getCodePointCount() + mod2.getCodePointCount();
     78         int requiredPadding = targetWidth - modLength - string.codePointCount();
     79         assert leftIndex == 0 && rightIndex == string.length(); // fix the previous line to remove this assertion
     80 
     81         int length = 0;
     82         if (requiredPadding <= 0) {
     83             // Padding is not required.
     84             length += mod1.apply(string, leftIndex, rightIndex);
     85             length += mod2.apply(string, leftIndex, rightIndex + length);
     86             return length;
     87         }
     88 
     89         if (position == PadPosition.AFTER_PREFIX) {
     90             length += addPaddingHelper(paddingString, requiredPadding, string, leftIndex);
     91         } else if (position == PadPosition.BEFORE_SUFFIX) {
     92             length += addPaddingHelper(paddingString, requiredPadding, string, rightIndex + length);
     93         }
     94         length += mod1.apply(string, leftIndex, rightIndex + length);
     95         length += mod2.apply(string, leftIndex, rightIndex + length);
     96         if (position == PadPosition.BEFORE_PREFIX) {
     97             length += addPaddingHelper(paddingString, requiredPadding, string, leftIndex);
     98         } else if (position == PadPosition.AFTER_SUFFIX) {
     99             length += addPaddingHelper(paddingString, requiredPadding, string, rightIndex + length);
    100         }
    101 
    102         return length;
    103     }
    104 
    105     private static int addPaddingHelper(String paddingString, int requiredPadding, NumberStringBuilder string,
    106             int index) {
    107         for (int i = 0; i < requiredPadding; i++) {
    108             // TODO: If appending to the end, this will cause actual insertion operations. Improve.
    109             string.insert(index, paddingString, null);
    110         }
    111         return paddingString.length() * requiredPadding;
    112     }
    113 }