/**
* Copyright (C) 2012 cogroo <cogroo@cogroo.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cogroo;
/**
* Copyright (C) 2008 CoGrOO Team (cogroo AT gmail DOT com)
*
* CoGrOO Team (cogroo AT gmail DOT com)
* LTA, PCS (Computer and Digital Systems Engineering Department),
* Escola Politécnica da Universidade de São Paulo
* Av. Prof. Luciano Gualberto, trav. 3, n. 380
* CEP 05508-900 - São Paulo - SP - BRAZIL
*
* http://cogroo.sourceforge.net/
*
* This file is part of CoGrOO.
*
* CoGrOO is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* CoGrOO 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 Lesser General Public
* License along with CoGrOO. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import br.usp.pcs.lta.cogroo.configuration.LegacyRuntimeConfiguration;
import br.usp.pcs.lta.cogroo.entity.Mistake;
import br.usp.pcs.lta.cogroo.entity.Sentence;
import br.usp.pcs.lta.cogroo.grammarchecker.CheckerResult;
import br.usp.pcs.lta.cogroo.grammarchecker.CogrooI;
import br.usp.pcs.lta.cogroo.tools.checker.rules.applier.RulesProvider;
import br.usp.pcs.lta.cogroo.tools.checker.rules.model.Example;
import br.usp.pcs.lta.cogroo.tools.checker.rules.model.Rule;
import br.usp.pcs.lta.cogroo.tools.checker.rules.model.Rules;
import br.usp.pcs.lta.cogroo.tools.checker.rules.util.RuleUtils;
import br.usp.pcs.lta.cogroo.tools.checker.rules.util.RuleUtils.RuleInfo;
import br.usp.pcs.lta.cogroo.tools.checker.rules.util.RulesContainerHelper;
import br.usp.pcs.lta.cogroo.util.StreamFactory;
/**
* This class grammar checks all examples from the rules file and prints an html
* report showing which rules are working.
*
* @author Marcelo Suzumura
*/
public class MultiCogrooHtml {
/**
* The file in which the report will be written.
*/
private OutputStreamWriter out = StreamFactory.createOutputStreamWriter(
"data/rules_status.html", "UTF-8");
/**
* The rules.
*/
private Rules rules;
/**
* The grammar checker.
*/
private CogrooI cogroo;
/**
* Examples that were not matched by any rule at all.
*/
private List<Rule> no = new ArrayList<Rule>();
/**
* Examples matched by the correct rule.
*/
private List<Rule> ok = new ArrayList<Rule>();
/**
* Examples matched by the correct rule, but matched by other rules too.
*/
private List<Rule> partial = new ArrayList<Rule>();
/**
* Examples matched only by other rules.
*/
private List<Rule> wrong = new ArrayList<Rule>();
/**
* List of rules that does not have any suggestion.
*/
private List<Rule> noSuggestions = new ArrayList<Rule>();
/**
* List of rules that does have bad suggestion.
*/
private List<Rule> badSuggestion = new ArrayList<Rule>();
/**
* Maps rules ids and the sentences that caused an exception.
*/
private Map<Long, List<String>> exceptions = new LinkedHashMap<Long, List<String>>();
private Map<Long, String> rulesInfo = new HashMap<Long, String>();
public MultiCogrooHtml() {
this.cogroo = new MultiCogroo(
new LegacyRuntimeConfiguration(
"/Users/wcolen/Documents/wrks/corpuswrk/cogroo3/CoGrOOBase/target/CoGrOOBase-3.1.3a-SNAPSHOT-bin")); // THE
// CoGrOO!
this.rules = new RulesContainerHelper().getContainerForXMLAccess()
.getComponent(RulesProvider.class).getRules();
}
private void test() throws Exception {
this.printHtmlHeader();
int totalRules = 0;
for (Rule rule : this.rules.getRule()) {
// Only active rules will be considered.
if (rule.isActive()) {
if (rule.getId() == 19) {
System.out.println("regra 19");
}
// Consolidates rule information.
this.prepareRuleInfo(rule);
totalRules++;
this.printRuleHeader(rule);
// Each position contains the mistakes for each example.
List<List<Mistake>> sentencesMistakes = new ArrayList<List<Mistake>>(
rule.getExample().size());
List<Sentence> sentences = new ArrayList<Sentence>(rule.getExample()
.size());
// Checks each incorrect example of the rule.
for (Example example : rule.getExample()) {
// Check sentence for mistakes.
try {
CheckerResult cr = this.cogroo.analyseAndCheckText(example
.getIncorrect());
sentencesMistakes.add(cr.mistakes);
sentences.add(cr.sentences.get(0));
} catch (RuntimeException e) {
sentencesMistakes.add(null);
sentences.add(null);
this.logException(Long.valueOf(rule.getId()),
example.getIncorrect());
}
}
this.evaluateMistakes(sentencesMistakes, sentences, rule);
this.printRuleFooter(rule);
}
this.storeNoSuggestionRule(rule);
}
this.printReport("ok", this.ok, totalRules, "00ff00");
this.printReport("partial", this.partial, totalRules, "ffff00");
this.printReport("no", this.no, totalRules, "ff8000");
this.printReport("wrong", this.wrong, totalRules, "ff0000");
this.printNoSuggestion();
this.printBadSuggestion();
this.printExceptionReport();
this.printHtmlFooter();
this.out.close();
}
private void prepareRuleInfo(Rule rule) {
Map<RuleInfo, String> mapInfo = RuleUtils.getRuleAsString(rule);
StringBuilder sb = new StringBuilder();
sb.append("<table border=\"1\">");
sb.append("<tr><th>Method</th><td>").append(mapInfo.get(RuleInfo.METHOD))
.append("</td></tr>");
sb.append("<tr><th>Type</th><td>").append(mapInfo.get(RuleInfo.TYPE))
.append("</td></tr>");
sb.append("<tr><th>Group</th><td>").append(mapInfo.get(RuleInfo.GROUP))
.append("</td></tr>");
sb.append("<tr><th>Message</th><td>").append(mapInfo.get(RuleInfo.MESSAGE))
.append("</td></tr>");
sb.append("<tr><th>ShortMessage</th><td>")
.append(mapInfo.get(RuleInfo.SHORTMESSAGE)).append("</td></tr>");
sb.append("<tr><th>Pattern</th><td>").append(mapInfo.get(RuleInfo.PATTERN))
.append("</td></tr>");
sb.append("<tr><th>Boundaries</th><td>")
.append(mapInfo.get(RuleInfo.BOUNDARIES)).append("</td></tr>");
sb.append("<tr><th>Suggestions</th><td>")
.append(mapInfo.get(RuleInfo.SUGGESTIONS)).append("</td></tr>");
sb.append("</table>");
String escapedHtml = this.escapeHtmlChars(sb.toString());
String newLineToBr = this.newLineToBr(escapedHtml);
this.rulesInfo.put(Long.valueOf(rule.getId()), newLineToBr);
}
private String prepareOverlib(Rule rule, String text) {
StringBuilder sb = new StringBuilder();
sb.append("<a href=\"javascript:void(0);\" onmouseover=\"return overlib('");
sb.append(this.rulesInfo.get(Long.valueOf(rule.getId())));
sb.append("', WIDTH, 768, LEFT, ABOVE, STICKY, CAPTION, 'Rule ");
sb.append(rule.getId());
sb.append("', MOUSEOFF);\" onmouseout=\"return nd();\">");
sb.append(text != null ? text + " " : "");
sb.append(Long.toString(rule.getId()));
sb.append("</a>");
return sb.toString();
}
private void printHtmlHeader() throws Exception {
this.out.append("<html>\n");
this.out.append("<head>\n");
// Imports the tooltip javascript.
this.out
.append(" <script type='text/javascript' src='overlib.js'></script>\n");
this.out
.append(" <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/> \n");
this.out.append("</head>\n");
this.out.append("<body>\n");
this.out
.append("<div id='overDiv' style='position:absolute; visibility:hidden; z-index:1000;'></div>\n");
}
private void printHtmlFooter() throws Exception {
this.out.append("</body>\n");
this.out.append("</html>\n");
}
private void printRuleHeader(Rule rule) throws Exception {
this.out.append("<table border='1' width='100%'>\n");
this.out.append(" <tr align='center'>\n");
// this.out.append(" <th colspan='2'>Rule ").append(Long.toString(rule.getId())).append("</th>\n");
this.out.append(" <th colspan='2'>");
this.out.append(this.prepareOverlib(rule, "Rule"));
this.out.append("</th>\n");
this.out.append(" </tr>\n");
}
private void printExamples(Example example, Sentence incorrectSentence)
throws Exception {
this.out.append(" <tr>\n");
this.out.append(" <td width='10%'>Incorrect</td>\n");
// this.out.append(" <td width='90%'>").append(example.getIncorrect()).append("</td>\n");
this.out
.append(" <td width='90%'>")
.append(
this.prepareAnalysisOverlib(example.getIncorrect(),
incorrectSentence)).append("</td>\n");
this.out.append(" </tr>\n");
this.out.append(" <tr>\n");
this.out.append(" <td width='10%'>Correct</td>\n");
this.out.append(" <td width='90%'>").append(example.getCorrect())
.append("</td>\n");
this.out.append(" </tr>\n");
}
private String prepareAnalysisOverlib(String incorrect,
Sentence incorrectSentence) {
StringBuilder sb = new StringBuilder();
sb.append("<a href=\"javascript:void(0);\" onmouseover=\"return overlib('");
sb.append(this.prepareAnalysisTable(incorrectSentence));
sb.append("', WIDTH, 480, LEFT, ABOVE, STICKY, CAPTION, 'Analysis for "");
sb.append(incorrect);
sb.append(""', MOUSEOFF);\" onmouseout=\"return nd();\">");
sb.append(incorrect);
sb.append("</a>");
return sb.toString();
}
private String prepareAnalysisTable(Sentence incorrectSentence) {
StringBuilder sb = new StringBuilder();
sb.append("<table border=\"1\">");
sb.append("<tr><th width=\"15%\">SyntTag</th><th width=\"15%\">ChunkTag</th><th width=\"20%\">Lexeme</th><th width=\"20%\">Primitive</th><th width=\"30%\">MorphoTag</th></tr>");
for (List<String> row : getAnalysisAsTable(incorrectSentence)) {
sb.append("<tr>");
for (String column : row) {
if (column == null) {
column = "null";
}
sb.append("<td>").append(column.equals("") ? " " : column)
.append("</td>");
}
sb.append("</tr>");
}
sb.append("</table>");
return this.escapeHtmlChars(sb.toString());
}
public List<List<String>> getAnalysisAsTable(Sentence sentence) {
if (sentence.getTokens().size() > 0
&& sentence.getTokens().get(0).getMorphologicalTag() == null) {
throw new IllegalStateException("The sentence was not analyzed yet.");
}
List<List<String>> analysis = new ArrayList<List<String>>(5);
for (int i = 0; i < sentence.getTokens().size(); i++) {
List<String> row = new ArrayList<String>();
if (sentence.getTokens().get(i).getSyntacticTag() != null) {
row.add(sentence.getTokens().get(i).getSyntacticTag().toString());
} else {
row.add("NULL!!");
}
row.add(sentence.getTokens().get(i).getChunkTag().toString());
row.add(sentence.getTokens().get(i).getLexeme());
row.add(sentence.getTokens().get(i).getPrimitive());
row.add(sentence.getTokens().get(i).getMorphologicalTag().toString());
analysis.add(row);
}
return analysis;
}
private void evaluateMistakes(List<List<Mistake>> sentencesMistakes,
List<Sentence> sentences, Rule rule) throws Exception {
int zeroMatches = 0;
int wrongMatches = 0;
int correctMatches = 0;
// sentencesMistakes.size() equals to the number of examples.
int sentence = 0;
for (List<Mistake> mistakes : sentencesMistakes) {
Example example = rule.getExample().get(sentence);
// Prints the incorrect and correct examples.
this.printExamples(example, sentences.get(sentence));
// Checks for null in case an exception occurred.
if (mistakes != null) {
if (mistakes.isEmpty()) {
zeroMatches++;
} else { // There were mistakes.
for (Mistake mistake : mistakes) {
int mistakeId = 0;
if (mistake.getRuleIdentifier().contains("xml:")) {
mistakeId = Integer.parseInt(mistake.getRuleIdentifier().replace(
"xml:", ""));
}
if (mistakeId == rule.getId()) {
correctMatches++;
this.out.append(" <tr bgcolor='00ff00'>\n");
} else {
wrongMatches++;
this.out.append(" <tr bgcolor='ff0000'>");
}
StringBuilder markedIncorrect = new StringBuilder(
example.getIncorrect());
try {
markedIncorrect.insert(mistake.getStart(), ">>>");
markedIncorrect.insert(mistake.getEnd() + 3, "<<<");
} catch (RuntimeException e) {
this.logException(Long.valueOf(rule.getId()),
example.getIncorrect());
}
// Incorrect sentence with the mistake between >>> and <<<.
this.out.append(" <td width='10%'>");
this.out.append(Integer.toString(mistakeId));
this.out.append("</td>\n");
this.out.append(" <td width='90%'>").append(markedIncorrect);
for (String suggestion : mistake.getSuggestions()) {
this.out.append(" [");
this.out.append(escapeHtmlSpaces(suggestion));
this.out.append("]");
}
this.out.append("</td>\n");
this.out.append(" </tr>\n");
}
}
}
sentence++;
}
if (zeroMatches > 0 && correctMatches == 0 && wrongMatches == 0) {
this.no.add(rule);
} else if (zeroMatches > 0 && correctMatches == 0 && wrongMatches > 0) {
this.wrong.add(rule);
} else if (zeroMatches > 0 && correctMatches > 0 && wrongMatches == 0) {
this.partial.add(rule);
} else if (zeroMatches > 0 && correctMatches > 0 && wrongMatches > 0) {
this.partial.add(rule);
} else if (zeroMatches == 0 && correctMatches == 0 && wrongMatches == 0) {
// An exception occurred.
} else if (zeroMatches == 0 && correctMatches == 0 && wrongMatches > 0) {
this.wrong.add(rule);
} else if (zeroMatches == 0 && correctMatches > 0 && wrongMatches == 0) {
this.ok.add(rule);
// point to try the suggestion
checkSuggestion(rule, sentencesMistakes, sentences);
} else if (zeroMatches == 0 && correctMatches > 0 && wrongMatches > 0) {
this.partial.add(rule);
}
}
private void checkSuggestion(Rule rule, List<List<Mistake>> mistakesList,
List<Sentence> sentences) {
long id = rule.getId();
if (id == 84)
System.out.println();
for (int i = 0; i < sentences.size(); i++) {
Sentence s = sentences.get(i);
List<Mistake> ml = mistakesList.get(i);
for (Mistake mistake : ml) {
int mistakeId = 0;
if (mistake.getRuleIdentifier().contains("xml:")) {
mistakeId = Integer.parseInt(mistake.getRuleIdentifier().replace(
"xml:", ""));
}
if (id != mistakeId)
System.out.println("Something wrong!!");
String[] suggestions = mistake.getSuggestions();
// at least one suggestion should fit
boolean suggestionIsOk = false;
for (String suggestion : suggestions) {
StringBuffer sb = new StringBuffer(s.getSentence());
sb.replace(mistake.getStart(), mistake.getEnd(), suggestion);
for (Example example : rule.getExample()) {
if (example.getIncorrect().contains(s.getSentence())) {
if (example.getCorrect().contains(sb)) {
suggestionIsOk = true;
} else {
System.out.println();
}
}
}
}
if (suggestionIsOk == false && suggestions.length > 0) {
this.badSuggestion.add(rule);
}
}
}
}
private void printRuleFooter(Rule rule) throws Exception {
this.out.append(" <tr>\n");
this.out.append(" <td>Status</td>\n");
if (this.no.contains(rule)) {
this.out.append(" <td bgcolor='ff8000'></td>\n"); // orange.
} else if (this.ok.contains(rule)) {
this.out.append(" <td bgcolor='00ff00'></td>\n"); // green.
} else if (this.wrong.contains(rule)) {
this.out.append(" <td bgcolor='ff0000'></td>\n"); // red.
} else if (this.partial.contains(rule)) {
this.out.append(" <td bgcolor='ffff00'></td>\n"); // yellow.
}
this.out.append(" </tr>\n");
this.out.append("</table>\n");
this.out.append("<br />\n");
}
private void printReport(String type, List<Rule> rulesStatus, int totalRules,
String color) throws Exception {
this.out.append("<table border='1' width='100%'>\n");
this.out.append(" <tr align='center' bgcolor='" + color + "'>\n");
this.out.append(" <td>").append(type).append(" = ");
this.out.append(rulesStatus.size() + "/" + totalRules);
this.out.append(" = ");
this.out.append(Double.toString((double) rulesStatus.size() / totalRules
* 100));
this.out.append("%</td>\n");
this.out.append(" </tr>\n");
this.out.append(" <tr>\n");
this.out.append(" <td>");
StringBuilder sb = new StringBuilder();
for (Rule rule : rulesStatus) {
sb.append(this.prepareOverlib(rule, null) + ", ");
}
if (sb.toString().endsWith(", ")) {
sb.delete(sb.length() - 2, sb.length()); // Removes the extra ", " at the
// end.
}
this.out.append(sb);
this.out.append("</td>\n");
this.out.append(" </tr>\n");
this.out.append("</table>\n");
this.out.append("<br />\n");
}
private void printNoSuggestion() throws Exception {
StringBuilder sb = new StringBuilder();
for (Rule rule : this.noSuggestions) {
sb.append(this.prepareOverlib(rule, null) + ", ");
}
if (sb.toString().endsWith(", ")) {
sb.delete(sb.length() - 2, sb.length()); // Removes the extra ", " at the
// end.
}
this.out.append("<table border='1' width='100%'>\n");
this.out.append(" <tr>\n");
this.out.append(" <th>no suggestions = ");
this.out.append(Integer.toString(this.noSuggestions.size()) + "/"
+ this.rules.getRule().size());
this.out.append(" = ");
this.out.append(Double.toString((double) this.noSuggestions.size()
/ this.rules.getRule().size() * 100));
this.out.append("%</th>\n");
this.out.append(" </tr>\n");
this.out.append(" <tr>\n");
this.out.append(" <td>").append(sb.toString()).append("</td>\n");
this.out.append(" </tr>\n");
this.out.append("</table>\n");
}
private void printBadSuggestion() throws Exception {
StringBuilder sb = new StringBuilder();
for (Rule rule : this.badSuggestion) {
sb.append(this.prepareOverlib(rule, null) + ", ");
}
if (sb.toString().endsWith(", ")) {
sb.delete(sb.length() - 2, sb.length()); // Removes the extra ", " at the
// end.
}
this.out.append("<table border='1' width='100%'>\n");
this.out.append(" <tr>\n");
this.out.append(" <th>bad suggestions = ");
this.out.append(Integer.toString(this.badSuggestion.size()) + "/"
+ this.rules.getRule().size());
this.out.append(" = ");
this.out.append(Double.toString((double) this.badSuggestion.size()
/ this.rules.getRule().size() * 100));
this.out.append("%</th>\n");
this.out.append(" </tr>\n");
this.out.append(" <tr>\n");
this.out.append(" <td>").append(sb.toString()).append("</td>\n");
this.out.append(" </tr>\n");
this.out.append("</table>\n");
}
private void printExceptionReport() throws Exception {
this.out.append("<table border='1' width='100%'>\n");
this.out.append(" <tr>\n");
boolean first = true;
for (Entry<Long, List<String>> entry : this.exceptions.entrySet()) {
Long id = entry.getKey();
List<String> causes = entry.getValue();
for (String cause : entry.getValue()) {
if (first) {
this.out.append(" <td rowspan='")
.append(Integer.toString(causes.size())).append("'>\n");
this.out.append(id.toString());
this.out.append(" </td>");
this.out.append(" <td>");
this.out.append(cause);
this.out.append(" </td>");
this.out.append(" </tr>");
} else {
this.out.append(" <tr>");
this.out.append(" <td>");
this.out.append(cause);
this.out.append(" </td>");
}
}
}
this.out.append(" </tr>\n");
this.out.append("</table>");
}
private void storeNoSuggestionRule(Rule rule) {
if (rule.getSuggestion().isEmpty()) {
this.noSuggestions.add(rule);
}
}
private void logException(Long ruleId, String incorrectExample) {
// Stores the sentence that generated the exception.
if (this.exceptions.get(ruleId) == null) {
List<String> cause = new ArrayList<String>();
cause.add(incorrectExample);
this.exceptions.put(ruleId, cause);
} else {
this.exceptions.get(ruleId).add(incorrectExample);
}
}
private String escapeHtmlSpaces(String string) {
String escaped = string;
escaped = escaped.replaceAll(" ", " ");
return escaped;
}
private String escapeHtmlChars(String string) {
String escaped = string;
escaped = escaped.replaceAll("\\\"", """);
escaped = escaped.replaceAll("<", "<");
escaped = escaped.replaceAll(">", ">");
return escaped;
}
private String newLineToBr(String string) {
return string.replaceAll("\\n", "<br/>");
}
public static void main(String[] args) throws Exception {
MultiCogrooHtml testCogrooHtml = new MultiCogrooHtml();
testCogrooHtml.test();
}
}