fujaba/NetworkParser

View on GitHub
src/main/java/de/uniks/networkparser/ext/story/CucumberStdRule.java

Summary

Maintainability
F
1 wk
Test Coverage
package de.uniks.networkparser.ext.story;

import de.uniks.networkparser.ext.PatternCondition;
import de.uniks.networkparser.graph.Association;
import de.uniks.networkparser.graph.Attribute;
import de.uniks.networkparser.graph.AttributeSet;
import de.uniks.networkparser.graph.Clazz;
import de.uniks.networkparser.graph.ClazzSet;
import de.uniks.networkparser.graph.DataType;
import de.uniks.networkparser.graph.GraphList;
import de.uniks.networkparser.graph.GraphMember;
import de.uniks.networkparser.graph.GraphModel;
import de.uniks.networkparser.graph.GraphTokener;
import de.uniks.networkparser.graph.GraphUtil;
import de.uniks.networkparser.graph.Pattern;
import de.uniks.networkparser.interfaces.ObjectCondition;
import de.uniks.networkparser.list.SimpleKeyValueList;
import de.uniks.networkparser.list.SimpleSet;
import de.uniks.networkparser.logic.And;
import de.uniks.networkparser.logic.Equals;
import de.uniks.networkparser.logic.InstanceOf;
import de.uniks.networkparser.logic.StringCondition;
import de.uniks.networkparser.parser.Token;

public class CucumberStdRule implements ObjectCondition {
    private Cucumber cucumber;
    private SimpleKeyValueList<String, ClazzSet> assocs = new SimpleKeyValueList<String, ClazzSet>();
    private ClazzSet clazzSet = new ClazzSet();
    private GraphList model;
    private ClazzSet attributeSet;

    @Override
    public boolean update(Object value) {
        if (value instanceof Cucumber) {
            return analyseCucumber((Cucumber) value);
        }
        return false;
    }

    public boolean analyseCucumber(Cucumber cucumber) {
        this.cucumber = cucumber;

        analyseDefinition(cucumber.getDefinition());

        GraphList model = new GraphList().withType(GraphTokener.OBJECTDIAGRAM);
        if (analyseTokens(cucumber.getGiven(), model) == false) {
            return false;
        }
        this.model = model;
        this.cucumber.withModel(model);
        
        
        // Now Analyse WHEN BLOCK
        model = new GraphList().withType(GraphTokener.OBJECTDIAGRAM);
        if (analyseTokens(cucumber.getWhen(), model) == false) {
            return false;
        }
        Pattern pattern = new Pattern();
        SimpleSet<GraphMember> visited=new SimpleSet<GraphMember>(); 
        for(Clazz clazz : model.getClazzes()) {
            pattern.withCondition(this.analysePattern(new And(), clazz, visited));
            //FIXME AND INCLUDE VISITED
            break;
        }
        this.cucumber.withPattern(pattern);
        return true;
    }

    private ObjectCondition analysePattern(And parent, Clazz clazz, SimpleSet<GraphMember> visited) {
        if(clazz == null) {
            return null;
        }
        if(visited.add(clazz) == false) {
            return null;
        }
        if(parent == null) {
            parent = new And();
        }
        
        // Copy to New One
        InstanceOf condition = InstanceOf.create(clazz);
        parent.add(condition);
        for(Association assoc : clazz.getAssociations()) {
            parent.add(analysePattern(assoc, visited));
        }
        for(Attribute attr : clazz.getAttributes()) {
            parent.add(analysePattern(attr, visited));
        }
        if(parent.size()==1) {
            return parent.first(); 
        }
        return parent;
    }

    private ObjectCondition analysePattern(Association assoc, SimpleSet<GraphMember> visited) {
        if(assoc == null) {
            return null;
        }
        Association other = assoc.getOther();
        if(visited.add(assoc) == false || visited.add(other) == false) {
            return null;
        }
        And parent = new And();
        parent.add(PatternCondition.create(other.getName()));
        Clazz clazz = other.getClazz();
        
        analysePattern(parent, clazz, visited);
        
        return parent;
    }

    private ObjectCondition analysePattern(Attribute attribute, SimpleSet<GraphMember> visited) {
        if(attribute == null) {
            return null;
        }
        String value = attribute.getValue();
        
        Object newValue = GraphUtil.getValue(attribute.getType(), value);
        if(newValue == null) {
            return null;
        }
        return Equals.create(attribute.getName(), newValue);
    }
        
    protected SimpleSet<Token> splitText(String values) {
        Token token = new Token().addKind(Token.UNKNOWN);
        SimpleSet<Token> result = new SimpleSet<Token>();
        for (int i = 0; i < values.length(); i++) {
            char c = values.charAt(i);
            if (c == ' ') {
                result.add(token);
                token = new Token().addKind(Token.UNKNOWN);
                continue;
            }
            if (c == '.') {
                if (token.length() > 0) {
                    result.add(token);
                }
                result.add(new Token().addText('.').addKind(Token.POINT));
                token = new Token().addKind(Token.UNKNOWN);
                continue;
            }
            token.addText(c);
        }
        result.add(token);
        return result;
    }

    private boolean analyseDefinition(SimpleKeyValueList<String, Boolean> values) {
        for (int i = 0; i < values.size(); i++) {
            String string = values.getKeyByIndex(i);
            String[] token = string.split(" ");
            char[] types = new char[token.length];
            int z;
            int isPos = 0;
            int andPos = 0;
            for (z = 0; z < token.length; z++) {
                if (types[z] == 0) {
                    types[z] = Token.UNKNOWN;
                    if(cucumber.getTypeDictionary(token[z])!= null) {
                        // May be Attribute
                        if(this.analyseTokenForAttribute(token)) {
                            break;
                        }
                    }
                }
                Character type = cucumber.getTokenType(token[z]);
                if (type != null) {
                    types[z] = type;
                    if (type == Token.DEFINITION) {
                        isPos = z;
                    }
                    continue;
                }
                if (token[z].equalsIgnoreCase("and")) {
                    andPos = z;
                    types[z] = Token.AND;
                    types[z - 1] = Token.NOMEN;
                    types[z + 1] = Token.NOMEN;
                    continue;
                }
                types[z] = Token.NOMEN;
            }
            if (isPos > 0) {
                int target = -1;
                if (andPos < 1) {
                    /* A Single Definition */
                    int source = 0;
                    for (z = isPos; z < token.length; z++) {
                        if (types[z] == Token.NOMEN) {
                            target = z;
                            break;
                        }
                    }
                    for (z = 0; z < isPos; z++) {
                        if (types[z] == Token.NOMEN) {
                            source = z;
                            break;
                        }
                    }
                    if (source >= 0 && target > 0) {
                        cucumber.addTypeDicitonary(token[source], token[target]);
                    }
                } else {
                    if (andPos > isPos) {
                        /* Target is Source and Source */
                        for (z = 0; z < isPos; z++) {
                            if (types[z] == Token.NOMEN) {
                                target = z;
                                break;
                            }
                        }
                        if (target >= 0) {
                            for (z = isPos; z < token.length; z++) {
                                if (types[z] == Token.NOMEN) {
                                    cucumber.addTypeDicitonary(token[z], token[target]);
                                    break;
                                }
                            }
                        }
                    } else {
                        for (z = isPos; z < token.length; z++) {
                            if (types[z] == Token.NOMEN) {
                                target = z;
                                break;
                            }
                        }
                        if (target >= 0) {
                            for (z = 0; z < isPos; z++) {
                                if (types[z] == Token.NOMEN) {
                                    cucumber.addTypeDicitonary(token[z], token[target]);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            values.setValue(i, true);
        }
        return true;
    }

    private boolean analyseTokenForAttribute(String[] token) {
        if(token == null || token.length<1) {
            return false;
        }
        int andPos=0, isPos = 0;
        char[] types=  new char[token.length];
        types[0] = Token.NOMEN;
        boolean isAttribute = false;
        int z;
        for (z = 1; z < token.length; z++) {
            Character type = cucumber.getTokenType(token[z]);
            if (type != null) {
                types[z] = type;
                if (type == Token.DEFINITION) {
                    isPos = z;
                }
                if(type == Token.ATTRTYPE ) {
                    isAttribute = true;
                }
                continue;
            }
            if (token[z].equalsIgnoreCase("and")) {
                andPos = z;
                types[z] = Token.AND;
                types[z - 1] = Token.NOMEN;
                types[z + 1] = Token.NOMEN;
                continue;
            }
            types[z] = Token.NOMEN;
        }
        if(isAttribute && isPos<=0) {
            Attribute attr=null;
            String className=null;
            for(int i = token.length-1;i>=0;i--) {
                if(types[i]==Token.ATTRTYPE) {
                    String type = cucumber.getTypeDictionary(token[i]);
                    attr = new Attribute(token[i], DataType.create(type));
                }else if(types[i]==Token.NOMEN && attr != null && "has".equalsIgnoreCase(token[i])==false) {
                    className = token[i];
                    break;
                }
                if(andPos == i-1) {
                    //FIXME add AND POS
                }
            }
            if(attr != null && className != null) {
                // Save Attributes
                if(attributeSet == null) {
                    this.attributeSet = new ClazzSet();
                }
                Clazz clazz = attributeSet.getClazz(className);
                if(clazz == null) {
                    clazz = new Clazz(className);
                    attributeSet.add(clazz);
                }
                GraphUtil.setChildren(clazz, attr);
                return true;
            }
            
        }
        return false;
    }

    private boolean analyseSentense(String sentence, GraphModel model) {
        String[] token = sentence.split(" ");
        int z;
        /* Test for replace Link Names */
        if (assocs.size() > 0) {
            StringCondition condition = StringCondition.createEquals(Clazz.PROPERTY_ID, null);
            for (z = 0; z < token.length; z++) {
                int found = assocs.indexOf(token[z]);
                int n;
                if (found < 0 && token[z].endsWith("s")) {
                    for (n = 0; n < assocs.size(); n++) {
                        String key = assocs.getKeyByIndex(n);
                        if (token[z].startsWith(key)) {
                            found = n;
                            break;
                        }
                    }
                }
                if (found >= 0) {
                    boolean transform = false;
                    condition.withValue(token[z - 1]);
                    if(model == null || clazzSet.filter(condition).size()<1) {
                        transform = true;
                    }
                    ClazzSet elements = assocs.getValueByIndex(found);
                    if (z > 0) {
                        if (elements.contains((Object) token[z - 1])) {
                            transform = false;
                        }
                    }
                    if (transform) {
                        String[] newToken = new String[token.length + (elements.size() + elements.size() - 1) - 1];
                        for (n = 0; n < z; n++) {
                            newToken[n] = token[n];
                        }
                        int temp = z;
                        for (n = 0; n < elements.size(); n++) {
                            newToken[n + temp] = elements.get(n).getId();
                            if (n < elements.size() - 1) {
                                temp++;
                                newToken[n + temp] = "and";
                            }
                        }
                        n = n + temp;
                        temp = z + 1;
                        while (temp < token.length) {
                            newToken[n++] = token[temp++];
                        }
                        token = newToken;
                    }
                }
            }
        }

        char[] types = new char[token.length];
        for (z = 0; z < token.length; z++) {
            if (types[z] == 0) {
                types[z] = Token.UNKNOWN;
            }
            Character type = cucumber.getTokenType(token[z]);
            if (type != null) {
                types[z] = type;
                continue;
            }
            if (token[z].equalsIgnoreCase("and")) {
                types[z] = Token.AND;
                types[z - 1] = Token.NOMEN;
                types[z + 1] = Token.NOMEN;
            }
        }
        for (z = 0; z < token.length; z++) {
            if (types[z] != Token.UNKNOWN) {
                continue;
            }
            if (z < 1) {
                types[z] = Token.NOMEN;
                continue;
            }
            if (types[z - 1] == Token.ATTRNAME) {
                types[z] = Token.ATTRVALUE;
                continue;
            }
            if (types[z - 1] == Token.ATTR) {
                try {
                    Double.parseDouble(token[z]);
                    types[z] = Token.ATTRVALUE;
                } catch (NumberFormatException e) {
                    types[z] = Token.ATTRNAME;
                }
                continue;
            }

            if (types[z - 1] == Token.NOMEN) {
                types[z] = Token.VERB;
            } else {
                types[z] = Token.NOMEN;
            }
        }
        for (z = 0; z < token.length; z++) {
            if (types[z] == Token.NOMEN) {
                clazzSet.add(getClazz(token[z], model));
            } else if (types[z] == Token.ATTRNAME && (types[z - 2] == Token.NOMEN
                    || types[z - 1] == Token.ATTRNAME && types[z - 3] == Token.NOMEN)) {
                Clazz clazz;
                if (types[z - 1] == Token.ATTRNAME) {
                    clazz = getClazz(token[z - 3], model);
                } else {
                    clazz = getClazz(token[z - 2], model);
                }
                clazzSet.add(clazz);
                DataType type = DataType.STRING;
                String name = "value";
                try {
                    Double.parseDouble(token[z+1]);
                    type = DataType.DOUBLE;
                    try {
                        Integer.parseInt(token[z+1]);
                        type = DataType.INT;
                    } catch (Exception e) {
                    }
                } catch (NumberFormatException e) {
                }
                if (types[z - 1] == Token.ATTRNAME) {
                    name = token[z - 1];
                }
                clazz.createAttribute(name, type).withValue(token[z+1]);
            } else if (types[z] == Token.ATTR) {
                Clazz clazz = getClazz(token[z - 1], model);
                DataType type = DataType.STRING;
                if(z<token.length ) {
                    if(types[z + 1] == Token.ATTRNAME) {
                        continue;
                    }
                    if(types[z+1]==Token.ATTRVALUE) {
                        // Check DataType
                        try {
                            Double.parseDouble(token[z+1]);
                            type = DataType.DOUBLE;
                            try {
                                Integer.parseInt(token[z+1]);
                                type = DataType.INT;
                            } catch (Exception e) {
                            }
                        } catch (NumberFormatException e) {
                        }
                    }
                }
                clazz.createAttribute(token[z], type);
            } else if (types[z] == Token.VERB) {
                int source = Association.ONE;
                int target = Association.ONE;
                if (z > 1 && types[z - 2] == Token.AND) {
                    if (token[z].endsWith("s") && token[z].equals("has") == false) {
                        token[z] = token[z].substring(0, token[z].length() - 1);
                    }
                    source = Association.MANY;
                }
                if (z + 2 < types.length && types[z + 2] == Token.AND) {
                    target = Association.MANY;
                }
                int s = z - 1;
                int t = z + 1;
                if (s >= 0) {
                    do {
                        Clazz sourceClazz = getClazz(token[s], model);
                        clazzSet.add(sourceClazz);
                        do {
                            if(t>=token.length) {
                                break;
                            }
                            Clazz targetClazz = getClazz(token[t], model);
                            clazzSet.add(targetClazz);
                            sourceClazz.withUniDirectional(targetClazz, getLinkName(token[z]), target);
                            addToAssoc(source, sourceClazz, token[z]);
                            if (t + 1 < types.length && types[t + 1] == Token.AND) {
                                t += 2;
                            } else {
                                break;
                            }
                        } while (t <= types.length);
                        if (s > 0 && types[s - 1] == Token.AND) {
                            s -= 2;
                        } else {
                            break;
                        }

                    } while (s >= 0);
                }
            }
        }
        return true;
    }
    
    private boolean analyseTokens(SimpleKeyValueList<String, Boolean> values, GraphModel model) {
        for (int i = 0; i < values.size(); i++) {
            String string = values.getKeyByIndex(i);
            String[] sentences = string.split("\\.");
            for(int s=0;s<sentences.length;s++) {
                analyseSentense(sentences[s].trim(), model);
            }
            values.setValue(i, Boolean.TRUE);
        }
        return true;
    }

    private boolean addToAssoc(int source, Clazz sourceClazz, String assocName) {
        assocName = assocName.toLowerCase();
        if (source == Association.MANY && assocName.endsWith("s")) {
            assocName = assocName.substring(0, assocName.length() - 1);
        }
        ClazzSet sub = assocs.get(assocName);
        if (sub != null) {
            return sub.add(sourceClazz);
        }
        sub = new ClazzSet().with(sourceClazz);
        return assocs.add(assocName, sub);
    }

    private String getLinkName(String id) {
        if(cucumber == null) {
            return null;
        }
        return cucumber.getDictionary(id);
    }

    private Clazz getClazz(String id, GraphModel model) {
        if(cucumber == null || model == null) {
            return null;
        }
        id = cucumber.getDictionary(id);
        Clazz clazz = GraphUtil.createClazzById(model, id);
        
        String type = cucumber.getTypeDictionary(id);
        if (type != null) {
            clazz.with(type);
            // Search for Attribute in Definition
            cucumber.getTypeDictionary(id);
        }
        // Add Attributes from id
        if(attributeSet != null) {
            Clazz prototype = attributeSet.getClazz(clazz.getName());
            if(prototype  != null) {
                AttributeSet attributes = prototype.getAttributes();
                for(Attribute attr : attributes) {
                    GraphUtil.setChildren(clazz, new Attribute(attr.getName(), attr.getType()));
                }
            }
        }
        return clazz;
    }
    
    public GraphModel getModel() {
        return model;
    }
}