/*
* CraftBook Copyright (C) 2010-2017 sk89q <http://www.sk89q.com>
* CraftBook Copyright (C) 2011-2017 me4502 <http://www.me4502.com>
* CraftBook Copyright (C) Contributors
*
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
* License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this program. If not,
* see <http://www.gnu.org/licenses/>.
*/
package com.sk89q.craftbook.core.util.documentation;
import com.sk89q.craftbook.core.CraftBookAPI;
import com.sk89q.craftbook.core.util.ConfigValue;
import com.sk89q.craftbook.core.util.PermissionNode;
import ninja.leaping.configurate.ConfigurationNode;
import ninja.leaping.configurate.commented.SimpleCommentedConfigurationNode;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class DocumentationGenerator {
private static final Pattern PERMS_PATTERN = Pattern.compile("%PERMS%", Pattern.LITERAL);
private static final Pattern CONFIG_PATTERN = Pattern.compile("%CONFIG%", Pattern.LITERAL);
private static final Pattern IMPORT_PATTERN = Pattern.compile("%IMPORT (.*)%");
private static String[] searchLocations = {"../docs", "docs", "config/craftbook/docs", "../config/craftbook/docs"};
private static File rootDirectory;
private static File getRootDirectory() {
if (rootDirectory == null) {
File wd = new File(".");
File rootDir;
for (String searchLocation : searchLocations) {
rootDir = new File(wd, searchLocation);
if (rootDir.exists()) {
rootDirectory = rootDir;
break;
}
}
}
return rootDirectory;
}
public static void generateDocumentation(DocumentationProvider provider) {
File docFile = new File(getRootDirectory(), "source/" + provider.getPath() + ".rst");
docFile.getParentFile().mkdirs();
File template = new File(getRootDirectory(), "templates/" + provider.getTemplatePath() + ".rst");
if (!template.exists()) {
CraftBookAPI.inst().getLogger().warn("Failed to find template for " + provider.getPath());
return;
}
String output = makeReplacements(loadFile(template), provider);
try(PrintWriter writer = new PrintWriter(docFile)) {
writer.write(output);
} catch(IOException e) {
CraftBookAPI.inst().getLogger().error("An IO Exception occured.", e);
}
}
public static String loadFile(File inputFile) {
StringBuilder output = new StringBuilder();
if (inputFile.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
String temp;
while ((temp = reader.readLine()) != null)
output.append(temp).append('\n');
} catch (IOException e) {
e.printStackTrace();
}
}
return output.toString();
}
public static String makeReplacements(String input, DocumentationProvider provider) {
StringBuilder configSection = new StringBuilder();
if(provider.getConfigurationNodes().length > 0) {
configSection.append("Configuration\n");
configSection.append("=============\n\n");
int nodeLength = "Node".length(), commentLength = "Comment".length(), typeLength = "Type".length(), defaultLength = "Default".length();
for(ConfigValue<?> configValue : provider.getConfigurationNodes()) {
if(configValue.getKey().length() > nodeLength)
nodeLength = configValue.getKey().length();
if(configValue.getComment().length() > commentLength)
commentLength = configValue.getComment().length();
if(configValue.getTypeToken().getRawType().getSimpleName().length() > typeLength)
typeLength = configValue.getTypeToken().getRawType().getSimpleName().length();
ConfigurationNode node = SimpleCommentedConfigurationNode.root();
configValue.serializeDefault(node);
if(node.getString("null").length() > defaultLength)
defaultLength = node.getString("null").length();
}
String border = createStringOfLength(nodeLength, '=') + ' ' + createStringOfLength(commentLength, '=') + ' ' + createStringOfLength(typeLength, '=') + ' ' + createStringOfLength(defaultLength, '=');
configSection.append(border).append('\n');
configSection.append(padToLength("Node", nodeLength + 1)).append(padToLength("Comment", commentLength + 1)).append(padToLength("Type", typeLength + 1)).append(padToLength("Default", defaultLength + 1)).append('\n');
configSection.append(border).append('\n');
for(ConfigValue<?> configValue : provider.getConfigurationNodes()) {
ConfigurationNode node = SimpleCommentedConfigurationNode.root();
configValue.serializeDefault(node);
configSection.append(padToLength(configValue.getKey(), nodeLength + 1)).append(padToLength(configValue.getComment(), commentLength + 1)).append(padToLength(configValue.getTypeToken().getRawType().getSimpleName(), typeLength + 1)).append(padToLength(node.getString("null"), defaultLength + 1)).append('\n');
}
configSection.append(border).append('\n');
}
input = CONFIG_PATTERN.matcher(input).replaceAll(Matcher.quoteReplacement(configSection.toString()));
StringBuilder permissionsSection = new StringBuilder();
if(provider.getPermissionNodes().length > 0) {
permissionsSection.append("Permissions\n");
permissionsSection.append("===========\n\n");
int nodeLength = "Node".length(), descriptionLength = "Description".length(), defaultRoleLength = "Default Role".length();
for(PermissionNode permissionNode : provider.getPermissionNodes()) {
if(permissionNode.getNode().length() > nodeLength)
nodeLength = permissionNode.getNode().length();
if(permissionNode.getDescription().length() > descriptionLength)
descriptionLength = permissionNode.getDescription().length();
if(permissionNode.getDefaultRole().length() > defaultRoleLength)
defaultRoleLength = permissionNode.getDefaultRole().length();
}
String border = createStringOfLength(nodeLength, '=') + ' ' + createStringOfLength(descriptionLength, '=') + ' ' + createStringOfLength(defaultRoleLength, '=');
permissionsSection.append(border).append('\n');
permissionsSection.append(padToLength("Node", nodeLength + 1)).append(padToLength("Description", descriptionLength + 1)).append(padToLength("Default Role", defaultRoleLength + 1)).append('\n');
permissionsSection.append(border).append('\n');
for(PermissionNode permissionNode : provider.getPermissionNodes()) {
permissionsSection.append(padToLength(permissionNode.getNode(), nodeLength + 1)).append(padToLength(permissionNode.getDescription(), descriptionLength + 1)).append(padToLength(permissionNode.getDefaultRole(), defaultRoleLength + 1)).append('\n');
}
permissionsSection.append(border).append('\n');
}
input = PERMS_PATTERN.matcher(input).replaceAll(Matcher.quoteReplacement(permissionsSection.toString()));
input = provider.performCustomConversions(input);
Matcher importMatcher = IMPORT_PATTERN.matcher(input);
while(importMatcher.find()) {
String fileDir = importMatcher.group(1);
File file = new File(new File(getRootDirectory(), "templates/" + provider.getTemplatePath() + ".rst").getParentFile(), fileDir + ".rst");
input = input.replace("%IMPORT " + fileDir + '%', makeReplacements(loadFile(file), provider));
}
return input;
}
public static String createStringOfLength(int length, char character) {
StringBuilder ret = new StringBuilder();
for(int i = 0; i < length; i++)
ret.append(character);
return ret.toString();
}
public static String padToLength(String input, int length) {
StringBuilder builder = new StringBuilder(input);
while(builder.length() < length)
builder.append(' ');
return builder.toString();
}
}