Passed
Push — master ( 2be287...624345 )
by Valentyn
06:15
created

java/com/osomapps/pt/xlsx/XlsxProgramParser.java (2 issues)

1
package com.osomapps.pt.xlsx;
2
3
import java.io.IOException;
4
import java.io.InputStream;
5
import java.util.ArrayList;
6
import java.util.List;
7
import java.util.Optional;
8
import java.util.StringJoiner;
9
import lombok.extern.slf4j.Slf4j;
10
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
11
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
12
import org.apache.poi.ss.usermodel.Cell;
13
import org.apache.poi.ss.usermodel.Row;
14
import org.apache.poi.ss.usermodel.Sheet;
15
import org.apache.poi.ss.usermodel.Workbook;
16
import org.apache.poi.ss.usermodel.WorkbookFactory;
17
18
@Slf4j
19
public class XlsxProgramParser {
20
    private final InputStream inputStream;
21
22
    private XlsxProgramParser(InputStream inputStream) {
23
       this.inputStream = inputStream;
24
    }
25
26
    public static XlsxProgramParser of(InputStream inputStream) {
27
        return new XlsxProgramParser(inputStream);
28
    }
29
30
    public ExcelSheets getExcelSheets() {
31
        final List<ExcelExercise> excelExercises = new ArrayList<>();
32
        final List<ExcelGoal> excelGoals = new ArrayList<>();
33
        try (final Workbook workbook = WorkbookFactory.create(inputStream)) {
34
35
            excelExercises.addAll(extractExercises(workbook.getSheetAt(3)));
36
            for (int index = 4; index < workbook.getNumberOfSheets(); index += 1) {
37
                final Sheet sheet = workbook.getSheetAt(index);
38
                ExcelGoal excelGoal = extractGoal(index, sheet, excelExercises);
39
                if (!excelGoal.getUserGroups().isEmpty()) {
40
                    excelGoals.add(excelGoal);
41
                }
42
            }
43
        } catch (IOException | InvalidFormatException ex) {
44
            log.error(ex.getMessage(), ex);
45
        }
46
        return new ExcelSheets().setExcelExercises(excelExercises).setExcelGoals(excelGoals);
47
    }
48
49
    private List<ExcelExercise> extractExercises(Sheet sheet) {
50
        List<ExcelExercise> excelExercises = new ArrayList<>();
51
        for (int exerciseIndex = 2; exerciseIndex < sheet.getLastRowNum();
52
                exerciseIndex += 1) {
53
            ExcelExercise excelExercise = new ExcelExercise()
54
                    .setExercise_id(getIntegerOrNull(getCellData(sheet, exerciseIndex, 0)))
55
                    .setExercise_name(getStringOrNull(getCellData(sheet, exerciseIndex, 1)))
56
                    .setUser_group_1_percent(getIntegerOrNull(getCellData(sheet, exerciseIndex, 3)))
57
                    .setUser_group_2_percent(getIntegerOrNull(getCellData(sheet, exerciseIndex, 4)))
58
                    .setUser_group_3_percent(getIntegerOrNull(getCellData(sheet, exerciseIndex, 5)))
59
                    .setUser_group_4_percent(getIntegerOrNull(getCellData(sheet, exerciseIndex, 6)))
60
                    .setBasis_for_calculations(getStringOrNull(getCellData(sheet, exerciseIndex, 12)));
61
            if (excelExercise.getUser_group_1_percent() != null) {
62
                excelExercises.add(excelExercise);
63
            }
64
        }
65
        return excelExercises;
66
    }
67
68
    private ExcelGoal extractGoal(int index, final Sheet sheet, List<ExcelExercise> excelExercises) {
69
        final ExcelGoal excelGoal = new ExcelGoal()
70
                .setSheetIndex(index)
71
                .setName(sheet.getSheetName())
72
                .setLoops(getIntegerOrNull(getCellData(sheet, 0, 1)))
73
                .setErrors(new ArrayList<>());
74
        String prevUserGroupName = "";
75
        String prevRoundName = "";
76
        String prevPartName = "";
77
        UserGroup userGroup = new UserGroup();
78
        Round round = new Round();
79
        Part part = new Part();
80
        for (int workoutIndex = 0; workoutIndex < sheet.getRow(0).getPhysicalNumberOfCells();
81
                workoutIndex += 1) {
82
            if (!(getCellData(sheet, 10, 2 + workoutIndex) instanceof Number)) {
83
                break;
84
            }
85
            final String userGroupName = getNumberOrNullAsString(getCellData(sheet, 2, 2 + workoutIndex));
86
            final String roundName = getNumberOrNullAsString(getCellData(sheet, 3, 2 + workoutIndex));
87
            final String partName = (String) getCellData(sheet, 4, 2 + workoutIndex);
88
            final boolean userGroupNameWasCreated;
89
            if (userGroupName != null && !prevUserGroupName.equals(userGroupName)) {
90
                userGroup = new UserGroup().setName(userGroupName);
91
                prevUserGroupName = userGroupName;
92
                excelGoal.getUserGroups().add(userGroup);
93
                userGroupNameWasCreated = true;
94
            } else {
95
                userGroupNameWasCreated = false;
96
            }
97
            final boolean roundNameWasCreated;
98
            if (roundName != null && (userGroupNameWasCreated || !prevRoundName.equals(roundName))) {
99
                round = new Round()
100
                        .setName(roundName);
101
                prevRoundName = roundName;
102
                userGroup.getRounds().add(round);
103
                roundNameWasCreated = true;
104
            } else {
105
                roundNameWasCreated = false;
106
            }
107
            if (partName != null && (userGroupNameWasCreated || roundNameWasCreated || !prevPartName.equals(partName))) {
108
                part = new Part()
109
                        .setName(partName);
110
                prevPartName = partName;
111
                round.getParts().add(part);
112
            }
113
            final String workoutName = new StringJoiner("_").add(excelGoal.getName())
114
                    .add(userGroup.getName()).add(round.getName()).add(part.getName()).toString();
115
            final Workout workout = new Workout();
116
            workout.setRowIndex(4);
117
            workout.setColumnIndex(2 + workoutIndex);
118
            workout.setName(workoutName);
119
            final Optional<WarmupWorkoutItem> warmupWorkoutItem = extractWarmupWorkoutItem(sheet,
120
                    workoutIndex, excelGoal, workoutName, excelExercises);
121
            workout.setWarmup(warmupWorkoutItem.orElse(null));
122
            for (int workoutItemIndex = 0; workoutItemIndex < 10; workoutItemIndex += 1) {
123
                final int multiplyCoeff = 7;
124
                if (!(getCellData(sheet, 10 + workoutItemIndex
125
                        * multiplyCoeff, 2 + workoutIndex) instanceof Number)) {
126
                    break;
127
                }
128
                final Optional<WorkoutItem> workoutItem = extractWorkoutItem(sheet, workoutItemIndex,
129
                        workoutIndex, excelGoal, workoutName, excelExercises);
130
                if (workoutItem.isPresent()) {
131
                    workout.getWorkoutItems().add(workoutItem.get());
132
                }
133
            }
134
            part.getWorkouts().add(workout);
135
        }
136
        return excelGoal;
137
    }
138
139
    private String getOnlySymbols(String value) {
140
        return value.replace("(Weight loss)", "").replace("Leg Press strenght", "Legpress")
141
                .replace("Chest Press", "Bench Press").replace("Bike, Steady Pace Walk or Jog", "Bike, Steady Pace")
142
                .replaceAll("[\\s\\.\\,]+", "");
143
    }
144
145
    private Optional<WarmupWorkoutItem> extractWarmupWorkoutItem(Sheet sheet, int workoutIndex,
146
            ExcelGoal excelGoal, String workoutName, List<ExcelExercise> excelExercises) {
147
        final Optional<String> warmupName = getStringOrEmpty(getCellData(sheet, 5, 2 + workoutIndex));
148
        if (!warmupName.isPresent()) {
149
            excelGoal.getErrors().add("Warmup name not found. Goal " + excelGoal.getName() + ", workout " + workoutName + ".");
150
            return Optional.empty();
151
        }
152
        Optional<ExcelExercise> excelExercise = excelExercises.stream().filter(exercise ->
153
            getOnlySymbols(exercise.getExercise_name()).equalsIgnoreCase(getOnlySymbols(warmupName.get()))
154
        ).findFirst();
155
        if (!excelExercise.isPresent()) {
156
            excelGoal.getErrors().add("Exercise warmup name (" + warmupName.get() + ") not recognised. Goal "
157
                    + excelGoal.getName() + ", workout " + workoutName + ".");
158
        }
159
160
        Integer speedInp = extractNumbers(getCellData(sheet, 5 + 1, 2 + workoutIndex));
161
        Integer inclineInp = getIntegerOrNull(getCellData(sheet, 5 + 2, 2 + workoutIndex));
162
        Float timeInp = extractFloatNumbers(getCellData(sheet, 5 + 3, 2 + workoutIndex));
163
        return Optional.of(new WarmupWorkoutItem().setExercise(warmupName.get())
164
            .setExerciseId(excelExercise.orElse(new ExcelExercise().setExercise_id(0)).getExercise_id())
165
            .setSpeed(speedInp).setIncline(inclineInp).setTimeInMin(timeInp));
166
    }
167
168
    private Optional<WorkoutItem> extractWorkoutItem(final Sheet sheet, int workoutItemIndex,
169
            int workoutIndex, ExcelGoal excelGoal, String workoutName, List<ExcelExercise> excelExercises) {
170
        final int multiplyCoeff = 7;
171
        WorkoutItem workoutItem = new WorkoutItem();
172
        workoutItem.setRowIndex(4 + 4 + workoutItemIndex * multiplyCoeff);
173
        workoutItem.setColumnIndex(2 + workoutIndex);
174
        final Optional<String> exerciseName = getStringOrEmpty(getCellData(sheet, 5 + 4
175
                + workoutItemIndex * multiplyCoeff, 2 + workoutIndex));
176
        if (!exerciseName.isPresent()) {
177
            excelGoal.getErrors().add("Exercise name not found. Goal " + excelGoal.getName() + ", workout " + workoutName + ".");
178
            return Optional.empty();
179
        }
180
        Optional<ExcelExercise> excelExercise = excelExercises.stream().filter(exercise ->
181
            getOnlySymbols(exercise.getExercise_name()).equalsIgnoreCase(getOnlySymbols(exerciseName.get()))
182
        ).findFirst();
183
        if (!excelExercise.isPresent()) {
184
            excelGoal.getErrors().add("Exercise name (" + exerciseName.get() + ") not recognised. Goal "
185
                    + excelGoal.getName() + ", workout " + workoutName + ".");
186
        } else {
187
            workoutItem.setExerciseId(excelExercise.get().getExercise_id());
188
        }
189
        Number setsInp = getNumberOrNull(getCellData(sheet, 5 + 5 + workoutItemIndex * multiplyCoeff, 2 + workoutIndex));
190
        Object repetitionsInp = getStringOrNumberOrNull(getCellData(sheet, 5 + 6  + workoutItemIndex * multiplyCoeff, 2 + workoutIndex));
191
        Object weightInp = getStringOrNumberOrNull(getCellData(sheet, 5 + 7 + workoutItemIndex * multiplyCoeff, 2 + workoutIndex));
192
        workoutItem.getInput().setExercise(exerciseName.orElse(null));
193
        if (repetitionsInp instanceof String || weightInp instanceof String) {
194
            workoutItem.getInput().setSets(new ArrayList<>());
195
            for (int index = 0; index < setsInp.intValue(); index += 1) {
0 ignored issues
show
A "NullPointerException" could be thrown; "setsInp" is nullable here.
Loading history...
196
                InputSet inputSet = new InputSet();
197
                if (repetitionsInp instanceof String) {
198
                    String[] repetitionsInps = ((String) repetitionsInp).split("\\s*,\\s*");
199
                    if (exerciseName.orElse("").contains("Plank")
200
                            || repetitionsInps[index].contains("min")
201
                            || "Time".equalsIgnoreCase(getStringOrNull(getCellData(sheet, 5 + 6  + workoutItemIndex * multiplyCoeff, 1)))) {
202
                        inputSet.setTimeInMin(getFloatOrNull(extractFloatNumbers(repetitionsInps[index])));
203
                    } else {
204
                       inputSet.setRepetitions(getIntegerOrNull(extractNumbers(repetitionsInps[index])));
205
                    }
206
                } else {
207
                    if ("Time".equalsIgnoreCase(getStringOrNull(getCellData(sheet, 5 + 6  + workoutItemIndex * multiplyCoeff, 1)))) {
208
                        inputSet.setTimeInMin(getFloatOrNull(repetitionsInp));
209
                    } else {
210
                       inputSet.setRepetitions(getIntegerOrNull(repetitionsInp));
211
                    }
212
                }
213
                if (weightInp instanceof String) {
214
                    String[] weightInps = ((String) weightInp).split("\\s*,\\s*");
215
                    inputSet.setWeight(getFloatOrNull(extractFloatNumbers(weightInps[Math.min(index, weightInps.length - 1)])));
216
                } else {
217
                    inputSet.setWeight(getFloatOrNull(weightInp));
218
                }
219
                workoutItem.getInput().getSets().add(inputSet);
220
            }
221
        } else {
222
            InputSet inputSet = new InputSet();
223
            if ("Time".equalsIgnoreCase(getStringOrNull(getCellData(sheet, 5 + 6  + workoutItemIndex * multiplyCoeff, 1)))) {
224
                inputSet.setTimeInMin(getFloatOrNull(repetitionsInp));
225
            } else {
226
               inputSet.setRepetitions(getIntegerOrNull(repetitionsInp));
227
            }
228
            inputSet.setWeight(getFloatOrNull(weightInp));
229
            workoutItem.getInput().setSets(new ArrayList<>());
230
            for (int index = 0; index < setsInp.intValue(); index += 1) {
0 ignored issues
show
A "NullPointerException" could be thrown; "setsInp" is nullable here.
Loading history...
231
                workoutItem.getInput().getSets().add(inputSet);
232
            }
233
        }
234
        return Optional.of(workoutItem);
235
    }
236
237
    private Number getNumberOrNull(Object object) {
238
        return object instanceof Number ? (Number) object : null;
239
    }
240
241
    private String getNumberOrNullAsString(Object object) {
242
        return object instanceof Number ? String.valueOf(((Number) object).intValue()) : null;
243
    }
244
245
    private Integer extractNumbers(Object object) {
246
        if (object instanceof String) {
247
            String onlyNumbersValue = ((String) object).replaceAll("[^\\d]+", "");
248
            return onlyNumbersValue.isEmpty() ? null : Integer.parseInt(onlyNumbersValue);
249
        }
250
        return null;
251
    }
252
253
    private Float extractFloatNumbers(Object object) {
254
        if (object instanceof String) {
255
            String onlyNumbersValue = ((String) object).replaceAll("[^\\d\\.]+", "");
256
            return onlyNumbersValue.isEmpty() ? null : Float.parseFloat(onlyNumbersValue);
257
        }
258
        return null;
259
    }
260
261
    private String getStringOrNull(Object object) {
262
        return object instanceof String ? (String) object : null;
263
    }
264
265
266
    private Object getStringOrNumberOrNull(Object object) {
267
        if (object instanceof String) {
268
            return (String) object;
269
        } else if (object instanceof Number) {
270
            return (Number) object;
271
        }
272
        return null;
273
    }
274
275
    private Integer getIntegerOrNull(Object object) {
276
        return object instanceof Number ? ((Number) object).intValue() : null;
277
    }
278
279
    private Float getFloatOrNull(Object object) {
280
        return object instanceof Number ? ((Number) object).floatValue() : null;
281
    }
282
283
    private Optional<String> getStringOrEmpty(Object object) {
284
        if (object instanceof String) {
285
            return Optional.of((String) object);
286
        }
287
        return Optional.empty();
288
    }
289
290
    private Object getCellData(Sheet sheet, int rowIndex, int cellIndex) {
291
        final Row row = sheet.getRow(rowIndex);
292
        if (row == null) {
293
            return null;
294
        }
295
        final Cell cell = row.getCell(cellIndex);
296
        return cell == null ? null : cellToObject(cell);
297
    }
298
299
    private Object cellToObject(Cell cell) {
300
        final int type = cell.getCellType();
301
        if (type == Cell.CELL_TYPE_STRING) {
302
            return cleanString(cell.getStringCellValue());
303
        }
304
305
        if (type == Cell.CELL_TYPE_BOOLEAN) {
306
            return cell.getBooleanCellValue();
307
        }
308
309
        if (type == Cell.CELL_TYPE_NUMERIC) {
310
            if (cell.getCellStyle().getDataFormatString().contains("%")) {
311
                return cell.getNumericCellValue() * 100;
312
            }
313
            return numeric(cell);
314
        }
315
316
        if (type == Cell.CELL_TYPE_FORMULA) {
317
            switch(cell.getCachedFormulaResultType()) {
318
                case Cell.CELL_TYPE_NUMERIC:
319
                    return numeric(cell);
320
                case Cell.CELL_TYPE_STRING:
321
                    return cleanString(cell.getRichStringCellValue().toString());
322
            }
323
        }
324
        return null;
325
    }
326
327
    private String cleanString(String str) {
328
        return str.replace("\n", "").replace("\r", "");
329
    }
330
331
    private Object numeric(Cell cell) {
332
        if (HSSFDateUtil.isCellDateFormatted(cell)) {
333
            return cell.getDateCellValue();
334
        }
335
        return cell.getNumericCellValue();
336
    }
337
338
}
339