package at.vvo.omds.client.gui;

import at.vvo.omds.client.gui.api.apriori.AprioriAuskunftService;
import at.vvo.omds.client.gui.api.calc.CalculateRequestAuskunftService;
import at.vvo.omds.client.gui.api.SOAPConnector;
import at.vvo.omds.helpers.*;
import at.vvo.omds.types.omds3.r2025_05.common.*;
import at.vvo.omds.types.omds3.r2025_05.on2antrag.common.*;
import com.sun.xml.messaging.saaj.SOAPExceptionImpl;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.layout.*;
import javafx.scene.paint.Paint;
import javafx.scene.text.*;
import javafx.stage.Stage;
import javafx.util.Pair;
import org.controlsfx.control.ToggleSwitch;
import org.eclipse.rdf4j.model.Model;
import org.eclipse.rdf4j.query.GraphQuery;
import org.eclipse.rdf4j.query.QueryResults;
import org.eclipse.rdf4j.repository.Repository;
import org.eclipse.rdf4j.repository.RepositoryConnection;
import org.eclipse.rdf4j.repository.sail.SailRepository;
import org.eclipse.rdf4j.rio.RDFFormat;
import org.eclipse.rdf4j.rio.Rio;
import org.eclipse.rdf4j.sail.memory.MemoryStore;

import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.time.LocalDate;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class MainView extends Application {

    Map<String, Integer> timesItemisIncludedById = new HashMap<>();
    Map<TreeItem<GuiProdukt>, Map<AttributType, String>> infoBoxFromItem = new HashMap<>();
    List<Plausi> plausiList = new ArrayList<>();

    RisikoobjektView risikoobjektView = new RisikoobjektView();
    TreeHelper treeHelper = new TreeHelper();
    RDFHelper rdfHelper = new RDFHelper();

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) {

        stage.setTitle("OMDS Client");
        stage.getIcons().add(new Image(MainView.class.getResourceAsStream("/logo/VVO_Logo_2024.png")));

        TabPane tabPane = new TabPane();
        Tab baumView = new Tab("Deckungsbaum");
        Tab risikoView = new Tab("Risikoobjekte");

        baumView.setClosable(false);
        risikoView.setClosable(false);

        tabPane.getTabs().addAll(baumView, risikoView);

        BorderPane content = new BorderPane();
        StackPane view = new StackPane();
        GridPane risikoobjekt = risikoobjektView.risikoobjekte();
        VBox deckungsbaum = deckungsbaum();

        content.setTop(tabPane);
        content.setCenter(view);

        view.getChildren().addAll(risikoobjekt ,deckungsbaum);
        risikoobjekt.setVisible(false);


        tabPane.getSelectionModel().selectedItemProperty().addListener((obs, oldTab, newTab) -> {
            if (newTab == risikoView) {
                risikoobjekt.setVisible(true);
                deckungsbaum.setVisible(false);
            } else if (newTab == baumView) {
                risikoobjekt.setVisible(false);
                deckungsbaum.setVisible(true);
            }
        });

        Scene scene = new Scene(content, 900, 600);
        stage.setScene(scene);

        stage.show();
    }

    public VBox deckungsbaum(){
        AprioriAuskunftService s = new AprioriAuskunftService(new SOAPConnector());

        final VBox[] controlBox = {new VBox()};
        DatePicker dp = new DatePicker();
        ChoiceBox<String> vpBox = new ChoiceBox<>();

        vpBox.setValue("Verkaufsprodukt auswählen ");
        vpBox.setVisible(false);
        vpBox.setPadding(new Insets(0, 10, 0, 0));

        AtomicReference<XMLGregorianCalendar> stichtag = new AtomicReference<>();
        AtomicReference<ProductsResponse> response = new AtomicReference<>();
        Button newCalcRequestButton = new Button("Calculate");
        HBox newCalcRequestControlBox = new HBox();
        newCalcRequestControlBox.setVisible(false);
        newCalcRequestControlBox.setPadding(new Insets(10, 10, 10, 10));
        newCalcRequestControlBox.getChildren().add(newCalcRequestButton);

        HBox servBox = new HBox();
        ToggleSwitch serverBtn = new ToggleSwitch("Benutze RDF Messaging");
        serverBtn.setSelected(true);
        serverBtn.setDisable(true);

        AtomicReference<List<APrioriVerkaufsproduktType>> responseproduct = new AtomicReference<>(new ArrayList<>());

        dp.setOnAction(e -> {
            try {
                stichtag.set(stichtagEvent(dp));
                if (stichtagEvent(dp) != null) {
                    try {
                        Pair<List<APrioriVerkaufsproduktType>, List<Plausi>> aprioriPair = s.aprioriRDFAuskunft(stichtag.get(), "042");
                        responseproduct.set(aprioriPair.getKey());
                        plausiList = aprioriPair.getValue();

                        newCalcRequestControlBox.setVisible(true);

                        if (responseproduct.get().size() > 1) {
                            if (!vpBox.getItems().isEmpty()) {
                                vpBox.getItems().clear();
                            }
                            for (APrioriVerkaufsproduktType vp : responseproduct.get()) {
                                vpBox.getItems().add(vp.getName());
                            }
                            vpBox.setVisible(true);
                            vpBox.setOnAction(ee -> {
                                for (int i = 0; i < responseproduct.get().size(); i++) {
                                    if (vpBox.getSelectionModel().getSelectedItem() != null && vpBox.getSelectionModel()
                                            .getSelectedItem().equals(responseproduct.get().get(i).getName())) {
                                        try {
                                            controlBox[0] = buttonAuskunft(responseproduct.get().get(i),
                                                    controlBox[0], newCalcRequestButton, stichtag, serverBtn);
                                            controlBox[0].getChildren().add(newCalcRequestControlBox);

                                        } catch (Exception ex) {
                                            throw new RuntimeException(ex);
                                        }
                                    }
                                }
                            });
                        } else {
                            controlBox[0] = buttonAuskunft(responseproduct.get().getFirst(),
                                    controlBox[0], newCalcRequestButton, stichtag, serverBtn);
                        }
                    } catch (Exception rdfex) {
                        serverBtn.setSelected(false);

                        try {
                            response.set(s.aprioriAuskunft(stichtag.get(), "042"));

                            newCalcRequestControlBox.setVisible(true);
                            if (response.get() != null && response.get().getVerkaufsprodukt().size() > 1) {

                                if (!vpBox.getItems().isEmpty()) {
                                    vpBox.getItems().clear();
                                }
                                for (APrioriVerkaufsproduktType vp : response.get().getVerkaufsprodukt()) {
                                    vpBox.getItems().add(vp.getName());
                                }
                                vpBox.setVisible(true);
                                vpBox.setOnAction(ee -> {
                                    for (int i = 0; i < response.get().getVerkaufsprodukt().size(); i++) {
                                        if (vpBox.getSelectionModel().getSelectedItem() != null && vpBox.getSelectionModel()
                                                .getSelectedItem().equals(response.get().getVerkaufsprodukt().get(i).getName())) {
                                            try {
                                                controlBox[0] = buttonAuskunft(response.get().getVerkaufsprodukt().get(i),
                                                        controlBox[0], newCalcRequestButton, stichtag, serverBtn);
                                                controlBox[0].getChildren().add(newCalcRequestControlBox);

                                            } catch (Exception ex) {
                                                throw new RuntimeException(ex);
                                            }
                                        }
                                    }
                                });
                            } else {
                                controlBox[0] = buttonAuskunft(response.get().getVerkaufsprodukt().getFirst(),
                                        controlBox[0], newCalcRequestButton, stichtag, serverBtn);
                            }
                        } catch (NoSuchElementException ex) {
                            controlBox[0].getChildren().clear();
                            controlBox[0].getChildren().add(dp);
                            vpBox.getItems().clear();

                            Label label = new Label("Kein Verkaufsoffenes Produkt an dem Datum: " +
                                    stichtag.get().toString().substring(0, stichtag.get().toString().length() - 1) +
                                    System.lineSeparator());
                            controlBox[0].getChildren().add(3, label);
                            throw new NoSuchElementException(ex.getMessage());
                        } catch (SOAPExceptionImpl ex) {
                            HBox errorBox = new HBox();
                            errorBox.setAlignment(Pos.CENTER);
                            errorBox.setPadding(new Insets(10, 10, 10, 10));
                            errorBox.getChildren().add(new Text("Keine Verbindung zu einer Rdf oder SOAP Schnittstelle möglich!"));

                            controlBox[0].getChildren().add(errorBox);
                        }
                    }

                    if (!controlBox[0].getChildren().contains(newCalcRequestControlBox)) {
                        controlBox[0].getChildren().add(newCalcRequestControlBox);
                    }
                } else {
                    Alert alert = new Alert(Alert.AlertType.ERROR);
                    alert.setTitle("Error");
                    alert.setHeaderText("Invalid Date");
                    alert.showAndWait();
                }
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }

        });

        dp.setValue(LocalDate.now());

        Platform.runLater(() -> {
            dp.getOnAction().handle(new ActionEvent(dp, null));
        });

        VBox.setVgrow(newCalcRequestControlBox, Priority.ALWAYS);
        newCalcRequestControlBox.setAlignment(Pos.BOTTOM_RIGHT);
        newCalcRequestControlBox.setId("newCalcRequestControlBox");

        servBox.getChildren().add(serverBtn);
        servBox.setAlignment(Pos.TOP_RIGHT);

        HBox aprioriControlBox = new HBox();
        Region region = new Region();
        HBox.setHgrow(region, Priority.ALWAYS);
        aprioriControlBox.setPadding(new Insets(10, 10, 0, 10));
        aprioriControlBox.getChildren().addAll(dp, vpBox, region, servBox);

        controlBox[0].getChildren().addAll(aprioriControlBox);

        return controlBox[0];
    }

    public XMLGregorianCalendar stichtagEvent(DatePicker dp) throws DatatypeConfigurationException {
        if (dp.getValue() == null) {
            return null;
        }
        int day = dp.getValue().getDayOfMonth();
        int month = dp.getValue().getMonthValue();
        int year = dp.getValue().getYear();

        return DatatypeFactory.newInstance().newXMLGregorianCalendarDate(year, month, day, 0);
    }

    public VBox buttonAuskunft(APrioriVerkaufsproduktType verkaufsprodukt, VBox vbox, Button newCalcRequest,
                               AtomicReference<XMLGregorianCalendar> stichtag, ToggleSwitch serverBtn) throws Exception {
        while (vbox.getChildren().size() > 1) {
            vbox.getChildren().removeLast();
        }

        VBox treeBox = new VBox();
        VBox infoBox = new VBox();

        TreeItem<GuiProdukt> vkp = treeHelper.aprioriItemToCalcItem(new TreeItem<>(new GuiProdukt(verkaufsprodukt)));
        vkp.setExpanded(true);

        treeHelper.aprioriProduktToTree(verkaufsprodukt, vkp);

        TreeView<GuiProdukt> tv = new TreeView<>(vkp);
        

        tv.getSelectionModel().selectedItemProperty().addListener((obs, oldSelection, newSelection) -> {
            if (newSelection != null) {
                if (!infoBox.getChildren().isEmpty()) {
                    infoBox.getChildren().removeAll(infoBox.getChildren());
                }

                if (isMeldungVorhanden((ProduktbausteinType) newSelection.getValue().getProdukt(), tv)){
                    ((ProduktbausteinType) newSelection.getValue().getProdukt()).getAttribute().removeIf(a -> a.getBezeichnung().equals("Praemie"));
                }
                ItemAttribute itemAttribute = new ItemAttribute();
                itemAttribute.setRisikoobjekte(risikoobjektView.getRisikoobjekte());
                if (!infoBoxFromItem.isEmpty()) itemAttribute.setInfoBoxFromItem(infoBoxFromItem);

                itemAttribute.addItemInfo(newSelection, infoBox);
                if (newSelection.getValue().getProdukt() instanceof VerkaufsproduktType){
                    itemAttribute.addVpInfo(infoBox, isMeldungVorhanden((ProduktbausteinType) newSelection.getValue().getProdukt(), tv), (VerkaufsproduktType) newSelection.getValue().getProdukt());
                }
                infoBoxFromItem = itemAttribute.getInfoBoxFromItem();
            }else{
                infoBox.getChildren().removeAll(infoBox.getChildren());
            }
        });

        final TreeItem<GuiProdukt> originalRoot = treeHelper.cloneTreeItem(tv.getRoot());
        tv.setCellFactory(tc -> new TreeCell<>() {
            @Override
            public void updateItem(GuiProdukt item, boolean empty) {
                super.updateItem(item, empty);

                if (item == null || empty) {
                    setText(null);
                    setGraphic(null);
                    setStyle("");
                } else {
                    HBox cellBox = new HBox();
                    Button include = new Button("+");
                    include.setStyle("-fx-margin: 5;");
                    Label label = new Label(((ProduktbausteinType) item.getProdukt()).getBezeichnung() + " ");
                    Button remove = new Button("-");

                    remove.setVisible(true);
                    remove.setFont(Font.font("System", FontWeight.BOLD, include.getFont().getSize() + 2));
                    remove.setPadding(new Insets(0, 5, 0, 5));

                    include.setFont(Font.font("System", FontWeight.BOLD, include.getFont().getSize() + 2));
                    include.setPadding(new Insets(0, 5, 0, 5));

                    if (!shouldBeIncluded(getTreeItem())) {
                        label.setFont(Font.font("System", FontPosture.ITALIC, label.getFont().getSize()));
                        label.setTextFill(Paint.valueOf("#A0A0A0"));
                        if (!(getTreeItem().getValue().isNotIncluded())) {
                            getTreeItem().getValue().setNotIncluded(true);
                        }
                        remove.setDisable(true);
                        remove.setStyle("-fx-background-color: #CCCCCC");
                    } else {
                        label.setTextFill(Paint.valueOf("#000000"));
                        remove.setVisible(true);

                        getTreeItem().getValue().setNotIncluded(false);
                    }

                    Region spacer = new Region();
                    HBox.setHgrow(spacer, Priority.ALWAYS);
                    Label spacer2 = new Label(" ");

                    label.setMaxWidth(Double.MAX_VALUE);

                    if (getTreeItem().getValue().getProdukt() instanceof VerkaufsproduktType ||
                            getTreeItem().getValue().getClass().equals(APrioriVerkaufsproduktType.class)) {
                        cellBox.getChildren().addAll(label);
                    } else if (timesItemisIncludedById.get(
                            ((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getId()) != null
                            &&  ((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getMaxVorkommen() != null
                            && ((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getMaxVorkommen() <=
                            timeItemIsIncludedByParent(getTreeItem().getParent(),
                                    ((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getId())) {
                        include.setDisable(true);
                        include.setStyle("-fx-background-color: #CCCCCC");
                        cellBox.getChildren().addAll(label, spacer, include, spacer2, remove);
                    } else {
                        cellBox.getChildren().addAll(label, spacer, include, spacer2, remove);
                    }

                    include.setOnAction(e -> {
                        if (getTreeItem().getValue().isNotIncluded()) {
                            label.setFont(Font.font("System", label.getFont().getSize()));
                            label.setTextFill(Paint.valueOf("#000000"));
                            remove.setVisible(true);

                            timesItemisIncludedById.put(((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getId(),
                                    (timesItemisIncludedById.get(
                                            ((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getId()) != null ?
                                            timesItemisIncludedById.get(
                                                    ((ProduktbausteinType) getTreeItem().getValue().getProdukt()).getId()) + 1 : 1));

                            getTreeItem().getValue().setNotIncluded(false);
                            includeAddedParent(getTreeItem());
                            includeAddedChildren(getTreeItem());
                            tv.setRoot(treeHelper.sortTree(tv.getRoot()));
                            tv.refresh();
                            timesItemisIncludedById.clear();
                            refreshTimesItemisIncludedById(tv.getRoot());
                        } else {
                            TreeItem<GuiProdukt> parent = getTreeItem().getParent();
                            TreeItem<GuiProdukt> clone = null;
                            try {
                                clone = treeHelper.cloneTreeItem(
                                        treeHelper.findTreeItem((ProduktbausteinType) item.getProdukt(), tv.getRoot()));
                            } catch (Exception ex) {
                                throw new RuntimeException(ex);
                            }
                            parent.getChildren().add(clone);

                            timesItemisIncludedById.clear();
                            refreshTimesItemisIncludedById(tv.getRoot());

                            tv.setRoot(treeHelper.sortTree(tv.getRoot()));
                            tv.refresh();
                        }

                        TreeItem<GuiProdukt> newRoot = checkPlausis(plausiList, tv.getRoot(), verkaufsprodukt);
                        if (newRoot != null) {
                            newRoot.setExpanded(true);
                            tv.setRoot(newRoot);
                            tv.refresh();
                        }
                    });

                    remove.setOnAction(e -> {
                        Map<String, Integer> countByParent = new HashMap<>();
                        Map<String, Integer> countByAprioriParent = new HashMap<>();
                        timesItemisIncludedById.clear();
                        refreshTimesItemisIncludedById(tv.getRoot());
                        timesItemisIncludedById.replace(((ProduktbausteinType) item.getProdukt()).getId(),
                                timesItemisIncludedById.get(((ProduktbausteinType) item.getProdukt()).getId()) - 1);

                        if (countChildIds(countByParent, getTreeItem().getParent()).get
                                (((ProduktbausteinType) item.getProdukt()).getId()).equals(countChildIds(countByAprioriParent,
                                treeHelper.findTreeItem(((ProduktbausteinType) item.getProdukt()), originalRoot).getParent()).get(
                                        ((ProduktbausteinType) item.getProdukt()).getId()))) {
                            label.setFont(Font.font("System", label.getFont().getSize()));
                            label.setTextFill(Paint.valueOf("#A0A0A0"));
                            remove.setVisible(false);

                            getTreeItem().getValue().setNotIncluded(true);
                            includeAddedChildren(getTreeItem());

                            tv.setRoot(treeHelper.sortTree(tv.getRoot()));
                            tv.refresh();
                        } else {
                            getTreeItem().getParent().getChildren().remove((getTreeItem()));
                        }

                        TreeItem<GuiProdukt> newRoot = checkPlausis(plausiList, tv.getRoot(), verkaufsprodukt);
                        if (newRoot != null) {
                            newRoot.setExpanded(true);

                            tv.setRoot(newRoot);
                            tv.refresh();
                        }

                        timesItemisIncludedById.clear();
                        refreshTimesItemisIncludedById(tv.getRoot());
                    });

                    if(((ProduktbausteinType) item.getProdukt()).getMeldungen() != null && !((ProduktbausteinType) item.getProdukt()).getMeldungen().isEmpty()) {
                        AtomicBoolean symboleAdded = new AtomicBoolean(false);
                        Text symbole = new Text("\u26A0 ");
                        symbole.setFont(Font.font("System", FontWeight.BOLD, symbole.getFont().getSize() + 2));


                        ((ProduktbausteinType) item.getProdukt()).getMeldungen().forEach(m -> {
                            if(m.getErrorType().equals(BigInteger.ONE)) {
                                symbole.setFill(Paint.valueOf("#aa3333"));
                                symboleAdded.set(true);
                            }
                            if (m.getErrorType().equals(BigInteger.TWO) && !symboleAdded.get()) {
                                symbole.setFill(Paint.valueOf("#ccbb00"));
                            }
                        });
                        cellBox.getChildren().addFirst(symbole);
                    }else {
                        if (cellBox.getChildren().getFirst() instanceof Text && ((Text)cellBox.getChildren().getFirst()).getText().equals("\u26A0")) {
                            cellBox.getChildren().removeFirst();
                        }
                    }
                    setGraphic(cellBox);
                    setText(null);
                }
            }
        });

        newCalcRequest.setOnAction(e -> {
            try {
                TreeItem<GuiProdukt> cleanedRoot = treeHelper.cleanTree(tv.getRoot());


                CalculateRequestAuskunftService s = new CalculateRequestAuskunftService(new SOAPConnector());
                TreeItem<GuiProdukt> newRoot = new TreeItem<>(cleanedRoot.getValue());
                treeHelper.setTimesItemisIncludedById(timesItemisIncludedById);
                if (serverBtn.isSelected()) {
                    VerkaufsproduktType calcResponse = s.calculateRDFAuskunft(new TreeView<>(cleanedRoot), stichtag.get());
                    newRoot.getValue().setProdukt(calcResponse);
                    treeHelper.produktToTree(calcResponse, newRoot);
                }else {
                    CalculateResponse calcResponse = s.calculateAuskunft(new TreeView<>(cleanedRoot), stichtag.get());
                    newRoot.getValue().setProdukt(calcResponse.getBerechnungsantwort().getVerkaufsprodukt());
                    treeHelper.produktToTree(calcResponse.getBerechnungsantwort().getVerkaufsprodukt(), newRoot);
                }

                timesItemisIncludedById = treeHelper.getTimesItemisIncludedById();
                newRoot.setExpanded(true);

                TreeItem<GuiProdukt> finalRoot = checkPlausis(plausiList, newRoot, verkaufsprodukt);
                if (finalRoot != null) {
                    finalRoot.setExpanded(true);
                    tv.setRoot(finalRoot);
                } else {
                    newRoot = treeHelper.addAprioriToCalc(newRoot, originalRoot);
                    newRoot = treeHelper.sortTree(newRoot);
                    tv.setRoot(newRoot);
                }



                timesItemisIncludedById.clear();

                refreshTimesItemisIncludedById(tv.getRoot());

                tv.refresh();
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        });

        if (!treeBox.getChildren().isEmpty()) {
            treeBox.getChildren().clear();
        }

        tv.setRoot(treeHelper.sortTree(tv.getRoot()));

        VBox.setVgrow(tv, Priority.ALWAYS);
        tv.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        tv.setStyle("-fx-border-color: white;");

        treeBox.getChildren().add(tv);
        treeBox.setPadding(new Insets(10));
        treeBox.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        HBox.setHgrow(treeBox, Priority.ALWAYS);
        treeBox.setStyle("-fx-border-color: black; -fx-background-color: white");

        infoBox.setStyle("-fx-border-color: black; -fx-background-color: white");
        infoBox.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
        HBox.setHgrow(infoBox, Priority.ALWAYS);

        HBox splitBox = new HBox(treeBox, infoBox);
        splitBox.setId("splitBox");
        splitBox.setSpacing(10);
        splitBox.setPadding(new Insets(20));
        splitBox.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);

        VBox wrapper = new VBox(splitBox);
        wrapper.setAlignment(Pos.CENTER);
        VBox.setVgrow(splitBox, Priority.ALWAYS);

        HBox logWrapper = new HBox();
        logWrapper.setPadding(new Insets(0, 20, 20, 20)); // Abstand zum Rand unten + Seite
        logWrapper.setAlignment(Pos.CENTER_LEFT);
        logWrapper.setMaxWidth(Double.MAX_VALUE);

        vbox.getChildren().addAll(wrapper);
        VBox.setVgrow(wrapper, Priority.ALWAYS);

        return vbox;
    }

    private void includeAddedParent(TreeItem<GuiProdukt> treeItem) {
        if (treeItem.getParent() != null) {
            treeItem.getParent().getValue().setNotIncluded(false);
            if (treeItem.getParent().getParent() != null) {
                includeAddedParent(treeItem.getParent());
            }
        }
    }

    private void includeAddedChildren(TreeItem<GuiProdukt> parent) {
        for (int i = 0; i < parent.getChildren().size(); i++) {
            parent.getChildren().get(i).getValue().setNotIncluded(false);
            if (!shouldBeIncluded(parent.getChildren().get(i)) && !(parent.getChildren().get(i).getValue().isNotIncluded())) {
                parent.getChildren().get(i).getValue().setNotIncluded(true);
            } else {
                parent.getChildren().get(i).getValue().setNotIncluded(false);
            }

            if (!parent.getChildren().get(i).getChildren().isEmpty() && parent.getChildren().get(i).getChildren() != null) {
                includeAddedChildren(parent.getChildren().get(i));
            }
        }
    }

    public boolean shouldBeIncluded(TreeItem<GuiProdukt> treeItem) {
        return !(((treeItem.getParent() != null && treeItem.getParent().getValue().isNotIncluded()) || treeItem.getValue().isNotIncluded() ||
                (((ProduktbausteinType) treeItem.getValue().getProdukt()).getMinVorkommen() != null && ((ProduktbausteinType) treeItem.getValue().getProdukt()).getMinVorkommen() == 0 &&
                        (timesItemisIncludedById.get(((ProduktbausteinType) treeItem.getValue().getProdukt()).getId()) == null ||
                                timesItemisIncludedById.get(((ProduktbausteinType) treeItem.getValue().getProdukt()).getId()) == 0))) &&
                !(treeItem.getValue().getProdukt() instanceof VerkaufsproduktType));
    }

    private Map<String, Integer> countChildIds(Map<String, Integer> count, TreeItem<GuiProdukt> root) {
        if (root != null) {
            for (int i = 0; i < root.getChildren().size(); i++) {
                TreeItem<GuiProdukt> item = root.getChildren().get(i);

                if (count.get(((ProduktbausteinType) item.getValue().getProdukt()).getId()) == null) {
                    count.put(((ProduktbausteinType) item.getValue().getProdukt()).getId(), 1);
                } else {
                    count.replace(((ProduktbausteinType) item.getValue().getProdukt()).getId(),
                            count.get(((ProduktbausteinType) item.getValue().getProdukt()).getId()) + 1);
                }

                if (!item.getChildren().isEmpty()) {
                    countChildIds(count, item);
                }
            }
        }
        return count;

    }

    private void refreshTimesItemisIncludedById(TreeItem<GuiProdukt> root) {
        for (int i = 0; i < root.getChildren().size(); i++) {
            TreeItem<GuiProdukt> item = root.getChildren().get(i);
            if (!item.getValue().isNotIncluded()) {
                if (timesItemisIncludedById.get(((ProduktbausteinType) item.getValue().getProdukt()).getId()) == null) {
                    timesItemisIncludedById.put(((ProduktbausteinType) item.getValue().getProdukt()).getId(), 1);
                } else {
                    timesItemisIncludedById.replace(((ProduktbausteinType) item.getValue().getProdukt()).getId(),
                            timesItemisIncludedById.get(((ProduktbausteinType) item.getValue().getProdukt()).getId()) + 1);
                }
            }
            if (!item.getChildren().isEmpty()) {
                refreshTimesItemisIncludedById(item);
            }
        }
    }

    public int timeItemIsIncludedByParent(TreeItem<GuiProdukt> parent, String itemId) {
        int erg = 0;
        for (int i = 0; i < parent.getChildren().size(); i++) {
            TreeItem<GuiProdukt> item = parent.getChildren().get(i);
            if (((ProduktbausteinType) item.getValue().getProdukt()).getId().equals(itemId)) {
                if (!item.getValue().isNotIncluded()) {
                    erg++;
                }
            }

        }

        return erg;
    }
    public boolean isMeldungVorhanden(ProduktbausteinType produkt, TreeView<GuiProdukt> tv) {
        TreeHelper treeHelper = new TreeHelper();
        TreeItem<GuiProdukt> actual = treeHelper.findTreeItem(produkt, tv.getRoot());

        if (actual != null && ((ProduktbausteinType)actual.getValue().getProdukt()).getMeldungen() != null && !((ProduktbausteinType)actual.getValue().getProdukt()).getMeldungen().isEmpty()) {
            return true;
        }
        for (ProduktbausteinType child : produkt.getBausteine()){
            if(isMeldungVorhanden(child, tv)) return true;
        }
        return false;
    }

    public TreeItem<GuiProdukt> checkPlausis(List<Plausi> plausiList, TreeItem<GuiProdukt> vp, APrioriProduktbausteinType verkaufsprodukt){
        Repository repo = new SailRepository(new MemoryStore());
        repo.init();

        try (RepositoryConnection conn = repo.getConnection()) {
            Model model = rdfHelper.createRdfModel(vp);

            conn.add(model);

            plausiList.stream().filter(p -> p.getArt().equals("update")).forEach(p -> {
                String query = p.getQuery();

                conn.prepareUpdate(query).execute();
            });

            model.clear();
            conn.getStatements(null, null, null).forEach(model::add);

            plausiList.stream().filter(p -> p.getArt().equals("graph")).forEach(p -> {
                String sparql = p.getQuery();

                GraphQuery q = conn.prepareGraphQuery(sparql);
                Model validatedModel = QueryResults.asModel(q.evaluate());

                model.addAll(validatedModel);
            });

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            Rio.write(model, baos, RDFFormat.JSONLD);

            VerkaufsproduktType neuRoot = rdfHelper.calculateRequestToVerkaufsprodukt(baos.toString());
            TreeItem<GuiProdukt> newRoot = new TreeItem<>(new GuiProdukt(neuRoot));
            newRoot.setExpanded(true);

            try {
                treeHelper.produktToTree(neuRoot, newRoot);

                TreeItem<GuiProdukt> aprioriTree = new TreeItem<>();
                treeHelper.aprioriProduktToTree(verkaufsprodukt, aprioriTree);

                return (treeHelper.sortTree(treeHelper.addAprioriToCalc(newRoot, aprioriTree)));
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        } catch(Exception ignored) {
            ignored.printStackTrace();
            System.out.println("CheckPlausi: " + ignored.getMessage());
            return null;
        }
    }
}
