Coverage Report - ca.uhn.hl7v2.model.primitive.FormattedTextEncoder
 
Classes in this File Line Coverage Branch Coverage Complexity
FormattedTextEncoder
98%
154/156
89%
86/96
4.333
 
 1  
 package ca.uhn.hl7v2.model.primitive;
 2  
 
 3  
 import java.util.regex.Matcher;
 4  
 import java.util.regex.Pattern;
 5  
 
 6  
 /**
 7  
  * <p>
 8  
  * Provides methods to convert between HL7 Formatted Text encoding (See Chapter
 9  
  * 2.7) and other encoding schemes.
 10  
  * </p>
 11  
  * <p>
 12  
  * For now, only {@link #getInstanceHtml() HTML encoding} is supported, but others may be added.
 13  
  * </p>
 14  
  * <p>
 15  
  * <b>Note that this class is not threadsafe!</b> Always use a new instance
 16  
  * (from a factory method) for each invocation.
 17  
  * </p>
 18  
  * 
 19  
  * @author James Agnew
 20  
  * @see AbstractTextPrimitive
 21  
  */
 22  
 public class FormattedTextEncoder {
 23  
 
 24  
         private StringBuilder myBuffer;
 25  
         private int myInBold;
 26  
         private boolean myInCenter;
 27  
 
 28  
         /**
 29  
          * Use factory methods to instantiate this class
 30  
          */
 31  
         private FormattedTextEncoder() {
 32  155
                 super();
 33  155
         }
 34  
 
 35  
         private void addLt() {
 36  5
                 myBuffer.append("&lt;");
 37  5
         }
 38  
 
 39  
         private void addGt() {
 40  5
                 myBuffer.append("&gt;");
 41  5
         }
 42  
 
 43  
         private void addAmpersand() {
 44  10
                 myBuffer.append("&amp;");
 45  10
         }
 46  
 
 47  
         private void addBreak() {
 48  120
                 myBuffer.append("<br>");
 49  120
         }
 50  
 
 51  
         private void addEndNoBreak() {
 52  15
                 myBuffer.append("</nobr>");
 53  15
         }
 54  
 
 55  
         private void addHighAscii(char nextChar) {
 56  5
                 myBuffer.append("&#");
 57  5
                 myBuffer.append((int) nextChar);
 58  5
                 myBuffer.append(";");
 59  5
         }
 60  
 
 61  
         private void addSpace() {
 62  160
                 myBuffer.append("&nbsp;");
 63  160
         }
 64  
 
 65  
         private void addStartCenter() {
 66  35
                 myBuffer.append("<center>");
 67  35
         }
 68  
 
 69  
         private void addStartNoBreak() {
 70  15
                 myBuffer.append("<nobr>");
 71  15
         }
 72  
 
 73  
         private void closeCenterIfNeeded() {
 74  265
                 if (myInCenter) {
 75  35
                         myBuffer.append("</center>");
 76  
                 }
 77  265
         }
 78  
 
 79  
         /**
 80  
          * Convert the input string containing FT encoding strings (\.br\, \.sp XX\,
 81  
          * etc.) into the appropriate output type for this encoder (currently HTML)
 82  
          * 
 83  
          * @param theInput
 84  
          *            The input string
 85  
          * @return An encoded version of the input string
 86  
          */
 87  
         public String encode(String theInput) {
 88  155
                 if (theInput == null) {
 89  0
                         return null;
 90  
                 }
 91  
 
 92  155
                 myBuffer = new StringBuilder(theInput.length() + 20);
 93  155
                 boolean myAtStartOfLine = true;
 94  155
                 myInCenter = false;
 95  155
                 boolean myWordWrap = true;
 96  155
                 int myCurrentLineOffset = 0;
 97  155
                 int myTemporaryIndent = 0;
 98  155
                 int myIndent = 0;
 99  155
                 boolean myNeedBreakBeforeNextText = false;
 100  155
                 boolean myInDiv = false;
 101  155
                 myInBold = 0;
 102  
 
 103  3440
                 for (int i = 0; i < theInput.length(); i++) {
 104  
 
 105  3285
                         char nextChar = theInput.charAt(i);
 106  3285
                         boolean handled = true;
 107  
 
 108  3285
                         switch (nextChar) {
 109  
                         case '\\':
 110  
 
 111  265
                                 int theStart = i + 1;
 112  265
                                 int numericArgument = Integer.MIN_VALUE;
 113  265
                                 int offsetIncludingNumericArgument = 0;
 114  265
                                 String nextFourChars = theInput.substring(theStart, Math.min(theInput.length(), theStart + 4)).toLowerCase();
 115  265
                                 if (theInput.length() >= theStart + 5) {
 116  245
                                         char sep = theInput.charAt(i + 4);
 117  245
                                         if (theInput.charAt(i + 1) == '.' && (sep == ' ' || sep == '-' || sep == '+')) {
 118  75
                                                 String nextThirtyChars = theInput.substring(theStart + 3, Math.min(theInput.length(), theStart + 30));
 119  75
                                                 Matcher m = Pattern.compile("^([ +-]?[0-9]+)\\\\").matcher(nextThirtyChars);
 120  75
                                                 if (m.find()) {
 121  65
                                                         String group = m.group(1);
 122  65
                                                         offsetIncludingNumericArgument = group.length() + 4;
 123  65
                                                         group = group.replace('+', ' ').trim();
 124  65
                                                         numericArgument = Integer.parseInt(group);
 125  
                                                 }
 126  
                                         }
 127  
                                 }
 128  
 
 129  265
                                 if (nextFourChars.equals(".br\\")) {
 130  
 
 131  75
                                         closeCenterIfNeeded();
 132  75
                                         if (myNeedBreakBeforeNextText) {
 133  0
                                                 addBreak();
 134  
                                         }
 135  75
                                         myNeedBreakBeforeNextText = true;
 136  75
                                         i += 4;
 137  75
                                         myAtStartOfLine = true;
 138  75
                                         myInCenter = false;
 139  75
                                         myCurrentLineOffset = 0;
 140  
 
 141  190
                                 } else if (nextFourChars.startsWith("h\\")) {
 142  
 
 143  15
                                         startBold();
 144  15
                                         i += 2;
 145  
 
 146  175
                                 } else if (nextFourChars.startsWith("n\\")) {
 147  
 
 148  10
                                         endBold();
 149  10
                                         i += 2;
 150  
 
 151  165
                                 } else if (nextFourChars.startsWith(".in") && myAtStartOfLine && numericArgument != Integer.MIN_VALUE) {
 152  
 
 153  25
                                         myIndent = numericArgument;
 154  25
                                         myTemporaryIndent = 0;
 155  25
                                         i += offsetIncludingNumericArgument;
 156  
 
 157  140
                                 } else if (nextFourChars.startsWith(".ti") && myAtStartOfLine && numericArgument != Integer.MIN_VALUE) {
 158  
 
 159  5
                                         myTemporaryIndent = numericArgument;
 160  5
                                         i += offsetIncludingNumericArgument;
 161  
 
 162  135
                                 } else if (nextFourChars.equals(".ce\\")) {
 163  
 
 164  35
                                         closeCenterIfNeeded();
 165  35
                                         if (!myAtStartOfLine) {
 166  30
                                                 addBreak();
 167  
                                         }
 168  35
                                         addStartCenter();
 169  35
                                         i += 4;
 170  35
                                         myAtStartOfLine = false;
 171  35
                                         myInCenter = true;
 172  
 
 173  100
                                 } else if (nextFourChars.equals(".fi\\")) {
 174  
 
 175  10
                                         if (!myWordWrap) {
 176  10
                                                 addEndNoBreak();
 177  10
                                                 myWordWrap = true;
 178  
                                         }
 179  10
                                         i += 4;
 180  
 
 181  90
                                 } else if (nextFourChars.equals(".nf\\")) {
 182  
 
 183  15
                                         if (myWordWrap) {
 184  15
                                                 addStartNoBreak();
 185  15
                                                 myWordWrap = false;
 186  
                                         }
 187  15
                                         i += 4;
 188  
 
 189  75
                                 } else if (nextFourChars.startsWith(".sp")) {
 190  
 
 191  50
                                         if (nextFourChars.equals(".sp\\")) {
 192  10
                                                 numericArgument = 1;
 193  10
                                                 i += 4;
 194  40
                                         } else if (numericArgument != -1) {
 195  40
                                                 i += offsetIncludingNumericArgument;
 196  
                                         }
 197  
 
 198  50
                                         if (numericArgument > 0) {
 199  
 
 200  75
                                                 for (int j = 0; j < numericArgument; j++) {
 201  45
                                                         addBreak();
 202  
                                                 }
 203  165
                                                 for (int j = 0; j < myCurrentLineOffset; j++) {
 204  135
                                                         addSpace();
 205  
                                                 }
 206  
 
 207  20
                                         } else if (numericArgument == Integer.MIN_VALUE) {
 208  
 
 209  20
                                                 handled = false;
 210  
 
 211  
                                         }
 212  
 
 213  25
                                 } else if (nextFourChars.equals(".sk ") && numericArgument >= 0) {
 214  
 
 215  35
                                         for (int j = 0; j < numericArgument; j++) {
 216  25
                                                 addSpace();
 217  
                                         }
 218  10
                                         i += offsetIncludingNumericArgument;
 219  
 
 220  
                                 } else {
 221  
 
 222  15
                                         handled = false;
 223  
 
 224  
                                 }
 225  
 
 226  15
                                 break;
 227  
                         default:
 228  
 
 229  3020
                                 handled = false;
 230  
 
 231  
                         }
 232  
 
 233  3285
                         if (!handled) {
 234  
 
 235  3055
                                 if (myAtStartOfLine) {
 236  
 
 237  225
                                         int thisLineIndent = Math.max(0, myIndent + myTemporaryIndent);
 238  225
                                         if (myNeedBreakBeforeNextText) {
 239  
 
 240  75
                                                 if (myInDiv) {
 241  10
                                                         myBuffer.append("</div>");
 242  65
                                                 } else if (thisLineIndent == 0) {
 243  45
                                                         addBreak();
 244  
                                                 }
 245  
                                         }
 246  
 
 247  225
                                         if (thisLineIndent > 0) {
 248  30
                                                 myBuffer.append("<div style=\"margin-left: ");
 249  30
                                                 myBuffer.append(thisLineIndent);
 250  30
                                                 myBuffer.append("em;\">");
 251  30
                                                 myInDiv = true;
 252  
                                         }
 253  
                                 }
 254  
 
 255  3055
                                 switch (nextChar) {
 256  
                                 case '&':
 257  10
                                         addAmpersand();
 258  10
                                         break;
 259  
                                 case '<':
 260  5
                                         addLt();
 261  5
                                         break;
 262  
                                 case '>':
 263  5
                                         addGt();
 264  5
                                         break;
 265  
                                 default:
 266  3035
                                         if (nextChar >= 160) {
 267  5
                                                 addHighAscii(nextChar);
 268  
                                         } else {
 269  3030
                                                 myBuffer.append(nextChar);
 270  
                                         }
 271  
                                 }
 272  
 
 273  3055
                                 myAtStartOfLine = false;
 274  3055
                                 myNeedBreakBeforeNextText = false;
 275  3055
                                 myCurrentLineOffset++;
 276  
 
 277  
                         }
 278  
 
 279  
                 }
 280  
 
 281  155
                 endBold();
 282  
 
 283  155
                 if (!myWordWrap) {
 284  5
                         addEndNoBreak();
 285  
                 }
 286  155
                 closeCenterIfNeeded();
 287  
 
 288  155
                 if (myInDiv) {
 289  20
                         myBuffer.append("</div>");
 290  
                 }
 291  
 
 292  155
                 return myBuffer.toString();
 293  
         }
 294  
 
 295  
         private void endBold() {
 296  180
                 for (int i = 0; i < myInBold; i++) {
 297  15
                         myBuffer.append("</b>");
 298  
                 }
 299  165
                 myInBold = 0;
 300  165
         }
 301  
 
 302  
         private void startBold() {
 303  15
                 myBuffer.append("<b>");
 304  15
                 myInBold++;
 305  15
         }
 306  
 
 307  
         /**
 308  
          * Returns a newly created instance which uses standard HTML encoding. The
 309  
          * returned instance is not threadsafe, so this method should be called to
 310  
          * obtain a new instance in any thread that requires a FormattedTextEncoder.
 311  
          * 
 312  
          * @see AbstractTextPrimitive#getValueAsHtml() for a description of the
 313  
          *      encoding performed by this type of encoder
 314  
          */
 315  
         public static FormattedTextEncoder getInstanceHtml() {
 316  155
                 return new FormattedTextEncoder();
 317  
         }
 318  
 
 319  
 }