fujaba/NetworkParser

View on GitHub
src/main/java/de/uniks/networkparser/graph/Pattern.java

Summary

Maintainability
D
2 days
Test Coverage
package de.uniks.networkparser.graph;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import de.uniks.networkparser.IdMap;
import de.uniks.networkparser.SimpleEvent;
import de.uniks.networkparser.ext.PatternCondition;
import de.uniks.networkparser.interfaces.ObjectCondition;
import de.uniks.networkparser.interfaces.SendableEntityCreator;
import de.uniks.networkparser.list.SimpleIterator;
import de.uniks.networkparser.list.SimpleList;
import de.uniks.networkparser.list.SimpleSet;

public class Pattern implements Iterator<Object>, Iterable<Object>, ObjectCondition {
    public static final String MODIFIER_SEARCH = "search";
    public static final String MODIFIER_CHANGE = "change";
    public static final String MODIFIER_ADD = "add";
    public static final String MODIFIER_REMOVE = "remove";
    public static final String MODIFIER_ROLE = "role";
    private Object match;
    private String modifier = MODIFIER_SEARCH;

    private SimpleSet<Pattern> children;
    private Pattern parent;
    private SimpleSet<Object> candidates = null;
    private ObjectCondition condition;
    private IdMap map;
    private SimpleIterator<Object> iterator;
    private SimpleSet<Pattern> chain;

    public Pattern getRoot() {
        if (this.getParent() != null) {
            return this.getParent().getRoot();
        }
        return this;
    }

    public IdMap getMap() {
        return getRoot().map;
    }

    public Pattern(IdMap map, Object match) {
        this();
        this.match = match;
        this.map = map;
        if (candidates == null) {
            candidates = new SimpleSet<Object>();
        }
        this.candidates.add(match);
    }
    
    public Pattern withCondition(ObjectCondition condition) {
        this.condition = condition;
        return this;
    }

    public Pattern() {
        this.chain = new SimpleSet<Pattern>();
        this.chain.add(this);
    }

    public Pattern(Pattern parent, ObjectCondition condition) {
        if (parent != null) {
            this.parent = parent;
            parent.addToChain(this);
        }
        this.condition = condition;
    }

    public Pattern has(String property) {
        return has(PatternCondition.create(property));
    }

    public Pattern has(ObjectCondition condition) {
        Pattern root = getRoot();
        if (root != this && this.condition == null) {
            this.condition = condition;
            return this;
        }
        Pattern subPattern = new Pattern(this, condition);
        if (children == null) {
            children = new SimpleSet<Pattern>();
        }
        this.children.add(subPattern);
        if (MODIFIER_SEARCH.equals(this.modifier)) {
            subPattern.find();
        }
        return subPattern;
    }

    private boolean addToChain(Pattern value) {
        SimpleSet<Pattern> myChain = getChain();
        if (myChain != null) {
            return myChain.add(value);
        }
        return false;
    }

    public static <T> SimpleList<T> createListOfType(Class<T> type) {
        return new SimpleList<T>();
    }

    @SuppressWarnings("unchecked")
    public <ST extends List<Object>> ST allMatches() {
        if (this.match == null) {
            find();
        }
        if (match == null) {
            return (ST) new SimpleList<Object>();
        }
        SimpleList<? extends Object> result = createListOfType(match.getClass());
        while (find()) {
            result.add(this.match);
        }
        return (ST) result;
    }

    public Object getMatch() {
        return match;
    }

    @SuppressWarnings("unchecked")
    public <ST extends Object> ST getMatch(Class<ST> clazz) {
        return (ST) match;
    }
    
    public boolean find(Object condition) {
        this.withCandidates(condition);
        return find();
    }

    public boolean find() {
        SimpleSet<Pattern> chain = getChain();
        if (chain == null) {
            return false;
        }
        Pattern last = chain.last();
        if (last == this) {
            return finding(true);
        }
        return last.finding(true);
    }

    public SimpleSet<Pattern> getChain() {
        return getRoot().chain;
    }

    @Override
    public boolean hasNext() {
        SimpleSet<Pattern> chain = getChain();
        if (chain == null) {
            return false;
        }
        Pattern last = chain.last();
        if (last == this) {
            return finding(false);
        }
        return last.finding(false);
    }

    private boolean findCondition(String modifier) {
        if(condition == null) {
            return false;
        }
        if(condition instanceof Pattern) {
            return condition.update(this);
        }
        if(MODIFIER_ROLE.equalsIgnoreCase(modifier)) {
            SimpleIterator<Object> iterator = getIterator();
            if(iterator != null) {
                PatternEvent event = new PatternEvent(this, MODIFIER_SEARCH);
                while(iterator.hasNext()) {
                    Object candidate = iterator.next();
                    event.setCandidate(candidate);
                    if(condition.update(event)) {
                        return true;
                    }
                }
            }
        }
        return condition.update(this);
    }
    
    private boolean finding(boolean save) {
        /* Backwards */
        
        if (findCondition(null) == false) {
            /* Not found */
            if (parent == null) {
                return false; 
            }
            boolean finding = parent.finding(save);
            if (save) {
                this.candidates = null;
                this.match = null;
                this.iterator = null;
                if (condition != null) {
                    findCondition(MODIFIER_ROLE);
                }
            }

            if (finding == false) {
                return this.match != null;
            }
            if (children != null) {
                for (Pattern child : children) {
                    finding = child.find();
                    if (finding == false) {
                        break;
                    }
                }
                if (finding == false) {
                    return false;
                }
            }
        }
        if (save) {
            this.match = iterator.current();
            applyPattern();
        }
        return this.match != null;
    }

    @Override
    public Object next() {
        if (find()) {
            return getMatch();
        }
        return null;
    }

    @Override
    public Iterator<Object> iterator() {
        return this;
    }

    public SimpleSet<Object> getCandidates() {
        return candidates;
    }

    public Pattern getParent() {
        return parent;
    }

    public Pattern withCandidates(Object newValue) {
        if (this.candidates == null) {
            this.candidates = new SimpleSet<Object>();
            this.iterator = (SimpleIterator<Object>) this.candidates.iterator();
            this.iterator.withCheckPointer(false);
        }
        if (newValue instanceof Collection<?>) {
            this.candidates.withList((Collection<?>) newValue);
        } else {
            this.candidates.with(newValue);
        }
        return this;
    }

    public SimpleIterator<Object> getIterator() {
        return iterator;
    }

    public Pattern withMatch(Object candidate) {
        this.match = candidate;
        return this;
    }

    public boolean applyPattern() {
        if (MODIFIER_SEARCH.equals(this.modifier)) {
            return true;
        }
        /* Go throw all Matches */
        SimpleSet<Pattern> chain = getChain();

        /* FROM LAST TO FIRST */
        for (int i = 0; i < chain.size(); i++) {
            Pattern pattern = chain.get(i);
            pattern.appling();
        }
        return true;
    }

    public boolean appling() {
        if (condition instanceof PatternCondition == false) {
            return false;
        }
        PatternCondition patternCondition = (PatternCondition) condition;
        if (MODIFIER_ADD.equals(this.modifier)) {
            if (this.match == null) {
                return false;
            }
            Object value = patternCondition.getValue();
            String clazzName = "" + value;
            SendableEntityCreator creatorClass = getMap().getCreator(clazzName, true);
            if (creatorClass != null) {
                this.match = creatorClass.getSendableInstance(false);
                if (this.parent != null) {
                    this.parent.setValue(patternCondition.getLinkName(), this.match);
                }
            }
            return true;
        }
        if (MODIFIER_CHANGE.equals(this.modifier)) {
            if (this.parent != null) {
                this.parent.setValue(patternCondition.getLinkName(), patternCondition.getValue());
            }
            return true;
        }
        if (MODIFIER_REMOVE.equals(this.modifier)) {
            SendableEntityCreator creatorClass = getMap().getCreatorClass(this.match);
            if (creatorClass instanceof SendableEntityCreator) {
                ((SendableEntityCreator) creatorClass).setValue(this.match, null, null,
                        SendableEntityCreator.REMOVE_YOU);
            }
            return true;
        }
        return false;
    }

    public boolean setValue(String property, Object value) {
        if (this.match != null) {
            SendableEntityCreator creatorClass = getMap().getCreatorClass(this.match);
            creatorClass.setValue(this.match, property, value, SendableEntityCreator.NEW);
        }
        return false;
    }

    @Override
    public boolean update(Object value) {
        if(value == null) {
            return false;
        }
         if(value instanceof Clazz) {
            return false;
        } 
        Object item = null;
        if(value instanceof SimpleEvent) {
            String linkName;
            SimpleEvent event = (SimpleEvent) value;
            item = event.getNewValue();
            PatternEvent pe = (PatternEvent) event;
            Object id = event.getPropagationId();
            if(id instanceof String) {
                linkName = (String) id;
            }else {
                linkName = event.getPropertyName();
                }
            IdMap map = this.getMap();
            SendableEntityCreator creator = map.getCreatorClass(item);
            if (creator != null) {
                Object newValue = creator.getValue(item, linkName);
                pe.addCandidate(newValue);
                return true;
            }
        }else {
            item = value;
        }
        return item != null;
    }

    public Pattern withMap(IdMap map) {
        this.map = map;
        return this;
    }
}