class PluginDocs {

    public static final String TARGET_DIR = "/target/web-sources/";
    MarkdownProcessor markdownProcessor = new MarkdownProcessor();

    /**
     * Generate the docs.
     * @param args no arguments necessary.
     */
    public static void main(String[] args) {
        try {
            new PluginDocs().scan();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * From a class definition resolve base URL common for all files in a maven project (project base directory).
     *
     * @param clazz class to use
     * @return base path (e.g. file:/J:/HotswapAgent/HibernatePlugin)
     */
    public static String getBaseURL(Class clazz) {
        String clazzUrl = clazz.getResource(clazz.getSimpleName() + ".class").toString();

        // strip path to the plugin from maven root directory
        String classPath = clazz.getName().replace(".", "/");
        return clazzUrl.replace("/target/classes/" + classPath, "").replace(".class", "");
    }

    /**
     *
     * @throws Exception
     */
    public void scan() throws Exception {
        StringBuilder html = new StringBuilder();
        addHtmlHeader(html);

        ClassPathAnnotationScanner scanner = new ClassPathAnnotationScanner(Plugin.class.getName(), new ClassPathScanner());

        for (String plugin : scanner.scanPlugins(getClass().getClassLoader(), PluginManager.PLUGIN_PACKAGE.replace(".", "/"))) {
            Class pluginClass = Class.forName(plugin);
            Plugin pluginAnnotation = (Plugin) pluginClass.getAnnotation(Plugin.class);

            String pluginName = pluginAnnotation.name();
            String pluginDocFile = "plugin/" + pluginName + ".html";
            String pluginLink = "ha-plugins/" + pluginName.toLowerCase() + "-plugin";

            URL url = new URL(getBaseURL(getClass()) + TARGET_DIR + pluginDocFile);
            boolean docExists = markdownProcessor.processPlugin(pluginClass, url);

            addHtmlRow(html, pluginAnnotation, docExists ? pluginLink : null);
        }

        addHtmlFooter(html);
        writeHtml(new URL(getBaseURL(getClass()) + TARGET_DIR + "plugins.html"), html.toString());


        String mainReadme = markdownProcessor.markdownToHtml(IOUtils.streamToString(new URL(
                getBaseURL(getClass()) + "/../README.md"
        ).openStream()));

        writeMainReadme(mainReadme);
    }

    private void writeMainReadme(String mainReadme) throws MalformedURLException {<FILL_FUNCTION_BODY>}


    private void addHtmlRow(StringBuilder html, Plugin annot, String pluginDocFile) {
        html.append("<tr>");
        html.append("<td>");
        html.append(annot.name());
        html.append("</td>");
        html.append("<td>");
        html.append(annot.description());
        html.append("</td>");
        html.append("<td>");
        commaSeparated(html, annot.testedVersions());
        html.append("</td>");
        html.append("<td>");
        commaSeparated(html, annot.expectedVersions());
        html.append("</td>");
        html.append("<td>");
        if (pluginDocFile != null) {
            html.append("<a href='");
            html.append(pluginDocFile);
            html.append("'>Documentation</a>");
        }
        html.append("</td>");
        html.append("</tr>");
    }

    private void addHtmlHeader(StringBuilder html) {
        html.append("<table>");
    }

    private void addHtmlFooter(StringBuilder html) {
        html.append("</table>");
    }

    private void commaSeparated(StringBuilder html, String[] strings) {
        boolean first = true;
        for (String s : strings) {
            if (!first)
                html.append(", ");
            html.append(s);
            first = false;
        }
    }

    private void writeHtml(URL url, String html) {
        try {
            assertDirExists(url);
            PrintWriter out = new PrintWriter(url.getFile());
            out.print(html);
            out.close();
        } catch (FileNotFoundException e) {
            throw new IllegalArgumentException("Unable to open file " + url + " to write HTML content.");
        }
    }

    /**
     * Create all required directories in path for a file
     */
    public static void assertDirExists(URL targetFile) {
        File parent = null;
        try {
            parent = new File(targetFile.toURI()).getParentFile();
        } catch (URISyntaxException e) {
            throw new IllegalStateException(e);
        }

        if(!parent.exists() && !parent.mkdirs()){
            throw new IllegalStateException("Couldn't create dir: " + parent);
        }
    }
}

        writeHtml(new URL(getBaseURL(getClass()) + TARGET_DIR + "README.html"), mainReadme);

        // each <h1> section
        for (String section : mainReadme.split("\\<h1\\>")) {
            if (section.isEmpty())
                continue;

            // create label as content between <h1> and </h1>
            int h1EndIndex = section.indexOf("</h1>");
            if (h1EndIndex > 0) {
                String label = section.substring(0, h1EndIndex);
                // strip off header, the web page already contains it
                String content = section.substring(h1EndIndex+5);

                // make user-friendly valid file name
                label = label.replaceAll("\\s", "-");
                label = label.replaceAll("[^A-Za-z0-9-]", "");
                label = label.toLowerCase();

                // name file after section name
                writeHtml(new URL(getBaseURL(getClass()) + TARGET_DIR + "section/" + label + ".html"), content);
            }
        }

    
<no_super_class>