Merge branch 'subtree'
[fanfix.git] / src / be / nikiroo / fanfix / output / BasicOutput.java
index e2bf2ff89fc0e28c382b8c8fa20db5a357b27e49..62a008c001b8b3697671079ab34b839fef74bf31 100644 (file)
@@ -2,13 +2,17 @@ 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.Story;
 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
@@ -36,7 +40,13 @@ public abstract class BasicOutput {
                /** ZIP with (PNG) images */
                CBZ,
                /** LaTeX file with "book" template */
-               LATEX;
+               LATEX,
+               /** HTML files in a dedicated directory */
+               HTML,
+
+               ;
+
+               @Override
                public String toString() {
                        return super.toString().toLowerCase();
                }
@@ -44,22 +54,51 @@ public abstract class BasicOutput {
                /**
                 * A description of this output type.
                 * 
+                * @param longDesc
+                *            TRUE for the long description, FALSE for the short one
+                * 
                 * @return the description
                 */
-               public String getDesc() {
-                       String desc = Instance.getTrans().getStringX(StringId.OUTPUT_DESC,
-                                       this.name());
+               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.getTrans()
-                                               .getString(StringId.OUTPUT_DESC, this);
+                               desc = Instance.getInstance().getTrans().getString(id, this.toString());
+                       }
+
+                       if (desc == null || desc.isEmpty()) {
+                               desc = this.toString();
                        }
 
                        return desc;
                }
 
                /**
-                * Call {@link OutputType#valueOf(String.toUpperCase())}.
+                * 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
@@ -72,42 +111,48 @@ public abstract class BasicOutput {
                }
 
                /**
-                * Call {@link OutputType#valueOf(String.toUpperCase())} but return NULL
-                * for NULL instead of raising exception.
+                * 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) {
-                       if (typeName == null) {
-                               return null;
+               public static OutputType valueOfNullOkUC(String typeName, OutputType def) {
+                       if (typeName == null || typeName.isEmpty()) {
+                               return def;
                        }
 
                        return OutputType.valueOfUC(typeName);
                }
 
                /**
-                * Call {@link OutputType#valueOf(String.toUpperCase())} but return NULL
-                * in case of error instead of raising an exception.
+                * 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) {
+               public static OutputType valueOfAllOkUC(String typeName, OutputType def) {
                        try {
                                return OutputType.valueOfUC(typeName);
                        } catch (Exception e) {
-                               return null;
+                               return def;
                        }
                }
        }
 
        /** The creator name (this program, by me!) */
-       static final String EPUB_CREATOR = "Fanfix (by Niki)";
+       static protected final String EPUB_CREATOR = "Fanfix "
+                       + Version.getCurrentVersion() + " (by Niki)";
 
        /** The current best name for an image */
        private String imageName;
@@ -116,6 +161,8 @@ public abstract class BasicOutput {
        private OutputType type;
        private boolean writeCover;
        private boolean writeInfo;
+       private Progress storyPg;
+       private Progress chapPg;
 
        /**
         * Process the {@link Story} into the given target.
@@ -125,6 +172,8 @@ public abstract class BasicOutput {
         * @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
@@ -132,16 +181,23 @@ public abstract class BasicOutput {
         * @throws IOException
         *             in case of I/O error
         */
-       public File process(Story story, String target) throws IOException {
-               target = new File(target).getAbsolutePath();
-               File targetDir = new File(target).getParentFile();
-               String targetName = new File(target).getName();
-
-               String ext = getDefaultExtension();
-               if (ext != null && !ext.isEmpty()) {
-                       if (targetName.toLowerCase().endsWith(ext)) {
-                               targetName = targetName.substring(0,
-                                               targetName.length() - ext.length());
+       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());
+                               }
                        }
                }
 
@@ -161,6 +217,7 @@ public abstract class BasicOutput {
         *            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
         * 
@@ -186,34 +243,59 @@ public abstract class BasicOutput {
                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 infoCover
-        *            TRUE to enable the creation of a .info file and a cover if
-        *            possible
+        * @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 writeCover,
-                       boolean writeInfo) {
+       protected BasicOutput setType(OutputType type, boolean writeInfo,
+                       boolean writeCover) {
                this.type = type;
-               this.writeCover = writeCover;
                this.writeInfo = writeInfo;
+               this.writeCover = writeCover;
 
                return this;
        }
 
        /**
         * The default extension to add to the output files.
-        * <p>
-        * Cannot be NULL!
+        * 
+        * @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
         */
-       protected String getDefaultExtension() {
+       public String getDefaultExtension(
+                       @SuppressWarnings("unused") boolean readerTarget) {
                return "";
        }
 
@@ -236,26 +318,49 @@ public abstract class BasicOutput {
        }
 
        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 + ".png";
+               imageName = paragraphNumber + "_" + chapterNameNum;
 
                if (story.getMeta() != null) {
                        story.getMeta().setType("" + getType());
                }
 
-               if (writeCover) {
+               if (isWriteCover()) {
                        InfoCover.writeCover(targetDir, targetName, story.getMeta());
                }
-               if (writeInfo) {
+               if (isWriteInfo()) {
                        InfoCover.writeInfo(targetDir, targetName, story.getMeta());
                }
 
-               writeStoryHeader(story);
+               storyPg.setProgress(1);
+
+               List<Progress> chapPgs = new ArrayList<Progress>(story.getChapters()
+                               .size());
                for (Chapter chap : story) {
-                       writeChapter(chap);
+                       chapPg = new Progress(0, chap.getParagraphs().size());
+                       storyPg.addProgress(chapPg, 1);
+                       chapPgs.add(chapPg);
+                       chapPg = null;
+               }
+
+               writeStoryHeader(story);
+               for (int i = 0; i < story.getChapters().size(); i++) {
+                       chapPg = chapPgs.get(i);
+                       writeChapter(story.getChapters().get(i));
+                       chapPg.setProgress(chapPg.getMax());
+                       chapPg = null;
                }
                writeStoryFooter(story);
+
+               storyPg.setProgress(storyPg.getMax());
+               storyPg = null;
        }
 
        protected void writeChapter(Chapter chap) throws IOException {
@@ -269,13 +374,17 @@ public abstract class BasicOutput {
 
                int num = 0;
                String paragraphNumber = String.format("%04d", num++);
-               imageName = chapterNameNum + "_" + paragraphNumber + ".png";
+               imageName = chapterNameNum + "_" + paragraphNumber;
 
                writeChapterHeader(chap);
+               int i = 1;
                for (Paragraph para : chap) {
                        paragraphNumber = String.format("%04d", num++);
-                       imageName = chapterNameNum + "_" + paragraphNumber + ".png";
+                       imageName = chapterNameNum + "_" + paragraphNumber;
                        writeParagraph(para);
+                       if (chapPg != null) {
+                               chapPg.setProgress(i++);
+                       }
                }
                writeChapterFooter(chap);
        }
@@ -286,6 +395,7 @@ public abstract class BasicOutput {
                writeParagraphFooter(para);
        }
 
+       @SuppressWarnings("unused")
        protected void writeTextLine(ParagraphType type, String line)
                        throws IOException {
        }
@@ -402,27 +512,33 @@ public abstract class BasicOutput {
         * 
         * @param type
         *            the type
-        * @param infoCover
-        *            force the <tt>.info</tt> file and the cover to be saved next
+        * @param writeCover
+        *            TRUE to enable the creation of a cover if possible to be saved
+        *            next to the main target file
+        * @param writeInfo
+        *            TRUE to enable the creation of a .info file to be saved next
         *            to the main target file
         * 
         * @return the {@link BasicOutput}
         */
-       public static BasicOutput getOutput(OutputType type, boolean infoCover) {
+       public static BasicOutput getOutput(OutputType type, boolean writeInfo,
+                       boolean writeCover) {
                if (type != null) {
                        switch (type) {
                        case EPUB:
-                               return new Epub().setType(type, infoCover, infoCover);
+                               return new Epub().setType(type, writeInfo, writeCover);
                        case TEXT:
-                               return new Text().setType(type, true, infoCover);
+                               return new Text().setType(type, writeInfo, true);
                        case INFO_TEXT:
                                return new InfoText().setType(type, true, true);
                        case SYSOUT:
                                return new Sysout().setType(type, false, false);
                        case CBZ:
-                               return new Cbz().setType(type, infoCover, infoCover);
+                               return new Cbz().setType(type, writeInfo, writeCover);
                        case LATEX:
-                               return new LaTeX().setType(type, infoCover, infoCover);
+                               return new LaTeX().setType(type, writeInfo, writeCover);
+                       case HTML:
+                               return new Html().setType(type, writeInfo, writeCover);
                        }
                }