/* LanguageTool, a natural language style checker
* Copyright (C) 2006 Daniel Naber (http://www.danielnaber.de)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
* USA
*/
package org.languagetool.dev;
import org.languagetool.JLanguageTool;
import org.languagetool.Language;
import org.languagetool.language.Contributor;
import org.languagetool.tools.StringTools;
import org.languagetool.tools.Tools;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
/**
* Command line tool to list supported languages and their number of rules.
*
* @author Daniel Naber
*/
public final class RuleOverview {
public static void main(final String[] args) throws IOException {
if (args.length != 1) {
System.out.println("Usage: " + RuleOverview.class.getName() + " <webRoot>");
System.exit(1);
}
final RuleOverview prg = new RuleOverview();
prg.run(new File(args[0]));
}
private RuleOverview() {
// no public constructor
}
private void run(File webRoot) throws IOException {
System.out.println("<b>Rules in LanguageTool " + JLanguageTool.VERSION + "</b><br />");
System.out.println("Date: " + new SimpleDateFormat("yyyy-MM-dd").format(new Date()) + "<br /><br />\n");
System.out.println("<table class=\"tablesorter sortable\">");
System.out.println("<thead>");
System.out.println("<tr>");
System.out.println(" <th valign='bottom' width=\"70\">Language</th>");
System.out.println(" <th valign='bottom' align=\"left\" width=\"60\">XML<br/>rules</th>");
System.out.println(" <th width=\"120\"></th>");
System.out.println(" <th align=\"left\" width=\"60\">Java<br/>rules</th>");
System.out.println(" <th align=\"left\" width=\"60\">False<br/>friends</th>");
//System.out.println(" <th valign='bottom' width=\"65\">Auto-<br/>detected</th>");
System.out.println(" <th valign='bottom' align=\"left\">Rule Maintainers</th>");
System.out.println("</tr>");
System.out.println("</thead>");
System.out.println("<tbody>");
final List<String> sortedLanguages = getSortedLanguages();
//setup false friends counting
final String falseFriendFile = JLanguageTool.getDataBroker().getRulesDir() + File.separator + "false-friends.xml";
final URL falseFriendUrl = this.getClass().getResource(falseFriendFile);
final String falseFriendRules = StringTools.readFile(Tools.getStream(falseFriendFile))
.replaceAll("(?s)<!--.*?-->", "")
.replaceAll("(?s)<rules.*?>", "");
int overallJavaCount = 0;
int langSpecificWebsiteCount = 0;
for (final String langName : sortedLanguages) {
final Language lang = Language.getLanguageForName(langName);
if (lang.isVariant()) {
continue;
}
System.out.print("<tr>");
final String langCode = lang.getShortName();
final File langSpecificWebsite = new File(webRoot, langCode);
if (langSpecificWebsite.isDirectory()) {
System.out.print("<td valign=\"top\"><a href=\"../" + langCode + "/\">" + lang.getName() + "</a></td>");
langSpecificWebsiteCount++;
} else {
System.out.print("<td valign=\"top\">" + lang.getName() + "</td>");
}
//FIXME: this does not work for en-GB and en-US
final String xmlFile = JLanguageTool.getDataBroker().getRulesDir() + File.separator + langCode + File.separator + "grammar.xml";
final URL url = this.getClass().getResource(xmlFile);
if (url == null) {
System.out.println("<td valign=\"top\" align=\"right\">0</td>");
} else {
// count XML rules:
String xmlRules = StringTools.readFile(Tools.getStream(xmlFile));
xmlRules = xmlRules.replaceAll("(?s)<!--.*?-->", "");
xmlRules = xmlRules.replaceAll("(?s)<rules.*?>", "");
final int count = countXmlRules(xmlRules);
final int countInRuleGroup = countXmlRuleGroupRules(xmlRules);
final String ruleBase = "http://languagetool.svn.sourceforge.net/viewvc/languagetool/trunk/languagetool/languagetool-language-modules/"
+ langCode + "/src/main/resources/org/languagetool/rules/";
System.out.print("<td valign=\"top\" align=\"right\">" + (count + countInRuleGroup) + "</td>");
System.out.print("<td valign=\"top\" align=\"right\">" +
//"<a href=\"" + ruleBase + langCode + "/grammar.xml" + "\">Show</a> / " +
"<a href=\"" + ruleBase + langCode + "/grammar.xml?content-type=text%2Fplain" + "\">XML</a> / " +
"<a href=\"http://community.languagetool.org/rule/list?lang=" + langCode + "\">Browse</a>" +
"</td>");
}
// count Java rules:
final File dir = new File("../languagetool-language-modules/" + langCode + "/src/main/java" +
JLanguageTool.getDataBroker().getRulesDir() + "/" + langCode);
if (!dir.exists()) {
System.out.print("<td valign=\"top\" align=\"right\">0</td>");
} else {
final File[] javaRules = dir.listFiles(new JavaFilter(langName));
final int javaCount = javaRules.length;
if (javaCount > 0) {
final String sourceCodeLink =
"http://languagetool.svn.sourceforge.net/viewvc/languagetool/trunk/languagetool/languagetool-language-modules/"
+ langCode + "/src/main/java/org/languagetool/rules/"
+ langCode + "/";
System.out.print("<td valign=\"top\" align=\"right\"><a href=\"" + sourceCodeLink + "\">" + javaCount + "</a></td>");
} else {
System.out.print("<td valign=\"top\" align=\"right\">" + javaCount + "</td>");
}
overallJavaCount++;
}
// false friends
if (falseFriendUrl == null) {
System.out.println("<td valign=\"top\" align=\"right\">0</td>");
} else {
final int count = countFalseFriendRules(falseFriendRules, lang);
System.out.print("<td valign=\"top\" align=\"right\">" + count + "</td>");
//System.out.print("<td valign=\"top\">" + (isAutoDetected(lang.getShortName()) ? "yes" : "-") + "</td>");
// maintainer information:
final StringBuilder maintainerInfo = getMaintainerInfo(lang);
System.out.print("<td valign=\"top\" align=\"left\">" + maintainerInfo.toString() + "</td>");
}
System.out.println("</tr>");
}
if (overallJavaCount == 0) {
throw new RuntimeException("No Java rules found - start this script from the LanguageTool directory so " +
"that the sources are at 'src/main/java/org/languagetool/rules'");
}
if (langSpecificWebsiteCount == 0) {
throw new RuntimeException("No language specific websites found - please let the web root parameter " +
"point to the 'www' directory (current value: '" + webRoot + "')");
}
System.out.println("</tbody>");
System.out.println("</table>");
}
private List<String> getSortedLanguages() {
final List<String> sortedLanguages = new ArrayList<String>();
for (Language element : Language.LANGUAGES) {
if (element == Language.DEMO) {
continue;
}
sortedLanguages.add(element.getName());
}
Collections.sort(sortedLanguages);
return sortedLanguages;
}
private int countXmlRules(String xmlRules) {
int pos = 0;
int count = 0;
while (true) {
pos = xmlRules.indexOf("<rule ", pos + 1);
if (pos == -1) {
break;
}
count++;
}
return count;
}
private int countXmlRuleGroupRules(String xmlRules) {
int pos = 0;
int countInRuleGroup = 0;
while (true) {
pos = xmlRules.indexOf("<rule>", pos + 1);
if (pos == -1) {
break;
}
countInRuleGroup++;
}
return countInRuleGroup;
}
private int countFalseFriendRules(String falseFriendRules, Language lang) {
int pos = 0;
int count = 0;
while (true) {
pos = falseFriendRules.indexOf("<pattern lang=\"" + lang.getShortName(), pos + 1);
if (pos == -1) {
break;
}
count++;
}
return count;
}
private StringBuilder getMaintainerInfo(Language lang) {
final StringBuilder maintainerInfo = new StringBuilder();
if (lang.getMaintainers() != null) {
for (Contributor contributor : lang.getMaintainers()) {
if (!StringTools.isEmpty(maintainerInfo.toString())) {
maintainerInfo.append(", ");
}
if (contributor.getUrl() != null) {
maintainerInfo.append("<a href=\"");
maintainerInfo.append(contributor.getUrl());
maintainerInfo.append("\">");
}
maintainerInfo.append(contributor.getName());
if (contributor.getUrl() != null) {
maintainerInfo.append("</a>");
}
if (contributor.getRemark() != null) {
maintainerInfo.append(" (" + contributor.getRemark() + ")");
}
}
}
return maintainerInfo;
}
/*private boolean isAutoDetected(String code) {
if (LanguageIdentifier.getSupportedLanguages().contains(code)) {
return true;
}
final Set<String> additionalCodes = new HashSet<String>(Arrays.asList(LanguageIdentifierTools.ADDITIONAL_LANGUAGES));
if (additionalCodes.contains(code)) {
return true;
}
return false;
}*/
}
class JavaFilter implements FileFilter {
private final String langName;
public JavaFilter(String langName) {
this.langName = langName;
}
public boolean accept(final File f) {
final String filename = f.getName();
final boolean isAbstractTopClass = filename.endsWith(langName + "Rule.java");
if (filename.endsWith(".java") && !isAbstractTopClass) {
return true;
}
return false;
}
}