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 if ( insideMonospaced )
93 {
94 text.append( c );
95 }
96 else
97 {
98 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
99 insideBold = true;
100 }
101
102 break;
103 case '_':
104 if ( insideItalic )
105 {
106 insideItalic = false;
107 specialBlocks = getList( new ItalicBlock( getChildren( text, specialBlocks ) ), specialBlocks );
108 text = new StringBuilder();
109 }
110 else if ( insideLink || insideMonospaced )
111 {
112 text.append( c );
113 }
114 else
115 {
116 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
117 insideItalic = true;
118 }
119
120 break;
121 case '-':
122 if ( insideLinethrough )
123 {
124 insideLinethrough = false;
125 blocks.add( new LinethroughBlock( text.toString() ) );
126 text = new StringBuilder();
127 }
128 else if ( insideLink || insideMonospaced )
129 {
130 text.append( c );
131 }
132 else
133 {
134 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
135 insideLinethrough = true;
136 }
137 break;
138 case '+':
139 if ( insideUnderline )
140 {
141 insideUnderline = false;
142 blocks.add( new UnderlineBlock( text.toString() ) );
143 text = new StringBuilder();
144 }
145 else if ( insideLink || insideMonospaced )
146 {
147 text.append( c );
148 }
149 else
150 {
151 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
152 insideUnderline = true;
153 }
154 break;
155 case '~':
156 if ( insideSub )
157 {
158 insideSub = false;
159 blocks.add( new SubBlock( text.toString() ) );
160 text = new StringBuilder();
161 }
162 else if ( insideLink || insideMonospaced )
163 {
164 text.append( c );
165 }
166 else
167 {
168 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
169 insideSub = true;
170 }
171 break;
172 case '^':
173 if ( insideSup )
174 {
175 insideSup = false;
176 blocks.add( new SupBlock( text.toString() ) );
177 text = new StringBuilder();
178 }
179 else if ( insideLink || insideMonospaced )
180 {
181 text.append( c );
182 }
183 else
184 {
185 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
186 insideSup = true;
187 }
188 break;
189 case '[':
190 if ( insideMonospaced )
191 {
192 text.append( c );
193 }
194 else
195 {
196 insideLink = true;
197 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
198 }
199 break;
200 case ']':
201 if ( insideLink )
202 {
203 boolean addHTMLSuffix = false;
204 String link = text.toString();
205
206 if ( !link.endsWith( ".html" ) )
207 {
208 if ( !link.contains( "http" ) )
209 {
210
211 addHTMLSuffix = true;
212 }
213 }
214 if ( link.contains( "|" ) )
215 {
216 String[] pieces = StringUtils.split( text.toString(), "|" );
217
218 if ( pieces[1].startsWith( "^" ) )
219 {
220
221
222 pieces[1] = pieces[1].substring( 1 );
223 addHTMLSuffix = false;
224
225 }
226
227 if ( addHTMLSuffix )
228 {
229 if ( !pieces[1].contains( "#" ) )
230 {
231 pieces[1] = pieces[1].concat( ".html" );
232 }
233 else
234 {
235 if ( !pieces[1].startsWith( "#" ) )
236 {
237 String[] temp = pieces[1].split( "#" );
238 pieces[1] = temp[0] + ".html#" + temp[1];
239 }
240 }
241 }
242
243 blocks.add( new LinkBlock( pieces[1], pieces[0] ) );
244 }
245 else
246 {
247 String value = link;
248
249 if ( link.startsWith( "#" ) )
250 {
251 value = link.substring( 1 );
252 }
253 else if ( link.startsWith( "^" ) )
254 {
255 link = link.substring( 1 );
256 value = link;
257 addHTMLSuffix = false;
258
259 }
260
261 if ( addHTMLSuffix )
262 {
263 if ( !link.contains( "#" ) )
264 {
265 link = link.concat( ".html" );
266 }
267 else
268 {
269 if ( !link.startsWith( "#" ) )
270 {
271 String[] temp = link.split( "#" );
272 link = temp[0] + ".html#" + temp[1];
273 }
274 }
275 }
276
277 blocks.add( new LinkBlock( link, value ) );
278 }
279
280 text = new StringBuilder();
281 insideLink = false;
282 }
283 else if ( insideMonospaced )
284 {
285 text.append( c );
286 }
287
288 break;
289 case '{':
290 if ( insideMonospaced )
291 {
292 text.append( c );
293 }
294 else
295 {
296 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
297
298 if ( nextChar( input, i ) == '{' )
299 {
300 i++;
301 insideMonospaced = true;
302 }
303 }
304
305
306 break;
307 case '}':
308 if ( nextChar( input, i ) == '}' )
309 {
310 i++;
311 insideMonospaced = false;
312 specialBlocks = getList( new MonospaceBlock( getChildren( text, specialBlocks ) ),
313 specialBlocks );
314 text = new StringBuilder();
315 }
316 else if ( insideMonospaced )
317 {
318 text.append( c );
319 }
320 else
321 {
322 String name = text.toString();
323 if ( name.startsWith( "anchor:" ) )
324 {
325 blocks.add( new AnchorBlock( name.substring( "anchor:".length() ) ) );
326 }
327 else
328 {
329 blocks.add( new TextBlock( "{" + name + "}" ) );
330 }
331 text = new StringBuilder();
332 }
333
334 break;
335 case '\\':
336 if ( insideMonospaced )
337 {
338 text.append( c );
339 }
340 else if ( nextChar( input, i ) == '\\' )
341 {
342 i++;
343 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
344 blocks.add( new LinebreakBlock() );
345 }
346 else
347 {
348
349 if ( i == input.length() - 1 )
350 {
351 text.append( '\\' );
352 }
353 else
354 {
355 text.append( input.charAt( ++i ) );
356 }
357 }
358
359 break;
360 default:
361 text.append( c );
362 }
363
364 if ( !specialBlocks.isEmpty() )
365 {
366 if ( !insideItalic && !insideBold && !insideMonospaced )
367 {
368 blocks.addAll( specialBlocks );
369 specialBlocks.clear();
370 }
371 }
372
373 }
374
375 if ( text.length() > 0 )
376 {
377 blocks.add( new TextBlock( text.toString() ) );
378 }
379
380 return blocks;
381 }
382
383 private List<Block> getList( Block block, List<Block> currentBlocks )
384 {
385 List<Block> list = new ArrayList<Block>();
386
387 if ( insideBold || insideItalic || insideMonospaced )
388 {
389 list.addAll( currentBlocks );
390 }
391
392 list.add( block );
393
394 return list;
395 }
396
397 private List<Block> getChildren( StringBuilder buffer, List<Block> currentBlocks )
398 {
399 String txt = buffer.toString().trim();
400
401 if ( currentBlocks.isEmpty() && StringUtils.isEmpty( txt ) )
402 {
403 return new ArrayList<Block>();
404 }
405
406 ArrayList<Block> list = new ArrayList<Block>();
407
408 if ( !insideBold && !insideItalic && !insideMonospaced )
409 {
410 list.addAll( currentBlocks );
411 }
412
413 if ( StringUtils.isEmpty( txt ) )
414 {
415 return list;
416 }
417
418 list.add( new TextBlock( txt ) );
419
420 return list;
421 }
422
423 private static char nextChar( String input, int i )
424 {
425 return input.length() > i + 1 ? input.charAt( i + 1 ) : '\0';
426 }
427
428 private StringBuilder addTextBlockIfNecessary( List<Block> blcks, List<Block> specialBlocks, StringBuilder txt )
429 {
430 if ( txt.length() == 0 )
431 {
432 return txt;
433 }
434
435 TextBlock textBlock = new TextBlock( txt.toString() );
436
437 if ( !insideBold && !insideItalic && !insideMonospaced )
438 {
439 blcks.add( textBlock );
440 }
441 else
442 {
443 specialBlocks.add( textBlock );
444 }
445
446 return new StringBuilder();
447 }
448
449 }