package com.scrivenvar.processors.markdown;
import com.scrivenvar.Services;
import com.scrivenvar.preferences.UserPreferences;
import com.scrivenvar.service.Options;
import com.scrivenvar.service.events.Notifier;
import com.scrivenvar.util.ProtocolResolver;
import com.vladsch.flexmark.ast.Image;
import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.html.IndependentLinkResolverFactory;
import com.vladsch.flexmark.html.LinkResolver;
import com.vladsch.flexmark.html.renderer.LinkResolverBasicContext;
import com.vladsch.flexmark.html.renderer.LinkStatus;
import com.vladsch.flexmark.html.renderer.ResolvedLink;
import com.vladsch.flexmark.util.ast.Node;
import com.vladsch.flexmark.util.data.MutableDataHolder;
import org.jetbrains.annotations.NotNull;
import org.renjin.repackaged.guava.base.Splitter;
import java.io.File;
import java.io.FileNotFoundException;
import java.nio.file.Path;
import static java.lang.String.format;
public class ImageLinkExtension implements HtmlRenderer.HtmlRendererExtension {
private final static Options sOptions = Services.load( Options.class );
private final static Notifier sNotifier = Services.load( Notifier.class );
public static ImageLinkExtension create( @NotNull final Path path ) {
return new ImageLinkExtension( path );
}
private class Factory extends IndependentLinkResolverFactory {
@Override
public @NotNull LinkResolver apply(
@NotNull final LinkResolverBasicContext context ) {
return new ImageLinkResolver();
}
}
private class ImageLinkResolver implements LinkResolver {
private final UserPreferences mUserPref = getUserPreferences();
private final File mImagesUserPrefix = mUserPref.getImagesDirectory();
private final String mImageExtensions = mUserPref.getImagesOrder();
public ImageLinkResolver() {
}
@NotNull
@Override
public ResolvedLink resolveLink(
@NotNull final Node node,
@NotNull final LinkResolverBasicContext context,
@NotNull final ResolvedLink link ) {
return node instanceof Image ? resolve( link ) : link;
}
private ResolvedLink resolve( final ResolvedLink link ) {
String url = link.getUrl();
final String protocol = ProtocolResolver.getProtocol( url );
try {
if( ("file".equals( protocol ) && Path.of( url ).toFile().exists()) ||
protocol.startsWith( "http" ) ) {
return valid( link, url );
}
} catch( final Exception ignored ) {
}
try {
final Path imagePrefix = getImagePrefix().toPath();
Path editPath = getEditPath();
if( editPath == null ) {
editPath = imagePrefix;
}
else {
editPath = Path.of( editPath.toString(), imagePrefix.toString() );
}
final Path imagePathPrefix = Path.of( editPath.toString(), url );
final String suffixes = getImageExtensions();
boolean missing = true;
for( final String ext : Splitter.on( ' ' ).split( suffixes ) ) {
final String imagePath = format( "%s.%s", imagePathPrefix, ext );
final File file = new File( imagePath );
if( file.exists() ) {
url = file.toString();
missing = false;
break;
}
}
if( missing ) {
throw new FileNotFoundException( imagePathPrefix + ".*" );
}
if( "file".equals( protocol ) ) {
url = "file://" + url;
}
getNotifier().clear();
return valid( link, url );
} catch( final Exception e ) {
getNotifier().notify( "File not found: " + e.getLocalizedMessage() );
}
return link;
}
private ResolvedLink valid( final ResolvedLink link, final String url ) {
return link.withStatus( LinkStatus.VALID ).withUrl( url );
}
private File getImagePrefix() {
return mImagesUserPrefix;
}
private String getImageExtensions() {
return mImageExtensions;
}
private Path getEditPath() {
return mPath.getParent();
}
}
private final Path mPath;
private ImageLinkExtension( @NotNull final Path path ) {
mPath = path;
}
@Override
public void rendererOptions( @NotNull final MutableDataHolder options ) {
}
@Override
public void extend(
final HtmlRenderer.Builder rendererBuilder,
@NotNull final String rendererType ) {
rendererBuilder.linkResolverFactory( new Factory() );
}
private UserPreferences getUserPreferences() {
return getOptions().getUserPreferences();
}
private Options getOptions() {
return sOptions;
}
private Notifier getNotifier() {
return sNotifier;
}
}