package com.github.bfh.study.slb.imports.parser;

import java.util.List;
import java.util.Optional;
import javax.xml.stream.EventFilter;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

/**
 * This filter accepts only elements that will process with JAXB later.
 *
 * @author Samuel Ackermann
 */
public class ElementEventFilter implements EventFilter {

    private ProcessingElement actualElement;

    private DecisionStore store;

    private List<ProcessingElement> interestedElements;

    public ElementEventFilter(List<ProcessingElement> interestedElements) {
        this.interestedElements = interestedElements;
    }

    @Override
    public boolean accept(XMLEvent event) {
        // Why a store? It could be that the same event is fired several times
        if (store != null && store.event.equals(event)) {
            return store.decision;
        }
        // create new store for storing decision
        store = new DecisionStore(false, event);

        if (actualElement == null && event.isStartElement()) {
            handleStartElement(event.asStartElement());
        } else if (actualElement != null && event.isEndElement()) {
            handleEndElement(event.asEndElement());
        // actualClass != null means a tag was found in the xml that we will parse
        // all sub tags are acceptable
        } else if (actualElement != null) {
            store.decision = true;
        }

        return store.decision;
    }

    /**
     * returns actual processing class.
     *
     * @return Class actual class
     */
    public Class<?> getActualClass() {
        if (actualElement != null) {
            return actualElement.getLinkedClass();
        }
        return null;
    }

    private void handleStartElement(StartElement startElement) {
        Optional<ProcessingElement> optional = searchClass(startElement.getName().getLocalPart());
        if (optional.isPresent()) {
            actualElement = optional.get();
            store.decision = true;
        }
    }

    private void handleEndElement(EndElement endElement) {
        String actualTagName = actualElement.getTagName();
        if (actualTagName.equals(endElement.getName().getLocalPart())) {
            actualElement = null;
        }
        store.decision = true;
    }

    private Optional<ProcessingElement> searchClass(String tagName) {
        return interestedElements.stream()
                .filter(element -> element.getTagName().equals(tagName))
                .findFirst();
    }

    /**
     * stores the last decision from the decision tree.
     *
     * @author Samuel Ackermann
     */
    private class DecisionStore {

        boolean decision;

        XMLEvent event;

        DecisionStore(boolean decision, XMLEvent event) {
            this.decision = decision;
            this.event = event;
        }
    }
}

@@ -471,24 +471,80 @@
 alElement;%0A%0A
+    private int level;%0A%0A    private int capturedLevel;%0A%0A
     private 
@@ -564,16 +564,16 @@
  store;%0A
-
 %0A    pri
@@ -752,16 +752,62 @@
 ements;%0A
+        level = 0;%0A        capturedLevel = 0;%0A
     %7D%0A%0A 
@@ -878,22 +878,59 @@
  // 
-Why a store? I
+Store the event internal?%0A        // Yes, because i
 t co
@@ -1181,16 +1181,109 @@
 vent);%0A%0A
+        // Store level%0A        if (event.isStartElement()) %7B%0A            level++;%0A        %7D%0A%0A
         
@@ -1715,32 +1715,122 @@
  true;%0A        %7D
+%0A        // Store level%0A        if (event.isEndElement()) %7B%0A            level--;%0A        %7D
 %0A%0A        return
@@ -2307,27 +2307,87 @@
 .isPresent()
-) %7B
+ && actualElement == null) %7B%0A            capturedLevel = level;
 %0A           
@@ -2658,16 +2658,42 @@
 lPart())
+ && capturedLevel == level
 ) %7B%0A    
@@ -2718,24 +2718,55 @@
 ent = null;%0A
+            capturedLevel = 0;%0A
         %7D%0A  

extend element filter with logic. Track deep of a xml tree