1 package org.apache.maven.doxia.module.confluence.parser;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.codehaus.plexus.util.StringUtils;
26
27
28
29
30
31
32
33
34
35
36 public class ChildBlocksBuilder
37 {
38 private boolean insideBold = false;
39
40 private boolean insideItalic = false;
41
42 private boolean insideLink = false;
43
44 private boolean insideLinethrough = false;
45
46 private boolean insideUnderline = false;
47
48 private boolean insideSub = false;
49
50 private boolean insideSup = false;
51
52 private List<Block> blocks = new ArrayList<Block>();
53
54 private StringBuilder text = new StringBuilder();
55
56 private String input;
57
58 private boolean insideMonospaced;
59
60
61
62
63
64
65 public ChildBlocksBuilder( String input )
66 {
67 this.input = input;
68 }
69
70
71
72
73
74
75 public List<Block> getBlocks()
76 {
77 List<Block> specialBlocks = new ArrayList<Block>();
78
79 for ( int i = 0; i < input.length(); i++ )
80 {
81 char c = input.charAt( i );
82
83 switch ( c )
84 {
85 case '*':
86 if ( insideBold )
87 {
88 insideBold = false;
89 specialBlocks = getList( new BoldBlock( getChildren( text, specialBlocks ) ), specialBlocks );
90 text = new StringBuilder();
91 }
92 else
93 {
94 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
95 insideBold = true;
96 }
97
98 break;
99 case '_':
100 if ( insideItalic )
101 {
102 insideItalic = false;
103 specialBlocks = getList( new ItalicBlock( getChildren( text, specialBlocks ) ), specialBlocks );
104 text = new StringBuilder();
105 }
106 else if ( insideLink )
107 {
108 text.append( '_' );
109 }
110 else
111 {
112 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
113 insideItalic = true;
114 }
115
116 break;
117 case '-':
118 if ( insideLinethrough )
119 {
120 insideLinethrough = false;
121 blocks.add( new LinethroughBlock( text.toString() ) );
122 text = new StringBuilder();
123 }
124 else if ( insideLink )
125 {
126 text.append( c );
127 }
128 else
129 {
130 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
131 insideLinethrough = true;
132 }
133 break;
134 case '+':
135 if ( insideUnderline )
136 {
137 insideUnderline = false;
138 blocks.add( new UnderlineBlock( text.toString() ) );
139 text = new StringBuilder();
140 }
141 else if ( insideLink )
142 {
143 text.append( c );
144 }
145 else
146 {
147 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
148 insideUnderline = true;
149 }
150 break;
151 case '~':
152 if ( insideSub )
153 {
154 insideSub = false;
155 blocks.add( new SubBlock( text.toString() ) );
156 text = new StringBuilder();
157 }
158 else if ( insideLink )
159 {
160 text.append( c );
161 }
162 else
163 {
164 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
165 insideSub = true;
166 }
167 break;
168 case '^':
169 if ( insideSup )
170 {
171 insideSup = false;
172 blocks.add( new SupBlock( text.toString() ) );
173 text = new StringBuilder();
174 }
175 else if ( insideLink )
176 {
177 text.append( c );
178 }
179 else
180 {
181 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
182 insideSup = true;
183 }
184 break;
185 case '[':
186 insideLink = true;
187 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
188 break;
189 case ']':
190 if ( insideLink )
191 {
192 boolean addHTMLSuffix = false;
193 String link = text.toString();
194
195 if ( !link.endsWith( ".html" ) )
196 {
197 if ( !link.contains( "http" ) )
198 {
199
200 addHTMLSuffix = true;
201 }
202 }
203 if ( link.contains( "|" ) )
204 {
205 String[] pieces = StringUtils.split( text.toString(), "|" );
206
207 if ( pieces[1].startsWith( "^" ) )
208 {
209
210
211 pieces[1] = pieces[1].substring( 1 );
212 addHTMLSuffix = false;
213
214 }
215
216 if ( addHTMLSuffix )
217 {
218 if ( !pieces[1].contains( "#" ) )
219 {
220 pieces[1] = pieces[1].concat( ".html" );
221 }
222 else
223 {
224 if ( !pieces[1].startsWith( "#" ) )
225 {
226 String[] temp = pieces[1].split( "#" );
227 pieces[1] = temp[0] + ".html#" + temp[1];
228 }
229 }
230 }
231
232 blocks.add( new LinkBlock( pieces[1], pieces[0] ) );
233 }
234 else
235 {
236 String value = link;
237
238 if ( link.startsWith( "#" ) )
239 {
240 value = link.substring( 1 );
241 }
242 else if ( link.startsWith( "^" ) )
243 {
244 link = link.substring( 1 );
245 value = link;
246 addHTMLSuffix =
247 false;
248 }
249
250 if ( addHTMLSuffix )
251 {
252 if ( !link.contains( "#" ) )
253 {
254 link = link.concat( ".html" );
255 }
256 else
257 {
258 if ( !link.startsWith( "#" ) )
259 {
260 String[] temp = link.split( "#" );
261 link = temp[0] + ".html#" + temp[1];
262 }
263 }
264 }
265
266 blocks.add( new LinkBlock( link, value ) );
267 }
268
269 text = new StringBuilder();
270 insideLink = false;
271 }
272
273 break;
274 case '{':
275
276 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
277
278 if ( nextChar( input, i ) == '{' )
279 {
280 i++;
281 insideMonospaced = true;
282 }
283
284
285 break;
286 case '}':
287
288
289
290 if ( nextChar( input, i ) == '}' )
291 {
292 i++;
293 insideMonospaced = false;
294 specialBlocks = getList( new MonospaceBlock( getChildren( text, specialBlocks ) ),
295 specialBlocks );
296 text = new StringBuilder();
297 }
298 else
299 {
300 String name = text.toString();
301 if ( name.startsWith( "anchor:" ) )
302 {
303 blocks.add( new AnchorBlock( name.substring( "anchor:".length() ) ) );
304 }
305 else
306 {
307 blocks.add( new TextBlock( "{" + name + "}" ) );
308 }
309 text = new StringBuilder();
310 }
311
312 break;
313 case '\\':
314 if ( insideMonospaced )
315 {
316 text.append( c );
317 }
318 else if ( nextChar( input, i ) == '\\' )
319 {
320 i++;
321 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
322 blocks.add( new LinebreakBlock() );
323 }
324 else
325 {
326
327 if ( i == input.length() - 1 )
328 {
329 text.append( '\\' );
330 }
331 else
332 {
333 text.append( input.charAt( ++i ) );
334 }
335 }
336
337 break;
338 default:
339 text.append( c );
340 }
341
342 if ( !specialBlocks.isEmpty() )
343 {
344 if ( !insideItalic && !insideBold && !insideMonospaced )
345 {
346 blocks.addAll( specialBlocks );
347 specialBlocks.clear();
348 }
349 }
350
351 }
352
353 if ( text.length() > 0 )
354 {
355 blocks.add( new TextBlock( text.toString() ) );
356 }
357
358 return blocks;
359 }
360
361 private List<Block> getList( Block block, List<Block> currentBlocks )
362 {
363 List<Block> list = new ArrayList<Block>();
364
365 if ( insideBold || insideItalic || insideMonospaced )
366 {
367 list.addAll( currentBlocks );
368 }
369
370 list.add( block );
371
372 return list;
373 }
374
375 private List<Block> getChildren( StringBuilder buffer, List<Block> currentBlocks )
376 {
377 String txt = buffer.toString().trim();
378
379 if ( currentBlocks.isEmpty() && StringUtils.isEmpty( txt ) )
380 {
381 return new ArrayList<Block>();
382 }
383
384 ArrayList<Block> list = new ArrayList<Block>();
385
386 if ( !insideBold && !insideItalic && !insideMonospaced )
387 {
388 list.addAll( currentBlocks );
389 }
390
391 if ( StringUtils.isEmpty( txt ) )
392 {
393 return list;
394 }
395
396 list.add( new TextBlock( txt ) );
397
398 return list;
399 }
400
401 private static char nextChar( String input, int i )
402 {
403 return input.length() > i + 1 ? input.charAt( i + 1 ) : '\0';
404 }
405
406 private StringBuilder addTextBlockIfNecessary( List<Block> blcks, List<Block> specialBlocks, StringBuilder txt )
407 {
408 if ( txt.length() == 0 )
409 {
410 return txt;
411 }
412
413 TextBlock textBlock = new TextBlock( txt.toString() );
414
415 if ( !insideBold && !insideItalic && !insideMonospaced )
416 {
417 blcks.add( textBlock );
418 }
419 else
420 {
421 specialBlocks.add( textBlock );
422 }
423
424 return new StringBuilder();
425 }
426
427 }