if (value != null ? !value.equals(that.value) : that.value != null)
            return false;
        return true;
    }

package io.kubernetes.client.openapi.models;

import java.lang.Integer;
import io.kubernetes.client.fluent.BaseFluent;
import io.kubernetes.client.custom.Quantity;
import java.lang.Object;
import java.lang.String;
import java.lang.Boolean;

public class V2beta2MetricValueStatusFluentImpl<A extends io.kubernetes.client.openapi.models.V2beta2MetricValueStatusFluent<A>> extends io.kubernetes.client.fluent.BaseFluent<A> implements io.kubernetes.client.openapi.models.V2beta2MetricValueStatusFluent<A> {

    public V2beta2MetricValueStatusFluentImpl() {
    }

    public V2beta2MetricValueStatusFluentImpl(io.kubernetes.client.openapi.models.V2beta2MetricValueStatus instance) {
        this.withAverageUtilization(instance.getAverageUtilization());
        this.withAverageValue(instance.getAverageValue());
        this.withValue(instance.getValue());
    }

    private java.lang.Integer averageUtilization;

    private io.kubernetes.client.custom.Quantity averageValue;

    private io.kubernetes.client.custom.Quantity value;

    public java.lang.Integer getAverageUtilization() {
        return this.averageUtilization;
    }

    public A withAverageUtilization(java.lang.Integer averageUtilization) {
        this.averageUtilization = averageUtilization;
        return (A) this;
    }

    public java.lang.Boolean hasAverageUtilization() {
        return this.averageUtilization != null;
    }

    public io.kubernetes.client.custom.Quantity getAverageValue() {
        return this.averageValue;
    }

    public A withAverageValue(io.kubernetes.client.custom.Quantity averageValue) {
        this.averageValue = averageValue;
        return (A) this;
    }

    public java.lang.Boolean hasAverageValue() {
        return this.averageValue != null;
    }

    public A withNewAverageValue(java.lang.String value) {
        return (A) withAverageValue(new Quantity(value));
    }

    public io.kubernetes.client.custom.Quantity getValue() {
        return this.value;
    }

    public A withValue(io.kubernetes.client.custom.Quantity value) {
        this.value = value;
        return (A) this;
    }

    public java.lang.Boolean hasValue() {
        return this.value != null;
    }

    public A withNewValue(java.lang.String value) {
        return (A) withValue(new Quantity(value));
    }

    public boolean equals(java.lang.Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        V2beta2MetricValueStatusFluentImpl that = (V2beta2MetricValueStatusFluentImpl) o;
        if (averageUtilization != null ? !averageUtilization.equals(that.averageUtilization) : that.averageUtilization != null)
            return false;
        if (averageValue != null ? !averageValue.equals(that.averageValue) : that.averageValue != null)
            return false;

    public int hashCode() {
        return java.util.Objects.hash(averageUtilization, averageValue, value, super.hashCode());
    }
}


package io.kubernetes.client.openapi.models;

import java.lang.Integer;
import io.kubernetes.client.fluent.BaseFluent;
import io.kubernetes.client.custom.Quantity;
import java.lang.Object;
import java.lang.String;
import java.lang.Boolean;

public class V2beta2MetricValueStatusFluentImpl<A extends io.kubernetes.client.openapi.models.V2beta2MetricValueStatusFluent<A>> extends io.kubernetes.client.fluent.BaseFluent<A> implements io.kubernetes.client.openapi.models.V2beta2MetricValueStatusFluent<A> {

    public V2beta2MetricValueStatusFluentImpl() {
    }

    public V2beta2MetricValueStatusFluentImpl(io.kubernetes.client.openapi.models.V2beta2MetricValueStatus instance) {
        this.withAverageUtilization(instance.getAverageUtilization());
        this.withAverageValue(instance.getAverageValue());
        this.withValue(instance.getValue());
    }

    private java.lang.Integer averageUtilization;

    private io.kubernetes.client.custom.Quantity averageValue;

    private io.kubernetes.client.custom.Quantity value;

    public java.lang.Integer getAverageUtilization() {
        return this.averageUtilization;
    }

    public A withAverageUtilization(java.lang.Integer averageUtilization) {
        this.averageUtilization = averageUtilization;
        return (A) this;
    }

    public java.lang.Boolean hasAverageUtilization() {
        return this.averageUtilization != null;
    }

    public io.kubernetes.client.custom.Quantity getAverageValue() {
        return this.averageValue;
    }

    public A withAverageValue(io.kubernetes.client.custom.Quantity averageValue) {
        this.averageValue = averageValue;
        return (A) this;
    }

    public java.lang.Boolean hasAverageValue() {
        return this.averageValue != null;
    }

    public A withNewAverageValue(java.lang.String value) {
        return (A) withAverageValue(new Quantity(value));
    }

    public io.kubernetes.client.custom.Quantity getValue() {
        return this.val

    }

    public A withValue(io.kubernetes.client.custom.Quantity value) {
        this.value = value;
        return (A) this;
    }

    public java.lang.Boolean hasValue() {
        return this.value != null;
    }

    public A withNewValue(java.lang.String value) {
        return (A) withValue(new Quantity(value));
    }

    public boolean equals(java.lang.Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        V2beta2MetricValueStatusFluentImpl that = (V2beta2MetricValueStatusFluentImpl) o;
        if (averageUtilization != null ? !averageUtilization.equals(that.averageUtilization) : that.averageUtilization != null)
            return false;
        if (averageValue != null ? !averageValue.equals(that.averageValue) : that.averageValue != null)
            return false;
        if (value != null ? !value.equals(that.value) : that.value != null)
            return false;
        return true;
    }

    public int hashCode() {
        return java.util.Objects.hash(averageUtilization, averageValue, value, super.hashCode());
    }
}


if (value != null ? !value.equals(that.value) : that.value != null)
            return false;

        return true;
    }

    public int hashCode() {
        return java.util.Objects.hash(averageUtilization, averageValue, value, super.hashCode());
    }
}


@Override
    public int[] getTargets(GameFacade gf)

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.southwestern.tasks.mspacman.sensors.directional.distance.farthest;

import edu.southwestern.tasks.mspacman.facades.GameFacade;

/**
 * @author Jacob Schrum
 */
public class VariableDirectionFarthestIncomingEdibleGhostDistanceBlock extends VariableDirectionFarthestDistanceBlock {

    public VariableDirectionFarthestIncomingEdibleGhostDistanceBlock(int dir) {
        super(dir);
    }

    @Override
    public String getType() {
        return "Incoming Edible Ghost";
    }

{
        return gf.getIncomingEdibleGhostLocations(dir);
    }
}


{
        return gf.getIncomingEdibleGhostLocations(dir);
    }

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.southwestern.tasks.mspacman.sensors.directional.distance.farthest;

import edu.southwestern.tasks.mspacman.facades.GameFacade;

/**
 * @author Jacob Schrum
 */
public class VariableDirectionFarthestIncomingEdibleGhostDistanceBlock extends VariableDirectionFarthestDistanceBlock {

    public VariableDirectionFarthestIncomingEdibleGhostDistanceBlock(int dir) {
        super(dir);
    }

    @Override
    public String getType() {
        return "Incoming Edible Ghost";
    }

    @Override
    public int[] getTargets(GameFacade gf)


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.southwestern.tasks.mspacman.sensors.directional.distance.farthest;

import edu.southwestern.tasks.mspacman.facades.GameFacade;

/**
 * @author Jacob Schrum
 */
public class VariableDirectionFarthestIncomingEdibleGhostDistanceBlock extends VariableDirectionFarthestDistanceBlock {

    public VariableDirectionFarthestIncomingEdibleGhostDistanceBlock(int dir) {
        super(dir);
    }

    @Override
    public String getType() {
        ret

    }

    @Override
    public int[] getTargets(GameFacade gf) {
        return gf.getIncomingEdibleGhostLocations(dir);
    }
}


package weibo4j.examples.comment;

import weibo4j.Comments;
import weibo4j.examples.oauth2.Log;
import weibo4j.model.Comment;
import weibo4j.model.CommentWapper;
import weibo4j.model.WeiboException;

public class GetCommentByMe {

{
        String access_token = args[0];
        Comments cm = new Comments();
        cm.client.setToken(access_token);
        try {
            CommentWapper comment = cm.getCommentByMe();
            for (Comment c : comment.getComments()) {
                Log.logInfo(c.toString());
            }
            System.out.println(comment.getNextCursor());
            System.out.println(comment.getPreviousCursor());
            System.out.println(comment.getTotalNumber());
            System.out.println(comment.getHasvisible());
        } catch (WeiboException e) {
            e.printStackTrace();
        }
    }
}


package weibo4j.examples.comment;

import weibo4j.Comments;
import weibo4j.examples.oauth2.Log;
import weibo4j.model.Comment;
import weibo4j.model.CommentWapper;
import weibo4j.model.WeiboException;

public class GetCommentByMe {

    public static void main(String[] args) {

        Comments cm = new Comments();
        cm.client.setToken(access_token);
        try {
            CommentWapper comment = cm.getCommentByMe();
            for (Comment c : comment.getComments()) {
                Log.logInfo(c.toString());
            }
            System.out.println(comment.getNextCursor());
            System.out.println(comment.getPreviousCursor());
            System.out.println(comment.getTotalNumber());
            System.out.println(comment.getHasvisible());
        } catch (WeiboException e) {
            e.printStackTrace();
        }
    }
}


Comments cm = new Comments();
        cm.client.setToken(access_token);

package weibo4j.examples.comment;

import weibo4j.Comments;
import weibo4j.examples.oauth2.Log;
import weibo4j.model.Comment;
import weibo4j.model.CommentWapper;
import weibo4j.model.WeiboException;

public class GetCommentByMe {

    public static void main(String[] args) {
        String access_token = args[0];

        try {
            CommentWapper comment = cm.getCommentByMe();
            for (Comment c : comment.getComments()) {
                Log.logInfo(c.toString());
            }
            System.out.println(comment.getNextCursor());
            System.out.println(comment.getPreviousCursor());
            System.out.println(comment.getTotalNumber());
            System.out.println(comment.getHasvisible());
        } catch (WeiboException e) {
            e.printStackTrace();
        }
    }
}


try {
            CommentWapper comment = cm.getCommentByMe();
            for (Comment c : comment.getComments()) {
                Log.logInfo(c.toString());
            }
            System.out.println(comment.getNextCursor());
            System.out.println(comment.getPreviousCursor());
            System.out.println(comment.getTotalNumber());
            System.out.println(comment.getHasvisible());
        } catch (WeiboException e) {
            e.printStackTrace();
        }
    }

package weibo4j.examples.comment;

import weibo4j.Comments;
import weibo4j.examples.oauth2.Log;
import weibo4j.model.Comment;
import weibo4j.model.CommentWapper;
import weibo4j.model.WeiboException;

public class GetCommentByMe {

    public static void main(String[] args) {
        String access_token = args[0];
        Comments cm = new Comments();
        cm.client.setToken(access_token);


package weibo4j.examples.comment;

import weibo4j.Comments;
import weibo4j.examples.oauth2.Log;
import weibo4j.model.Comment;
import weibo4j.model.CommentWapper;
import weibo4j.model.WeiboException;

public class GetCommentByMe {

    public static void main(String[] args) {
        String access_token = args[0];
        Comments cm =

        cm.client.setToken(access_token);
        try {
            CommentWapper comment = cm.getCommentByMe();
            for (Comment c : comment.getComments()) {
                Log.logInfo(c.toString());
            }
            System.out.println(comment.getNextCursor());
            System.out.println(comment.getPreviousCursor());
            System.out.println(comment.getTotalNumber());
            System.out.println(comment.getHasvisible());
        } catch (WeiboException e) {
            e.printStackTrace();
        }
    }
}


try {
            CommentWapper comment = cm.getCommentByMe();
            for (Comment c : comment.getComments()) {
                Log.logInfo(c.toString());
            }
            System.out.println(comment.getNextCursor());
            System.out.println(comment.getPreviousCursor());
            System.out.println(comment.getTotalNumber());
            System.out.println(comment.getHasvisible());
        } catch (WeiboException e) {
            e.printStackTrace();
        }


package org.eclipse.jnosql.communication.column;

import jakarta.nosql.TypeSupplier;
import jakarta.nosql.Value;
import jakarta.nosql.column.Column;
import org.eclipse.jnosql.communication.Entry;
import java.util.Objects;

/**
 * The default implementation of {@link Column}
 */
final class DefaultColumn implements Column, Entry {

    private final String name;

    private final Value value;

    DefaultColumn(String name, Value value) {
        this.name = name;
        this.value = value;
    }

{
        return name;
    }

    public Value getValue() {
        return value;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return value.get(clazz);
    }

    @Override
    public <T> T get(TypeSupplier<T> typeSupplier) {
        return value.get(typeSupplier);
    }

    @Override
    public Object get() {
        return value.get();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Column)) {
            return false;
        }
        Column that = (Column) o;
        return Objects.equals(name, that.getName()) && Objects.equals(value, that.getValue());
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }

    @Override
    public String toString() {
        return "DefaultColumn{" + "name='" + name + '\'' + ", value=" + value + '}';
    }
}


{
        return "DefaultColumn{" + "name='" + name + '\'' + ", value=" + value + '}';
    }

package org.eclipse.jnosql.communication.column;

import jakarta.nosql.TypeSupplier;
import jakarta.nosql.Value;
import jakarta.nosql.column.Column;
import org.eclipse.jnosql.communication.Entry;
import java.util.Objects;

/**
 * The default implementation of {@link Column}
 */
final class DefaultColumn implements Column, Entry {

    private final String name;

    private final Value value;

    DefaultColumn(String name, Value value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public Value getValue() {
        return value;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return value.get(clazz);
    }

    @Override
    public <T> T get(TypeSupplier<T> typeSupplier) {
        return value.get(typeSupplier);
    }

    @Override
    public Object get() {
        return value.get();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Column)) {
            return false;
        }
        Column that = (Column) o;
        return Objects.equals(name, that.getName()) && Objects.equals(value, that.getValue());
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }

    @Override
    public String toString()


        if (this == o) {
            return true;
        }

package org.eclipse.jnosql.communication.column;

import jakarta.nosql.TypeSupplier;
import jakarta.nosql.Value;
import jakarta.nosql.column.Column;
import org.eclipse.jnosql.communication.Entry;
import java.util.Objects;

/**
 * The default implementation of {@link Column}
 */
final class DefaultColumn implements Column, Entry {

    private final String name;

    private final Value value;

    DefaultColumn(String name, Value value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public Value getValue() {
        return value;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return value.get(clazz);
    }

    @Override
    public <T> T get(TypeSupplier<T> typeSupplier) {
        return value.get(typeSupplier);
    }

    @Override
    public Object get() {
        return value.get();
    }

    @Override
    public boolean equals(Object o) {

        if (!(o instanceof Column)) {
            return false;
        }
        Column that = (Column) o;
        return Objects.equals(name, that.getName()) && Objects.equals(value, that.getValue());
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }

    @Override
    public String toString() {
        return "DefaultColumn{" + "name='" + name + '\'' + ", value=" + value + '}';
    }
}


if (!(o instanceof Column)) {
            return false;
        }
        Column that = (Column) o;

package org.eclipse.jnosql.communication.column;

import jakarta.nosql.TypeSupplier;
import jakarta.nosql.Value;
import jakarta.nosql.column.Column;
import org.eclipse.jnosql.communication.Entry;
import java.util.Objects;

/**
 * The default implementation of {@link Column}
 */
final class DefaultColumn implements Column, Entry {

    private final String name;

    private final Value value;

    DefaultColumn(String name, Value value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public Value getValue() {
        return value;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return value.get(clazz);
    }

    @Override
    public <T> T get(TypeSupplier<T> typeSupplier) {
        return value.get(typeSupplier);
    }

    @Override
    public Object get() {
        return value.get();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }

        return Objects.equals(name, that.getName()) && Objects.equals(value, that.getValue());
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }

    @Override
    public String toString() {
        return "DefaultColumn{" + "name='" + name + '\'' + ", value=" + value + '}';
    }
}


return Objects.equals(name, that.getName()) && Objects.equals(value, that.getValue());
    }

package org.eclipse.jnosql.communication.column;

import jakarta.nosql.TypeSupplier;
import jakarta.nosql.Value;
import jakarta.nosql.column.Column;
import org.eclipse.jnosql.communication.Entry;
import java.util.Objects;

/**
 * The default implementation of {@link Column}
 */
final class DefaultColumn implements Column, Entry {

    private final String name;

    private final Value value;

    DefaultColumn(String name, Value value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public Value getValue() {
        return value;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return value.get(clazz);
    }

    @Override
    public <T> T get(TypeSupplier<T> typeSupplier) {
        return value.get(typeSupplier);
    }

    @Override
    public Object get() {
        return value.get();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Column)) {
            return false;
        }
        Column that = (Column) o;

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }

    @Override
    public String toString() {
        return "DefaultColumn{" + "name='" + name + '\'' + ", value=" + value + '}';
    }
}


package org.eclipse.jnosql.communication.column;

import jakarta.nosql.TypeSupplier;
import jakarta.nosql.Value;
import jakarta.nosql.column.Column;
import org.eclipse.jnosql.communication.Entry;
import java.util.Objects;

/**
 * The default implementation of {@link Column}
 */
final class DefaultColumn implements Column, Entry {

    private final String name;

    private final Value value;

    DefaultColumn(String name, Value value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return n

    }

    public Value getValue() {
        return value;
    }

    @Override
    public <T> T get(Class<T> clazz) {
        return value.get(clazz);
    }

    @Override
    public <T> T get(TypeSupplier<T> typeSupplier) {
        return value.get(typeSupplier);
    }

    @Override
    public Object get() {
        return value.get();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof Column)) {
            return false;
        }
        Column that = (Column) o;
        return Objects.equals(name, that.getName()) && Objects.equals(value, that.getValue());
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, value);
    }

    @Override
    public String toString() {
        return "DefaultColumn{" + "name='" + name + '\'' + ", value=" + value + '}';
    }
}


if (this == o) {
            return true;
        }


package cn.timebusker.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("calculate")
public class CalculateProperties {

    private int scale;

    public int getScale() {
        return scale;
    }


package cn.timebusker.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("calculate")
public class CalculateProperties {

    private int scale;

    public int getScale()

    public void setScale(int scale) {
        this.scale = scale;
    }
}


package cn.timebusker.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("calculate")
public class CalculateProperties {

    private int scale;

    public int getScale() {
        return scale;
    }

    public void setScale(int scale) {
        this.scale =


public void convert(String inputFilename, OutputStream outStream)

package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

{
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();
            if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }
            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {
            final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
            final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
            // PipedRDFStream and PipedRDFIterator need to be on different threads
            final Runnable r = new Runnable() {

                @Override
                public void run() {
                    RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                }
            };
            final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }
            pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }
    }
    // end of class FirstPass
}


package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

    public void convert(String inputFilename, OutputStream outStream) {
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();
            if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }
            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {
            final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
            final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
            // PipedRDFStream and PipedRDFIterator need to be on different threads
            final Runnable r = new Runnable() {

                @Override
                public void run()

            };
            final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }
            pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }
    }
    // end of class FirstPass
}


package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

    public void convert(String inputFilename, OutputStream outStream) {
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();
            if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }
            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {

            final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }
            pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }
    }
    // end of class FirstPass
}


final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }

package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

    public void convert(String inputFilename, OutputStream outStream) {
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();
            if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }
            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {
            final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
            final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
            // PipedRDFStream and PipedRDFIterator need to be on different threads
            final Runnable r = new Runnable() {

                @Override
                public void run() {
                    RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                }
            };

            pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }
    }
    // end of class FirstPass
}


pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }

package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

    public void convert(String inputFilename, OutputStream outStream) {
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();
            if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }
            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {
            final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
            final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
            // PipedRDFStream and PipedRDFIterator need to be on different threads
            final Runnable r = new Runnable() {

                @Override
                public void run() {
                    RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                }
            };
            final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }


package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

    public void convert(String inputFilename, OutputStream outStream) {
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();
            if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }
            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {
            final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
            final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
            // PipedRDFStream and PipedRDFIterator need to be on different threads
            final Runnable r = new Runnable() {

                @Override
                public void run() {
                    RDFParser.create().labelToNode(L

                }
            };
            final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }
            pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }
    }
    // end of class FirstPass
}


if (s instanceof Node_Triple) {
                final Triple subjTriple = ((Node_Triple) s).get();
                s = printTriples(subjTriple, writer, nFmt, true);
                first_lap = false;
            }

package se.liu.ida.rdfstar.tools.conversion;

import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.lang3.StringUtils;
import org.apache.jena.atlas.io.IndentedWriter;
import org.apache.jena.graph.Node;
import org.apache.jena.graph.NodeFactory;
import org.apache.jena.graph.Node_Triple;
import org.apache.jena.graph.Triple;
import org.apache.jena.riot.RDFParser;
import org.apache.jena.riot.lang.LabelToNode;
import org.apache.jena.riot.lang.PipedRDFIterator;
import org.apache.jena.riot.lang.PipedTriplesStream;
import org.apache.jena.riot.out.NodeFormatter;
import org.apache.jena.riot.out.NodeFormatterTTL;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.RiotLib;
import org.apache.jena.vocabulary.RDF;
import se.liu.ida.rdfstar.tools.parser.lang.LangTurtleStar;

/**
 * Conversion of Turtle* files into Turtle such that the resulting
 * RDF data is a reification-based representation of the RDF* data.
 *
 * @author Jesper Eriksson
 * @author Amir Hakim
 * @author Ebba Lindström
 * @author Olaf Hartig
 * @author Robin Keskisärkkä
 */
public class RDFStar2RDF {

    static protected final int BUFFER_SIZE = 16000;

    static protected final boolean EXPLICITILY_ADD_REIFIED_STATEMENTS = true;

    public void convert(String inputFilename, OutputStream outStream) {
        convert(inputFilename, outStream, null);
    }

    public void convert(String inputFilename, OutputStream outStream, String baseIRI) {
        final FirstPass fp = new FirstPass(inputFilename, outStream);
        fp.setBaseIRI(baseIRI);
        fp.execute();
        final FileConverter fc = new FileConverter(inputFilename, outStream, fp.getBaseIRI(), fp.getPrefixMap());
        fc.execute();
    }

    protected class FileConverter {

        final protected String inputFilename;

        final protected OutputStream outStream;

        final protected String baseIRI;

        final protected PrefixMap pmap;

        // populated during the conversion to record for every reified
        // triple, the blank node that has been created as statement ID
        protected final Map<Triple, Node> bNodes = new HashMap<>();

        protected boolean first_lap = true;

        // used to create turtle blocks
        protected Node lastSubject = NodeFactory.createBlankNode();

        // used to create turtle blocks
        protected Node lastPredicate = NodeFactory.createBlankNode();

        public FileConverter(String inputFilename, OutputStream outStream, String baseIRI, PrefixMap pm) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
            this.baseIRI = baseIRI;
            this.pmap = pm;
        }

        public void execute() {
            // print all prefixes and the base IRI to the output file
            try (IndentedWriter writer = new IndentedWriter(outStream)) {
                RiotLib.writePrefixes(writer, pmap);
                RiotLib.writeBase(writer, baseIRI);
                // second pass over the file to perform the conversion in a streaming manner
                final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
                final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
                // PipedRDFStream and PipedRDFIterator need to be on different threads
                final Runnable r = new Runnable() {

                    @Override
                    public void run() {
                        RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                    }
                };
                final ExecutorService executor = Executors.newSingleThreadExecutor();
                executor.submit(r);
                final NodeFormatter nFmt = new NodeFormatterTTL(baseIRI, pmap);
                while (it.hasNext()) {
                    printTriples(it.next(), writer, nFmt, false);
                }
                it.close();
                executor.shutdown();
                writer.write(" .");
                writer.flush();
            }
        }

        /**
         * Recursively flattens nested triples and prints in pretty format. One triple at the time.
         */
        protected Node printTriples(Triple triple, IndentedWriter writer, NodeFormatter nFmt, boolean hasParent) {
            Node s = triple.getSubject();
            Node p = triple.getPredicate();
            Node o = triple.getObject();

            if (o instanceof Node_Triple) {
                final Triple objTriple = ((Node_Triple) o).get();
                o = printTriples(objTriple, writer, nFmt, true);
                first_lap = false;
            }
            // if we have reached here, we are at the deepest level of recursion, or if its not nested at all
            if (hasParent) {
                final Triple hashKey = Triple.create(s, p, o);
                Node bnode;
                if ((bnode = bNodes.get(hashKey)) != null) {
                    return bnode;
                } else {
                    bnode = NodeFactory.createBlankNode();
                    bNodes.put(hashKey, bnode);
                    if (!first_lap)
                        writer.write(" .\n");
                    if (EXPLICITILY_ADD_REIFIED_STATEMENTS) {
                        nFmt.format(writer, s);
                        writer.write(" ");
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                        writer.write(" .\n");
                    }
                    nFmt.format(writer, bnode);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.type);
                    writer.write(" ");
                    nFmt.format(writer, RDF.Nodes.Statement);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.subject);
                    writer.write(" ");
                    nFmt.format(writer, s);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.predicate);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ;\n" + StringUtils.leftPad("", bnode.toString().length() + 4));
                    nFmt.format(writer, RDF.Nodes.object);
                    writer.write(" ");
                    nFmt.format(writer, o);
                    lastSubject = bnode;
                    lastPredicate = NodeFactory.createBlankNode();
                    return bnode;
                }
            } else // Enter here if not nested or top level of recursion
            {
                if (lastSubject.matches(s)) {
                    int pad = 0;
                    if (lastSubject.isBlank())
                        pad = 3;
                    if (lastPredicate.matches(p)) {
                        writer.write(" ,\n" + StringUtils.leftPad("", s.toString().length() + p.toString().length() + 2 + pad));
                        nFmt.format(writer, o);
                    } else {
                        writer.write(" ;\n" + StringUtils.leftPad("", s.toString().length() + 1 + pad));
                        nFmt.format(writer, p);
                        writer.write(" ");
                        nFmt.format(writer, o);
                    }
                } else {
                    if (lastSubject.matches(o) || !first_lap)
                        writer.write(" .\n");
                    else
                        first_lap = false;
                    nFmt.format(writer, s);
                    writer.write(" ");
                    nFmt.format(writer, p);
                    writer.write(" ");
                    nFmt.format(writer, o);
                }
            }
            writer.flush();
            lastSubject = s;
            lastPredicate = p;
            first_lap = false;
            // return to the execute method
            return null;
        }
    }

    // end of class FileConverter
    /**
     * Performs a first pass over the input file to collect all prefixes.
     */
    protected class FirstPass {

        final protected String inputFilename;

        final protected OutputStream outStream;

        protected PrefixMap pmap;

        protected String baseIRI;

        public FirstPass(String inputFilename, OutputStream outStream) {
            this.inputFilename = inputFilename;
            this.outStream = outStream;
        }

        public PrefixMap getPrefixMap() {
            return pmap;
        }

        public String getBaseIRI() {
            return baseIRI;
        }

        public void setBaseIRI(String baseIRI) {
            this.baseIRI = baseIRI;
        }

        public void execute() {
            final PipedRDFIterator<Triple> it = new PipedRDFIterator<>(BUFFER_SIZE);
            final PipedTriplesStream triplesStream = new PipedTriplesStream(it);
            // PipedRDFStream and PipedRDFIterator need to be on different threads
            final Runnable r = new Runnable() {

                @Override
                public void run() {
                    RDFParser.create().labelToNode(LabelToNode.createUseLabelEncoded()).source(inputFilename).lang(LangTurtleStar.TURTLESTAR).base(baseIRI).build().parse(triplesStream);
                }
            };
            final ExecutorService executor = Executors.newSingleThreadExecutor();
            executor.submit(r);
            // consume the iterator
            while (it.hasNext()) {
                it.next();
            }
            pmap = it.getPrefixes();
            if (baseIRI == null) {
                baseIRI = it.getBaseIri();
            }
            it.close();
            executor.shutdown();
        }
    }
    // end of class FirstPass
}