package water.api; import java.io.*; import java.util.ArrayList; import java.util.Iterator; import water.Boot; import water.util.Log; /** * Basic page introducing tutorial for Random Forest on Iris * * @author michal * */ abstract public class TutorialWorkflow extends HTMLOnlyRequest { protected final Int _step = new Int(STEP, 1); /** Returns a workflow to show */ protected abstract TutorWorkflow getWorkflow(); @Override protected String build(Response response) { StringBuilder sb = new StringBuilder(); sb.append("<script type='text/javascript' src='tutorials/js/basic.js'></script>"); decorateWorkflow(getWorkflow(), sb, _step.value()); return sb.toString(); } /** Shows the active workflow step */ protected void decorateActiveStep(final TutorStep step, StringBuilder sb) { sb.append("<h4>").append(step.summary()).append("</h4>"); sb.append(step.content()); } protected void decorateWorkflow(final TutorWorkflow twf, StringBuilder sb, int activeStepNum) { int len = twf.length(); TutorStep activeStep = twf.getStep(activeStepNum); // Format tutorial header sb.append("<div class='container' style='margin: 0px auto'>"); sb.append("<h2>").append(twf.title()).append("</h2>"); sb.append("<blockquote><p>").append(activeStep.summary()).append("</p>"); sb.append("<small>Step ").append(activeStepNum).append(" of ").append(len).append("</small>"); sb.append("</blockquote>"); // Container for left, right columns sb.append("<div class='row'>" ); // Append left column with list of tutorial steps sb.append("<div class='span3'>"); sb.append("<table class='table table-stripped'>"); for (TutorStep ts : twf) { sb.append("<tr>"); sb.append("<td><span class='label ").append(activeStepNum == ts.ord ? "label-info" : "" ).append("'>").append(ts.title()).append("</span></td>"); sb.append("<td>"); if (activeStepNum == ts.ord) { sb.append("<strong>").append(ts.summary()).append("</strong>"); } else { sb.append("<a href='").append(getStepUrl(ts.ord)).append("'>"); sb.append(ts.summary()); sb.append("</a>"); } sb.append("</td>"); sb.append("</tr>"); } sb.append("</table>"); sb.append("</div>"); // Close container for left column // Append right column with tutorial step description sb.append("<div class='span7 hero-unit'>"); decorateActiveStep(activeStep, sb); sb.append("</div>"); // Close container for right column sb.append("</div>"); // Close top-level row for left and right columns // Pager in the bottom of left/right column sb.append("<div class='row'>"); sb.append("<div class='span3'> </div>"); sb.append("<div class='span7'>"); sb.append("<ul class='pager'>"); String next = getStepUrl(activeStepNum+1); String prev = getStepUrl(activeStepNum-1); sb.append(activeStepNum > 1 ? "<li><a href='"+prev+"'>Previous</a></li>" : "<li class='disabled'><a href='#'>Previous</a></li>"); sb.append(activeStepNum < len ? "<li><a href='"+next+"'>Next</a></li>" : "<li class='disabled'><a href='#'>Next</a></li>"); sb.append("</ul>"); sb.append("</div>"); sb.append("</div>"); // Close top-level container sb.append("</div>"); } String getStepUrl(int step) { return this.getClass().getSimpleName() + ".html?step=" + step; } /** A simple tutorial workflow representation */ protected class TutorWorkflow implements Iterable<TutorStep> { private final ArrayList<TutorStep> _steps = new ArrayList<TutorialWorkflow.TutorStep>(); private final String _title; public TutorWorkflow(String title) { _title = title; } /** Add a new step into tutorial workflow */ public void addStep(int num, TutorStep step) { _steps.add(step); step.ord = num; } /** Get tutorial step. Step parameter is 1-based. */ public TutorStep getStep(int step) { return _steps.get(step-1); } @Override public Iterator<TutorStep> iterator() { return _steps.iterator(); } public final int length() { return _steps.size(); } public final String title() { return _title; } } /** Simple tutorial step defined by its title, summary, and content. */ protected abstract class TutorStep { int ord; /* Array storing step name, title, and content */ protected final String[] _info; public final String title() { return _info[0]; } public final String summary() { return _info[1]; } /* Override this method to provide the content */ public abstract String content(); public TutorStep(final String[] info) { assert info.length >= 2; _info = info; } } /** Tutorial step stored in file */ protected class FileTutorStep extends TutorStep { private String _content; public FileTutorStep(String[] info) { super(info); assert info.length == 3; } @Override synchronized public final String content() { if (_content == null) _content = loadContent(_info[2]); return _content; } private String loadContent(String fromFile) { BufferedReader reader = null; StringBuilder sb = new StringBuilder(); try { InputStream is = Boot._init.getResource2(fromFile); assert is != null : "Bundled resource " + fromFile + " does not exist!"; reader = new BufferedReader(new InputStreamReader(is)); String line = null; while( (line = reader.readLine())!=null) sb.append(line).append('\n'); } catch( IOException e ) { /* Silently ignoring */ Log.err(e); } finally { if (reader!=null) try { reader.close(); } catch( IOException e ) { throw new RuntimeException(Log.err("IOException during reader close.",e)); } } return sb.toString(); } } }