1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.api.markup.asciidoc;
18
19 import static org.forgerock.api.markup.asciidoc.AsciiDocSymbols.*;
20 import static org.forgerock.api.util.ValidationUtil.isEmpty;
21
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.regex.Matcher;
25 import java.util.regex.Pattern;
26
27 import org.forgerock.util.Reject;
28
29
30
31
32
33
34
35
36 public class AsciiDocTable {
37
38
39
40
41 public static final int COLUMN_WIDTH_SMALL = 1;
42
43
44
45
46 public static final int COLUMN_WIDTH_MEDIUM = 2;
47
48 private static final Pattern TABLE_CELL_SYMBOL_PATTERN = Pattern.compile("\\|");
49
50 private final AsciiDoc asciiDoc;
51 private final StringBuilder builder;
52 private final List<String> cells;
53 private int[] columnWidths;
54 private Integer columnsPerRow;
55 private String title;
56 private boolean hasHeader;
57
58 AsciiDocTable(final AsciiDoc asciiDoc, final StringBuilder builder) {
59 this.asciiDoc = Reject.checkNotNull(asciiDoc);
60 this.builder = Reject.checkNotNull(builder);
61 cells = new ArrayList<>();
62 }
63
64
65
66
67
68
69
70 public AsciiDocTable title(final String title) {
71 if (isEmpty(title)) {
72 throw new AsciiDocException("title required");
73 }
74 if (this.title != null) {
75 throw new AsciiDocException("title already defined");
76 }
77 this.title = title;
78 return this;
79 }
80
81
82
83
84
85
86
87
88 public AsciiDocTable headers(final List<String> columnHeaders) {
89 return headers(columnHeaders.toArray(new String[columnHeaders.size()]));
90 }
91
92
93
94
95
96
97
98
99 public AsciiDocTable headers(final String... columnHeaders) {
100 if (isEmpty(columnHeaders)) {
101 throw new AsciiDocException("columnHeaders required");
102 }
103 if (hasHeader) {
104 throw new AsciiDocException("headers already defined");
105 }
106 if (columnsPerRow == null) {
107 columnsPerRow = columnHeaders.length;
108 } else if (columnsPerRow != columnHeaders.length) {
109 throw new AsciiDocException("columnHeaders.length != columnsPerRow");
110 }
111 hasHeader = true;
112
113
114 cells.add(null);
115 for (int i = columnHeaders.length - 1; i > -1; --i) {
116 cells.add(0, TABLE_CELL + normalizeColumnCell(columnHeaders[i]));
117 }
118 return this;
119 }
120
121
122
123
124
125
126
127
128
129
130
131 public AsciiDocTable columnsPerRow(final int columnsPerRow) {
132 if (this.columnsPerRow != null) {
133 throw new AsciiDocException("columnsPerRow already defined");
134 }
135 if (this.columnsPerRow < 1) {
136 throw new AsciiDocException("columnsPerRow < 1");
137 }
138 this.columnsPerRow = columnsPerRow;
139 return this;
140 }
141
142
143
144
145
146
147
148
149 public AsciiDocTable columnWidths(final List<Integer> columnWidths) {
150 final int[] array = new int[columnWidths.size()];
151 for (int i = 0; i < array.length; ++i) {
152 array[i] = columnWidths.get(i);
153 }
154 return columnWidths(array);
155 }
156
157
158
159
160
161
162
163
164 public AsciiDocTable columnWidths(final int... columnWidths) {
165 if (columnWidths == null || columnWidths.length == 0) {
166 throw new AsciiDocException("columnWidths required");
167 }
168 for (final int w : columnWidths) {
169 if (w < 1 || w > 99) {
170 throw new AsciiDocException("columnWidths values must be within range [1,99]");
171 }
172 }
173 if (columnsPerRow != null) {
174 if (columnsPerRow != columnWidths.length) {
175 throw new AsciiDocException("columnWidths.length != columnsPerRow");
176 }
177 } else {
178 columnsPerRow = columnWidths.length;
179 }
180 this.columnWidths = columnWidths;
181 return this;
182 }
183
184
185
186
187
188
189
190 public AsciiDocTable columnCell(final String columnCell) {
191 cells.add(TABLE_CELL + normalizeColumnCell(columnCell));
192 return this;
193 }
194
195
196
197
198
199
200
201
202 public AsciiDocTable columnCell(final String columnCell, final AsciiDocTableColumnStyles style) {
203 cells.add(style.toString() + TABLE_CELL + normalizeColumnCell(columnCell));
204 return this;
205 }
206
207
208
209
210
211
212
213 public AsciiDocTable rowEnd() {
214 cells.add(null);
215 return this;
216 }
217
218 private String normalizeColumnCell(final String columnCell) {
219 if (isEmpty(columnCell)) {
220
221 return "";
222 }
223
224 final Matcher m = TABLE_CELL_SYMBOL_PATTERN.matcher(columnCell);
225 return m.find() ? m.replaceAll("\\" + TABLE_CELL) : columnCell;
226 }
227
228
229
230
231
232
233 public AsciiDoc tableEnd() {
234 if (columnsPerRow == null) {
235 throw new AsciiDocException("columnsPerRow has not be defined");
236 }
237
238
239 builder.append("[cols=\"");
240 if (columnWidths != null) {
241
242 builder.append(columnWidths[0]);
243 for (int i = 1; i < columnWidths.length; ++i) {
244 builder.append(',').append(columnWidths[i]);
245 }
246 } else {
247
248 builder.append(columnsPerRow).append("*");
249 }
250 builder.append("\", caption=\"\", options=\"");
251 if (hasHeader) {
252 builder.append("header");
253 }
254 builder.append("\"]").append(NEWLINE);
255
256
257 if (title != null) {
258 builder.append(".").append(title).append(NEWLINE);
259 }
260
261
262 builder.append(TABLE).append(NEWLINE);
263 if (cells.get(cells.size() - 1) == null) {
264
265 cells.remove(cells.size() - 1);
266 }
267 for (final String item : cells) {
268 if (item != null) {
269
270 builder.append(item);
271 }
272 builder.append(NEWLINE);
273 }
274 builder.append(TABLE).append(NEWLINE);
275
276 return asciiDoc;
277 }
278
279 }