package de.ph87.data.view.tree; import de.ph87.data.point.Point; import de.ph87.data.view.ViewScope; import jakarta.persistence.*; import lombok.*; import java.util.ArrayList; import java.util.List; import java.util.function.BiFunction; @Entity @Getter @Setter @NoArgsConstructor @ToString(callSuper = true) @DiscriminatorValue("binary") public class ViewBinary extends View { @NonNull @Enumerated(EnumType.STRING) private Operation operation; @NonNull @OneToOne(optional = false, orphanRemoval = true, cascade = CascadeType.ALL) private View view0; @NonNull @OneToOne(optional = false, orphanRemoval = true, cascade = CascadeType.ALL) private View view1; public ViewBinary(@NonNull final Operation operation, @NonNull final View view0, @NonNull final View view1) { this.operation = operation; this.view0 = view0; this.view1 = view1; } public enum Operation { PLUS(Double::sum), MINUS((a, b) -> a - b), MULTIPLY((a, b) -> a * b), DIVIDE((a, b) -> a / b), MODULO((a, b) -> a % b), PERCENT((a, b) -> a / b * 100), ; public final BiFunction function; Operation(final BiFunction function) { this.function = function; } @NonNull public Point apply(@NonNull final Point a, @NonNull final Point b) { return new Point(a.date, function.apply(a.value, b.value)); } } @Override public List getPoints(final @NonNull ViewScope scope) { final List pointsA = view0.getPoints(scope); final List pointsB = view1.getPoints(scope); final List result = new ArrayList<>(pointsA.size() + pointsB.size()); int indexA = 0; int indexB = 0; while (indexA < pointsA.size() && indexB < pointsB.size()) { final Point pointA = pointsA.get(indexA); final Point pointB = pointsB.get(indexB); int cmp = pointA.date.compareTo(pointB.date); if (cmp < 0) { indexA++; } else if (cmp > 0) { indexB++; } else { result.add(operation.apply(pointA, pointB)); indexA++; indexB++; } } return result; } }