PageRenderTime 37ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/src/com/atlassian/uwc/converters/smf/FixNesting.java

https://bitbucket.org/dodok1/uwc
Java | 181 lines | 159 code | 18 blank | 4 comment | 30 complexity | 25d083053198f2bf344e4ced54e21064 MD5 | raw file
  1. package com.atlassian.uwc.converters.smf;
  2. import java.util.Comparator;
  3. import java.util.HashMap;
  4. import java.util.Set;
  5. import java.util.TreeMap;
  6. import java.util.TreeSet;
  7. import java.util.Vector;
  8. import java.util.regex.Matcher;
  9. import java.util.regex.Pattern;
  10. import org.apache.log4j.Logger;
  11. import com.atlassian.uwc.converters.BaseConverter;
  12. import com.atlassian.uwc.converters.tikiwiki.RegexUtil;
  13. import com.atlassian.uwc.ui.Page;
  14. public class FixNesting extends BaseConverter {
  15. Logger log = Logger.getLogger(this.getClass());
  16. public void convert(Page page) {
  17. String input = page.getOriginalText();
  18. String converted = convertNesting(input);
  19. page.setConvertedText(converted);
  20. }
  21. protected String convertNesting(String input) {
  22. input = addMissingLi(input);
  23. TreeMap<Integer, String> start = getIndexes("<((li)|(ul)|(ol))>", input);
  24. TreeMap<Integer, String> end = getIndexes("<\\/((li)|(ul)|(ol))>", input);
  25. input = fixNesting(start, end, input);
  26. return input;
  27. }
  28. Pattern listsNoLI = Pattern.compile("" +
  29. "(?s)(<[uo]l>)(.*?)(?=<[uo]l>)");
  30. protected String addMissingLi(String input) {
  31. Matcher listFinder = listsNoLI.matcher(input);
  32. StringBuffer sb = new StringBuffer();
  33. boolean found = false;
  34. while (listFinder.find()) {
  35. String firstList = listFinder.group(1);
  36. String contents = listFinder.group(2);
  37. if (contents.contains("<li>")) continue;
  38. found = true;
  39. String replacement = firstList + "<li>" + contents;
  40. replacement = RegexUtil.handleEscapesInReplacement(replacement);
  41. listFinder.appendReplacement(sb, replacement);
  42. }
  43. if (found) {
  44. listFinder.appendTail(sb);
  45. return sb.toString();
  46. }
  47. return input;
  48. }
  49. protected TreeMap<Integer, String> getIndexes(String tag, String input) {
  50. Pattern tagStart = Pattern.compile(tag);
  51. Matcher tagFinder = tagStart.matcher(input);
  52. TreeMap<Integer, String> indexes = new TreeMap<Integer, String>();
  53. while (tagFinder.find()) {
  54. indexes.put(tagFinder.start(), tagFinder.group());
  55. }
  56. return indexes;
  57. }
  58. private String fixNesting(TreeMap<Integer, String> start, TreeMap<Integer, String> end,
  59. String input) {
  60. if (same(start, end)) return input;
  61. int diff = (start.size() - end.size());
  62. if (diff != 0) {
  63. input = addClosing(start, end, input);
  64. }
  65. return input;
  66. }
  67. protected boolean same(TreeMap a, TreeMap b) {
  68. return a.size() == b.size();
  69. }
  70. Pattern outerlist = Pattern.compile("[ou]l");
  71. protected String addClosing(TreeMap<Integer, String> start, TreeMap<Integer, String> end, String input) {
  72. //foreach key in start, note value
  73. TreeMap<Integer, String> combined = new TreeMap<Integer, String>();
  74. combined.putAll(start);
  75. combined.putAll(end);
  76. Vector<Integer> indexes = new Vector<Integer>();
  77. if (!combined.isEmpty())
  78. indexes.addAll(combined.keySet());
  79. HashMap<String, Integer> tree = new HashMap<String, Integer>();
  80. for (int i = 0; i < indexes.size(); i++) {
  81. int index = indexes.get(i);
  82. String assocTag = combined.get(index);
  83. int count = 0;
  84. String key = assocTag.replaceFirst("^<\\/?", "");
  85. key = key.replaceFirst(">$", "");
  86. if (tree.containsKey(key)) count = tree.get(key);
  87. if (assocTag.startsWith("</")) count--;
  88. else count++;
  89. tree.put(key, count);
  90. }
  91. Set<String> tags = tree.keySet();
  92. TreeSet<String> sortedTags = new TreeSet<String>(new NestingOrderComparator());
  93. sortedTags.addAll(tags);
  94. Set<Integer> ends = end.keySet();
  95. Vector<Integer> endsVec = new Vector<Integer>();
  96. endsVec.addAll(ends);
  97. int adjustment = 0;
  98. TreeSet<String> nonZeroTags = new TreeSet<String>();
  99. for (String tag : tree.keySet()) if (tree.get(tag) != 0) nonZeroTags.add(tag);
  100. for (String tag : sortedTags) {
  101. int problem = tree.get(tag);
  102. if (problem > 0) {
  103. boolean justadd = isJustAdd(nonZeroTags);
  104. if (justadd) {
  105. String addition = "</" + tag + ">";
  106. input += addition;
  107. adjustment += addition.length();
  108. }
  109. else {
  110. //find the last ul or ol
  111. for (int i = endsVec.size()-1; i >=0 ; i--) {
  112. Integer index = (Integer) endsVec.get(i);
  113. if (outerlist.matcher(end.get(index)).find()) {
  114. String pre = input.substring(0, index+adjustment);
  115. String post = input.substring(index+adjustment);
  116. String addition = "</" + tag + ">";
  117. adjustment += addition.length();
  118. input = pre + addition + post;
  119. break;
  120. }
  121. }
  122. }
  123. }
  124. else if (problem < 0) {
  125. for (int i = endsVec.size()-1; i >=0 ; i--) {
  126. Integer index = (Integer) endsVec.get(i);
  127. if (end.get(index).contains(tag)) {
  128. String pre = input.substring(0, index+adjustment);
  129. String post = input.substring(index+adjustment);
  130. String find = "<\\/" + tag + ">";
  131. String newpost = post.replaceFirst(find, "");
  132. adjustment -= post.length() - newpost.length();
  133. input = pre + newpost;
  134. break;
  135. }
  136. }
  137. }
  138. //ignore 0
  139. nonZeroTags.remove(tag);
  140. }
  141. return input;
  142. }
  143. protected boolean isJustAdd(TreeSet<String> tags) {
  144. boolean hasOuter = false;
  145. for (String tag : tags) {
  146. if (outerlist.matcher(tag).find()) {
  147. hasOuter = true;
  148. break;
  149. }
  150. }
  151. return hasOuter;
  152. }
  153. public class NestingOrderComparator implements Comparator {
  154. public int compare(Object a, Object b) {
  155. //li has to come before ol or ul
  156. String s1 = (String) a;
  157. String s2 = (String) b;
  158. if (s1.contains("li")) return -1;
  159. if (s2.contains("li")) return 1;
  160. return 1;
  161. }
  162. }
  163. }