package com.scrivenvar.processors;
import static com.scrivenvar.Constants.PERSIST_R_STARTUP;
import static com.scrivenvar.Constants.STATUS_PARSE_ERROR;
import static com.scrivenvar.Messages.get;
import com.scrivenvar.Services;
import static com.scrivenvar.decorators.RVariableDecorator.PREFIX;
import static com.scrivenvar.decorators.RVariableDecorator.SUFFIX;
import static com.scrivenvar.processors.text.TextReplacementFactory.replace;
import com.scrivenvar.service.Options;
import com.scrivenvar.service.events.Notifier;
import java.io.IOException;
import static java.lang.Math.min;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Map;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public final class InlineRProcessor extends DefaultVariableProcessor {
private final Notifier notifier = Services.load( Notifier.class );
private final Options options = Services.load( Options.class );
private ScriptEngine engine;
public InlineRProcessor(
final Processor<String> processor,
final Map<String, String> map,
final Path path ) {
super( processor, map );
init( path.getParent() );
}
private void init( final Path workingDirectory ) {
try {
final Path wd = nullSafe( workingDirectory );
final String dir = wd.toString().replace( '\\', '/' );
final Map<String, String> definitions = getDefinitions();
definitions.put( "$application.r.working.directory$", dir );
final String initScript = getInitScript();
if( !initScript.isEmpty() ) {
final String rScript = replace( initScript, getDefinitions() );
eval( rScript );
}
} catch( final IOException | ScriptException e ) {
throw new RuntimeException( e );
}
}
private String getInitScript() throws IOException {
return getOptions().get( PERSIST_R_STARTUP, "" );
}
@Override
public String processLink( final String text ) {
final int length = text.length();
final int prefixLength = PREFIX.length();
final StringBuilder sb = new StringBuilder( length );
int prevIndex = 0;
int currIndex = text.indexOf( PREFIX );
while( currIndex >= 0 ) {
sb.append( text.substring( prevIndex, currIndex ) );
prevIndex = currIndex + prefixLength;
currIndex = text.indexOf( SUFFIX, min( currIndex + 1, length ) );
if( currIndex > 1 ) {
final String r = text.substring( prevIndex, currIndex );
try {
final Object result = eval( r );
sb.append( result );
} catch( final Exception e ) {
sb.append( PREFIX ).append( r ).append( SUFFIX );
getNotifier().notify( get( STATUS_PARSE_ERROR,
e.getMessage(), currIndex )
);
}
prevIndex = currIndex + 1;
}
else {
}
currIndex = text.indexOf( PREFIX, min( currIndex + 1, length ) );
}
return sb.append( text.substring( min( prevIndex, length ) ) ).toString();
}
private Object eval( final String r ) throws ScriptException {
return getScriptEngine().eval( r );
}
private synchronized ScriptEngine getScriptEngine() {
if( this.engine == null ) {
this.engine = (new ScriptEngineManager()).getEngineByName( "Renjin" );
}
return this.engine;
}
private Notifier getNotifier() {
return this.notifier;
}
private Options getOptions() {
return this.options;
}
private Path nullSafe( final Path path ) {
return path == null ? Paths.get( System.getProperty( "user.dir" ) ) : path;
}
}