/**
* Copyright 2015 Santhosh Kumar Tekuri
*
* The JLibs authors license this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package jlibs.nblr.rules;
import jlibs.core.lang.StringUtil;
import jlibs.core.util.CollectionUtil;
import jlibs.nblr.matchers.Any;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
/**
* @author Santhosh Kumar T
*/
public class Rule{
public int id;
public String name;
public Node node;
public ArrayList<Node> nodes(){
ArrayList<Node> nodes = new ArrayList<Node>();
ArrayList<Edge> edges = new ArrayList<Edge>();
computeIDS(nodes, edges, node);
return nodes;
}
public Node nodeWithName(String name){
if(name==null)
return node;
for(Node node: nodes()){
if(name.equals(node.name))
return node;
}
return null;
}
public ArrayList<Edge> edges(){
ArrayList<Node> nodes = new ArrayList<Node>();
ArrayList<Edge> edges = new ArrayList<Edge>();
computeIDS(nodes, edges, node);
return edges;
}
public void computeIDS(){
ArrayList<Node> nodes = new ArrayList<Node>();
ArrayList<Edge> edges = new ArrayList<Edge>();
computeIDS(nodes, edges, node);
}
public void computeIDS(List<Node> visited, List<Edge> edges, Node node){
if(!visited.contains(node)){
node.id = visited.size();
visited.add(node);
for(Edge edge: node.outgoing){
edges.add(edge);
computeIDS(visited, edges, edge.target);
}
}
}
public Set<Node> states(){
Set<Node> states = new LinkedHashSet<Node>();
for(Node node: nodes()){
if(node==this.node || node.name!=null)
states.add(node);
else{
for(Edge edge: node.incoming()){
if(edge.matcher!=null || edge.ruleTarget!=null){
states.add(node);
break;
}
}
}
}
return states;
}
public Rule copy(){
ArrayList<Node> nodes = new ArrayList<Node>();
ArrayList<Edge> edges = new ArrayList<Edge>();
computeIDS(nodes, edges, node);
Rule newRule = new Rule();
newRule.id = id;
newRule.name = name;
for(int i=0; i<nodes.size(); i++){
Node newNode = new Node();
newNode.id = i;
newNode.name = nodes.get(i).name;
newNode.action = nodes.get(i).action;
nodes.set(i, newNode);
}
newRule.node = nodes.get(0);
for(Edge edge: edges){
Edge newEdge = nodes.get(edge.source.id).addEdgeTo(nodes.get(edge.target.id));
newEdge.matcher = edge.matcher;
newEdge.fallback = edge.fallback;
if(edge.ruleTarget!=null){
RuleTarget ruleTarget = edge.ruleTarget;
RuleTarget newRuleTarget = newEdge.ruleTarget = new RuleTarget();
newRuleTarget.rule = ruleTarget.rule==this ? newRule : ruleTarget.rule;
newRuleTarget.name = ruleTarget.name;
}
}
return newRule;
}
/*-------------------------------------------------[ String Related ]---------------------------------------------------*/
public void insertStringBefore(Node node, String str){
boolean startingNode = this.node==node;
int cp[] = StringUtil.toCodePoints(str);
for(int i=cp.length-1; i>=0; i--){
Node newNode = new Node();
for(Edge edge: node.incoming()){
if(!edge.loop())
edge.setTarget(newNode);
}
newNode.addEdgeTo(node).matcher = new Any(cp[i]);
node = newNode;
}
if(startingNode)
this.node = node;
}
public void insertStringAfter(Node node, String str){
for(int cp: StringUtil.toCodePoints(str)){
Node newNode = new Node();
for(Edge edge: node.outgoing()){
if(!edge.loop())
edge.setSource(newNode);
}
newNode.addEdgeFrom(node).matcher = new Any(cp);
node = newNode;
}
}
public void addStringBranch(Node node, String str){
for(int cp: StringUtil.toCodePoints(str)){
Node newNode = new Node();
node.addEdgeTo(newNode).matcher = new Any(cp);
node = newNode;
}
}
public int[] matchString(){
ArrayList<Integer> ints = new ArrayList<Integer>();
Node node = this.node;
while(true){
if(node.action!=null)
return null;
switch(node.outgoing.size()){
case 0:
return CollectionUtil.toIntArray(ints);
case 1:
Edge edge = node.outgoing.get(0);
if(edge.loop() || !(edge.matcher instanceof Any))
return null;
Any any = (Any)edge.matcher;
if(any.chars==null || any.chars.length!=1)
return null;
ints.add(any.chars[0]);
node = edge.target;
continue;
default:
return null;
}
}
}
@Override
public String toString(){
int matchString[] = matchString();
if(matchString!=null)
return '"'+StringUtil.toLiteral(new String(matchString, 0, matchString.length), false)+'"';
return name;
}
}