1 /*
2 * CSVeed (https://github.com/42BV/CSVeed)
3 *
4 * Copyright 2013-2023 CSVeed.
5 *
6 * All rights reserved. This program and the accompanying materials
7 * are made available under the terms of The Apache Software License,
8 * Version 2.0 which accompanies this distribution, and is available at
9 * https://www.apache.org/licenses/LICENSE-2.0.txt
10 */
11 package org.csveed.bean;
12
13 import org.csveed.common.Column;
14
15 /**
16 * <p>
17 * The concept of dynamic columns comes into play when a sheet contains columns that are not really part of the columns,
18 * but should have been separate rows. For example, let's say you have a table that looks like this:
19 * </p>
20 * <code>
21 * | name | town | jan 14 | jan 15 | jan 16 |
22 * | Rob | Leiden | 4 | 1 | 7 |
23 * | Rob | Delft | 0 | 3 | 8 |
24 * | Erik | Leiden | 2 | 4 | 1 |
25 * | Erik | Sneek | 1 | 0 | 9 |
26 * </code>
27 * <p>
28 * Let's say you want to compact this table into the following, normalized format: <code>
29 * | name | town | date | visits |
30 * | Rob | Leiden | jan 14 | 4 |
31 * | Rob | Leiden | jan 15 | 1 |
32 * | Rob | Leiden | jan 16 | 7 |
33 * | Rob | Delft | jan 14 | 0 |
34 * | Rob | Delft | jan 15 | 3 |
35 * | Rob | Delft | jan 16 | 8 |
36 * | Erik | Leiden | jan 14 | 2 |
37 * | Erik | Leiden | jan 15 | 4 |
38 * | Erik | Leiden | jan 16 | 1 |
39 * | Erik | Sneek | jan 14 | 1 |
40 * | Erik | Sneek | jan 15 | 0 |
41 * | Erik | Sneek | jan 16 | 9 |
42 * </code>
43 * <p>
44 * In order to realize this goal, you need to make that startIndexDynamicColumns is set to 3 on @CsvFile. This will
45 * assume the columns starting with the third and all thereafter are dynamic. For every dynamic column, a new bean will
46 * be created. All static columns will be copied into every created bean.
47 * </p>
48 * <p>
49 * The header name and the cell value can be copied into bean properties. In the example, the bean requires two fields
50 * date and visits. date must be annotated with @CsvHeaderName and visits with @CsvHeaderValue.
51 * </p>
52 */
53 public class DynamicColumn {
54
55 /** The start column. */
56 private Column startColumn;
57
58 /** The current column. */
59 private Column currentColumn;
60
61 /**
62 * Instantiates a new dynamic column.
63 *
64 * @param configuredStartColumn
65 * the configured start column
66 */
67 public DynamicColumn(Column configuredStartColumn) {
68 this.startColumn = configuredStartColumn == null ? null : new Column(configuredStartColumn);
69 this.currentColumn = configuredStartColumn == null ? null : new Column(configuredStartColumn);
70 }
71
72 /**
73 * Check for reset.
74 *
75 * @param numberOfColumns
76 * the number of columns
77 */
78 public void checkForReset(int numberOfColumns) {
79 if (lastDynamicColumnPassed(numberOfColumns)) {
80 reset();
81 }
82 }
83
84 /**
85 * Reset.
86 */
87 protected void reset() {
88 this.currentColumn = new Column(this.startColumn);
89 }
90
91 /**
92 * Last dynamic column passed.
93 *
94 * @param numberOfColumns
95 * the number of columns
96 *
97 * @return true, if successful
98 */
99 protected boolean lastDynamicColumnPassed(int numberOfColumns) {
100 return this.currentColumn != null && this.currentColumn.getColumnIndex() > numberOfColumns;
101 }
102
103 /**
104 * At first dynamic column.
105 *
106 * @return true, if successful
107 */
108 public boolean atFirstDynamicColumn() {
109 return this.startColumn == null || this.startColumn.equals(this.currentColumn);
110 }
111
112 /**
113 * Advance dynamic column.
114 */
115 public void advanceDynamicColumn() {
116 if (currentColumn == null) {
117 return;
118 }
119 this.currentColumn = currentColumn.nextColumn();
120 }
121
122 /**
123 * Checks if is dynamic column active.
124 *
125 * @param currentColumn
126 * the current column
127 *
128 * @return true, if is dynamic column active
129 */
130 public boolean isDynamicColumnActive(Column currentColumn) {
131 return this.currentColumn != null && this.currentColumn.getColumnIndex() == currentColumn.getColumnIndex();
132 }
133
134 }