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