package ru.ulstu.controller; import io.swagger.v3.oas.annotations.Hidden; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import ru.ulstu.datamodel.ChartForm; import ru.ulstu.datamodel.ModelingResult; import ru.ulstu.datamodel.exception.ModelingException; import ru.ulstu.datamodel.ts.TimeSeries; import ru.ulstu.datamodel.ts.TimeSeriesValue; import ru.ulstu.db.DbService; import ru.ulstu.service.TimeSeriesService; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.time.format.DateTimeFormatter; import java.time.format.FormatStyle; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; import java.util.stream.Stream; @Controller @Hidden public class IndexController { private final TimeSeriesService timeSeriesService; private final DbService dbService; public IndexController(TimeSeriesService timeSeriesService, DbService dbService) { this.timeSeriesService = timeSeriesService; this.dbService = dbService; } @GetMapping("/") public String index(Model model) throws IOException { model.addAttribute("sets", dbService.getSets()); model.addAttribute("chartForm", new ChartForm()); return "index"; } @GetMapping("chart") public String chart(@ModelAttribute ChartForm chartForm, Model model) throws IOException, ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { model.addAttribute("sets", dbService.getSets()); if (chartForm.getSet() != null) { model.addAttribute("listTimeSeries", dbService.getTimeSeriesMeta(chartForm.getSet())); } if (chartForm.getTimeSeriesMeta() != null && chartForm.getTimeSeriesMeta().getKey() != null && !chartForm.getTimeSeriesMeta().getKey().isEmpty()) { addChartToModel(dbService.getTimeSeries(chartForm.getSet(), chartForm.getTimeSeriesMeta().getKey()), null, model); } return "index"; } private void addChartToModel(TimeSeries timeSeries, String method, Model model) throws ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, ModelingException { int countForecastPoints = timeSeries.getLength() > 20 ? 10 : timeSeries.getLength() / 3; TimeSeries timeSeriesModel; ModelingResult modelingResult; if (method == null) { timeSeriesModel = timeSeriesService.smoothTimeSeries(timeSeries).getTimeSeries(); modelingResult = timeSeriesService.getForecast(timeSeries, countForecastPoints); } else { timeSeriesModel = timeSeriesService.smoothTimeSeries(timeSeries, method).getTimeSeries(); modelingResult = timeSeriesService.getForecast(timeSeries, method, countForecastPoints); } TimeSeries forecast = modelingResult.getTimeSeries(); TimeSeries testForecast = modelingResult.getTestForecast(); model.addAttribute("dates", getDatesForChart(timeSeries, forecast)); model.addAttribute("timeSeries", timeSeries.getValues().stream().map(TimeSeriesValue::getValue).toArray()); // если временной ряд был сжат моделью, то для графика нужно вставить пустые значения TimeSeries modelWithSkips = new TimeSeries(timeSeriesModel.getKey()); int j = 0; for (int i = 0; i < timeSeries.getLength(); i++) { if (timeSeries.getValue(i).getDate().equals(timeSeriesModel.getValue(j).getDate())) { modelWithSkips.addValue(timeSeriesModel.getValue(j)); j++; } else { modelWithSkips.addValue(new TimeSeriesValue((Double) null)); } } model.addAttribute("model", modelWithSkips.getValues().stream().map(TimeSeriesValue::getValue).toArray()); timeSeries.getValues().remove(timeSeries.getValues().size() - 1); List forecastValues = timeSeries.getValues().stream().map(v -> (Double) null).collect(Collectors.toList()); forecastValues.addAll(forecast.getValues().stream().map(TimeSeriesValue::getValue).collect(Collectors.toList())); model.addAttribute("forecast", forecastValues.toArray()); List testForecastValues = timeSeries.getValues() .stream() .skip(countForecastPoints) .map(v -> (Double) null) .collect(Collectors.toList()); testForecastValues.addAll(testForecast.getValues().stream().map(TimeSeriesValue::getValue).collect(Collectors.toList())); model.addAttribute("testForecast", testForecastValues.toArray()); model.addAttribute("forecastDescription", modelingResult); } private List getDatesForChart(TimeSeries timeSeries, TimeSeries forecast) { return Stream.concat(timeSeries.getValues().stream(), forecast.getValues().stream()) .map(TimeSeriesValue::getDate) .sorted() .map(date -> date.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT))) .distinct() .collect(Collectors.toList()); } @GetMapping("/method") public String method(Model model) throws IOException { model.addAttribute("sets", dbService.getSets()); model.addAttribute("methods", timeSeriesService.getAvailableMethods()); model.addAttribute("chartForm", new ChartForm()); return "method"; } @GetMapping("chartMethod") public String chartMethod(@ModelAttribute ChartForm chartForm, Model model) throws IOException, ModelingException, ExecutionException, InterruptedException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException { model.addAttribute("sets", dbService.getSets()); model.addAttribute("methods", timeSeriesService.getAvailableMethods()); if (chartForm.getSet() != null && !chartForm.getSet().getKey().equals("")) { model.addAttribute("listTimeSeries", dbService.getTimeSeriesMeta(chartForm.getSet())); } if (chartForm.getTimeSeriesMeta() != null && chartForm.getTimeSeriesMeta().getKey() != null && !chartForm.getTimeSeriesMeta().getKey().isEmpty() && chartForm.getMethodClassName() != null && !chartForm.getMethodClassName().equals("")) { addChartToModel(dbService.getTimeSeries(chartForm.getSet(), chartForm.getTimeSeriesMeta().getKey()), chartForm.getMethodClassName(), model); } return "method"; } }