RenderStaProMa2.java

package de.japrost.staproma;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.time.LocalDate;
import java.util.Date;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOCase;
import org.apache.commons.io.filefilter.FileFilterUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.RegexFileFilter;

import de.japrost.staproma.renderer.ScheduledTaskHtmlRenderer;
import de.japrost.staproma.renderer.StatusTaskHtmlRenderer;
import de.japrost.staproma.task.FolderTask;
import de.japrost.staproma.task.LeafTask;
import de.japrost.staproma.task.Task;

/**
 * Second edition of RenderStaProMa.
 *
 * @author alexxismachine (Ulrich David)
 */
public class RenderStaProMa2 {

	/** The base dir to read from. */
	private final File startDir;
	/** The base dir to write to. */
	private final File outDir;
	private final IOFileFilter fileFilter;
	private final String currentFileName = "01_currentItems.html";
	private final String waitingFileName = "02_waitingItems.html";
	private final String scheduledFileName = "03_scheduledItems.html";
	private final String futureFileName = "10_futureItems.html";
	private final String somedayFileName = "20_somedayItems.html";
	private final String doneFileName = "99_doneItems.html";

	/**
	 * Init using start dir also as out dir.
	 *
	 * @param startDir The base dir to read from.
	 * @param fileFilter filter which files to use.
	 */
	public RenderStaProMa2(final File startDir, final IOFileFilter fileFilter) {
		this(startDir, startDir, fileFilter);
	}

	/**
	 * Init.
	 *
	 * @param startDir The base dir to read from.
	 * @param outDir The base dir to write to.
	 * @param fileFilter filter which files to use.
	 */
	public RenderStaProMa2(final File startDir, final File outDir, final IOFileFilter fileFilter) {
		this.startDir = startDir;
		this.outDir = outDir;
		this.fileFilter = fileFilter;
		// FIXME use some logger
		boolean log = false;
		if (!log) {
			System.setOut(new PrintStream(new OutputStream() {

				@Override
				public void write(final int b) throws IOException {
					// NOOP
				}
			}));
		}
	}

	/**
	 * @param args command line args
	 * @throws IOException on io problems
	 */
	public static void main(final String[] args) throws IOException {
		final IOFileFilter currentFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?current\\..*$", IOCase.SENSITIVE));
		final IOFileFilter waitingFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?waiting\\..*$", IOCase.SENSITIVE));
		final IOFileFilter scheduleFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?schedule\\..*$", IOCase.SENSITIVE));
		final IOFileFilter futureFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?future\\..*$", IOCase.SENSITIVE));
		final IOFileFilter somedayFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?someday\\..*$", IOCase.SENSITIVE));
		final IOFileFilter doneFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?done\\..*$", IOCase.SENSITIVE));
		final IOFileFilter gtdFilter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^\\d*_?gtd\\..*$", IOCase.SENSITIVE));
		final IOFileFilter gtd2Filter = FileFilterUtils.and(FileFilterUtils.fileFileFilter(),
				new RegexFileFilter("^([A-Z]+)-(\\d+)_(.*)\\.spm$", IOCase.SENSITIVE));
		final IOFileFilter allFilter = FileFilterUtils.or(currentFilter, waitingFilter, scheduleFilter, futureFilter,
				somedayFilter, doneFilter, gtdFilter, gtd2Filter);
		File baseDir = new File("/home/uli/media/DSOne_home/01_ToDo/");
		File outDir = new File("/home/uli/media/DSOne_home/01_ToDo/");
		if (args.length > 0) {
			baseDir = new File(args[0]);
			outDir = baseDir;
			System.err.println("Starting for " + baseDir.getAbsolutePath());
		}
		if (args.length > 1) {
			outDir = new File(args[1]);
			System.err.println("Writing to " + outDir.getAbsolutePath());
		}
		final RenderStaProMa2 current = new RenderStaProMa2(baseDir, outDir, allFilter);
		current.doAll();
	}

	private void doAll() throws IOException {
		final Task rootTask = crawlFiles();
		final StatusTaskHtmlRenderer stw = new StatusTaskHtmlRenderer();
		writeFile(rootTask, stw, "Current", TaskState.CURRENT, currentFileName);
		writeFile(rootTask, stw, "Waiting", TaskState.WAITING, waitingFileName);
		// special handling for scheduled tasks
		// add a line for today
		final LeafTask today = new LeafTask(rootTask,
				LocalDate.now().toString() + " +-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+-_-+");
		today.setState(TaskState.SCHEDULE);
		rootTask.addChild(today);
		// special rendering
		writeScheduleFile(rootTask, "Scheduled", scheduledFileName);
		writeFile(rootTask, stw, "Future", TaskState.FUTURE, futureFileName);
		writeFile(rootTask, stw, "Someday", TaskState.SOMEDAY, somedayFileName);
		writeFile(rootTask, stw, "Done", TaskState.DONE, doneFileName);
		copyStyle();
	}

	private void writeScheduleFile(final Task root, final String title, final String fileName) throws IOException {
		StringWriter writer;
		writer = new StringWriter();
		writeHead(writer, title);
		final ScheduledTaskHtmlRenderer scheduledTaskHtmlRenderer = new ScheduledTaskHtmlRenderer(root, writer);
		scheduledTaskHtmlRenderer.render();
		writeFoot(writer);

		writeFile(fileName, writer.toString());
	}

	private void writeFile(final Task root, final StatusTaskHtmlRenderer stw, final String title, final TaskState status,
			final String fileName) throws IOException {
		StringWriter writer;
		writer = new StringWriter() {

			@Override
			public StringWriter append(final CharSequence csq) {
				write(String.valueOf(csq));
				write("\n");
				return this;
			}
		};
		writeHead(writer, title);
		stw.render(root, status, writer);
		writeFoot(writer);
		writeFile(fileName, writer.toString());
	}

	private void writeHead(final StringWriter writer, final String title) {
		writer.append("<!DOCTYPE html>\n");
		writer.append("<html>");
		writer.append("<head>");
		writer.append("<title>" + title + "</title>");
		writer.append("<link type='text/css' href='style.css' rel='stylesheet'/>");
		writer.append("<meta http-equiv='content-type' content='text/html; charset=UTF-8'/>");
		writer.append("<style>");
		for (int prio = 1; prio < 10; prio++) {
			writePriorityStyle(writer, prio);
		}
		writer.append("</style>");
		writer.append("</head>");
		writer.append("<body>");
		writer.append("<div class='navigation'>");
		writer.append("<a href='" + currentFileName + "'>Current</a> ");
		writer.append("<a href='" + waitingFileName + "'>Waiting</a> ");
		writer.append("<a href='" + scheduledFileName + "'>Scheduled</a> ");
		writer.append("<a href='" + futureFileName + "'>Future</a> ");
		writer.append("<a href='" + somedayFileName + "'>Someday</a> ");
		writer.append("<a href='" + doneFileName + "'>Done</a> ");
		writer.append("</div>");
		writer.append("<hr/>");
		writer.append("<div class='title'>" + title + " Items</div>");
		writer.append("<hr/>");
		writer.append("<form>");
		for (int prio = 1; prio < 10; prio++) {
			writePriorityFrom(writer, prio);
		}
	}

	private void writePriorityFrom(final StringWriter writer, final int prio) {
		writer.append("<input type='checkbox' id='prio" + prio + "'" + (prio < 5 ? " checked" : "") + ">");
		writer.append("<label class='priority" + prio + "' for='prio" + prio + "'>Prio " + prio + "</label>");
	}

	private void writePriorityStyle(final StringWriter writer, final int prio) {
		writer.append(".priority" + prio + " {");
		writer.append("  max-height: 0;");
		writer.append("  overflow: hidden;");
		writer.append("}");
		for (int level = 2; level < 7; level++) {
			writer.append("#prio" + prio + ":checked ~h" + level + ".priority" + prio + " {");
			writer.append("  max-height: 100%;");
			writer.append("}");
		}
		writer.append("#prio" + prio + ":checked ~ul li.priority" + prio + " {");
		writer.append("  max-height: 100%;");
		writer.append("}");
	}

	private void writeFoot(final StringWriter writer) {
		writer.append("<div class='generationTime'>" + new Date().toString() + "</div>");
		writer.append("</form>");
		writer.append("</body>");
		writer.append("</html>");
	}

	private Task crawlFiles() throws IOException {
		final Task root = new FolderTask(null, "ROOT");
		final TaskFileWalker fileWalker = new TaskFileWalker(root, startDir, fileFilter);
		fileWalker.crawl();
		return root;
	}

	private void writeFile(final String fileName, final String content) throws IOException {
		FileUtils.write(new File(outDir, fileName), content);
	}

	private void copyStyle() throws IOException {
		final File srcCssFile = new File("src/main/resources/style.css");
		if (srcCssFile.canRead()) {
			final File destCssFile = new File(outDir, "style.css");
			FileUtils.copyFile(srcCssFile, destCssFile);
		}
	}
}