package be.nikiroo.fanfix.output; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import be.nikiroo.fanfix.Instance; import be.nikiroo.fanfix.bundles.StringId; import be.nikiroo.fanfix.data.Chapter; import be.nikiroo.fanfix.data.Paragraph; import be.nikiroo.fanfix.data.Paragraph.ParagraphType; import be.nikiroo.fanfix.data.Story; import be.nikiroo.utils.Progress; import be.nikiroo.utils.Version; /** * This class is the base class used by the other output classes. It can be used * outside of this package, and have static method that you can use to get * access to the correct support class. * * @author niki */ public abstract class BasicOutput { /** * The supported output types for which we can get a {@link BasicOutput} * object. * * @author niki */ public enum OutputType { /** EPUB files created with this program */ EPUB, /** Pure text file with some rules */ TEXT, /** TEXT but with associated .info file */ INFO_TEXT, /** DEBUG output to console */ SYSOUT, /** ZIP with (PNG) images */ CBZ, /** LaTeX file with "book" template */ LATEX, /** HTML files in a dedicated directory */ HTML, ; @Override public String toString() { return super.toString().toLowerCase(); } /** * A description of this output type. * * @param longDesc * TRUE for the long description, FALSE for the short one * * @return the description */ public String getDesc(boolean longDesc) { StringId id = longDesc ? StringId.OUTPUT_DESC : StringId.OUTPUT_DESC_SHORT; String desc = Instance.getInstance().getTrans().getStringX(id, this.name()); if (desc == null) { desc = Instance.getInstance().getTrans().getString(id, this.toString()); } if (desc == null || desc.isEmpty()) { desc = this.toString(); } return desc; } /** * The default extension to add to the output files. * * @param readerTarget * TRUE to point to the main {@link Story} entry point for a * reader (for instance, the main entry point if this * {@link Story} is in a directory bundle), FALSE to point to * the main file even if it is a directory for instance * * @return the extension */ public String getDefaultExtension(boolean readerTarget) { BasicOutput output = BasicOutput.getOutput(this, false, false); if (output != null) { return output.getDefaultExtension(readerTarget); } return null; } /** * Call {@link OutputType#valueOf(String)} after conversion to upper * case. * * @param typeName * the possible type name * * @return NULL or the type */ public static OutputType valueOfUC(String typeName) { return OutputType.valueOf(typeName == null ? null : typeName .toUpperCase()); } /** * Call {@link OutputType#valueOf(String)} after conversion to upper * case but return def for NULL and empty instead of raising an * exception. * * @param typeName * the possible type name * @param def * the default value * * @return NULL or the type */ public static OutputType valueOfNullOkUC(String typeName, OutputType def) { if (typeName == null || typeName.isEmpty()) { return def; } return OutputType.valueOfUC(typeName); } /** * Call {@link OutputType#valueOf(String)} after conversion to upper * case but return def in case of error instead of raising an exception. * * @param typeName * the possible type name * @param def * the default value * * @return NULL or the type */ public static OutputType valueOfAllOkUC(String typeName, OutputType def) { try { return OutputType.valueOfUC(typeName); } catch (Exception e) { return def; } } } /** The creator name (this program, by me!) */ static protected final String EPUB_CREATOR = "Fanfix " + Version.getCurrentVersion() + " (by Niki)"; /** The current best name for an image */ private String imageName; private File targetDir; private String targetName; private OutputType type; private boolean writeCover; private boolean writeInfo; private Progress storyPg; private Progress chapPg; /** * Process the {@link Story} into the given target. * * @param story * the {@link Story} to export * @param target * the target where to save to (will not necessary be taken as is * by the processor, for instance an extension can be added) * @param pg * the optional progress reporter * * @return the actual main target saved, which can be slightly different * that the input one * * @throws IOException * in case of I/O error */ public File process(Story story, String target, Progress pg) throws IOException { storyPg = pg; File targetDir = null; String targetName = null; if (target != null) { target = new File(target).getAbsolutePath(); targetDir = new File(target).getParentFile(); targetName = new File(target).getName(); String ext = getDefaultExtension(false); if (ext != null && !ext.isEmpty()) { if (targetName.toLowerCase().endsWith(ext)) { targetName = targetName.substring(0, targetName.length() - ext.length()); } } } return process(story, targetDir, targetName); } /** * Process the {@link Story} into the given target. *
* This method is expected to be overridden in most cases. * * @param story * the {@link Story} to export * @param targetDir * the target dir where to save to * @param targetName * the target filename (will not necessary be taken as is by the * processor, for instance an extension can be added) * * * @return the actual main target saved, which can be slightly different * that the input one * * @throws IOException * in case of I/O error */ protected File process(Story story, File targetDir, String targetName) throws IOException { this.targetDir = targetDir; this.targetName = targetName; writeStory(story); return null; } /** * The output type. * * @return the type */ public OutputType getType() { return type; } /** * Enable the creation of a .info file next to the resulting processed file. * * @return TRUE to enable it */ protected boolean isWriteInfo() { return writeInfo; } /** * Enable the creation of a cover file next to the resulting processed file * if possible. * * @return TRUE to enable it */ protected boolean isWriteCover() { return writeCover; } /** * The output type. * * @param type * the new type * @param writeCover * TRUE to enable the creation of a cover if possible * @param writeInfo * TRUE to enable the creation of a .info file * * @return this */ protected BasicOutput setType(OutputType type, boolean writeInfo, boolean writeCover) { this.type = type; this.writeInfo = writeInfo; this.writeCover = writeCover; return this; } /** * The default extension to add to the output files. * * @param readerTarget * TRUE to point to the main {@link Story} entry point for a * reader (for instance, the main entry point if this * {@link Story} is in a directory bundle), FALSE to point to the * main file even if it is a directory for instance * * @return the extension */ public String getDefaultExtension( @SuppressWarnings("unused") boolean readerTarget) { return ""; } protected void writeStoryHeader(Story story) throws IOException { } protected void writeChapterHeader(Chapter chap) throws IOException { } protected void writeParagraphHeader(Paragraph para) throws IOException { } protected void writeStoryFooter(Story story) throws IOException { } protected void writeChapterFooter(Chapter chap) throws IOException { } protected void writeParagraphFooter(Paragraph para) throws IOException { } protected void writeStory(Story story) throws IOException { if (storyPg == null) { storyPg = new Progress(0, story.getChapters().size() + 2); } else { storyPg.setMinMax(0, story.getChapters().size() + 2); } String chapterNameNum = String.format("%03d", 0); String paragraphNumber = String.format("%04d", 0); imageName = paragraphNumber + "_" + chapterNameNum; if (story.getMeta() != null) { story.getMeta().setType("" + getType()); } if (isWriteCover()) { InfoCover.writeCover(targetDir, targetName, story.getMeta()); } if (isWriteInfo()) { InfoCover.writeInfo(targetDir, targetName, story.getMeta()); } storyPg.setProgress(1); List