/*
* WPCleaner: A tool to help on Wikipedia maintenance tasks.
* Copyright (C) 2013 Nicolas Vervelle
*
* See README.txt file for licensing information.
*/
package org.wikipediacleaner.api.check.algorithm;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.wikipediacleaner.api.check.AddInternalLinkActionProvider;
import org.wikipediacleaner.api.check.CheckErrorResult;
import org.wikipediacleaner.api.constants.ArticleUrl;
import org.wikipediacleaner.api.constants.EnumWikipedia;
import org.wikipediacleaner.api.constants.WPCConfiguration;
import org.wikipediacleaner.api.data.DataManager;
import org.wikipediacleaner.api.data.MagicWord;
import org.wikipediacleaner.api.data.Namespace;
import org.wikipediacleaner.api.data.Page;
import org.wikipediacleaner.api.data.PageAnalysis;
import org.wikipediacleaner.api.data.PageElementExternalLink;
import org.wikipediacleaner.api.data.PageElementImage;
import org.wikipediacleaner.api.data.PageElementTag;
import org.wikipediacleaner.api.data.PageElementImage.Parameter;
import org.wikipediacleaner.api.data.PageElementInternalLink;
import org.wikipediacleaner.api.data.PageElementTemplate;
import org.wikipediacleaner.api.data.SpecialPage;
import org.wikipediacleaner.i18n.GT;
import org.wikipediacleaner.utils.StringChecker;
import org.wikipediacleaner.utils.StringCheckerUnauthorizedCharacters;
/**
* Algorithm for analyzing error 090 of check wikipedia project.
* Error 090: Internal link written as external link
*/
public class CheckErrorAlgorithm090 extends CheckErrorAlgorithmBase {
/**
* String checker for text inputed by user.
*/
private final StringChecker checker;
public CheckErrorAlgorithm090() {
super("Internal link written as external link");
checker = new StringCheckerUnauthorizedCharacters("[]\"");
}
/**
* Analyze a page to check if errors are present.
*
* @param analysis Page analysis.
* @param errors Errors found in the page.
* @param onlyAutomatic True if analysis could be restricted to errors automatically fixed.
* @return Flag indicating if the error was found.
*/
@Override
public boolean analyze(
PageAnalysis analysis,
Collection<CheckErrorResult> errors, boolean onlyAutomatic) {
if (analysis == null) {
return false;
}
// Analyze each link
boolean result = false;
result |= analyzeExternalLinks(analysis, errors, onlyAutomatic);
result |= analyzeInternalLinks(analysis, errors, onlyAutomatic);
return result;
}
/**
* Analyze external links.
*
* @param analysis Page analysis.
* @param errors Errors found in the page.
* @param onlyAutomatic True if analysis could be restricted to errors automatically fixed.
* @return Flag indicating if the error was found.
*/
private boolean analyzeExternalLinks(
PageAnalysis analysis,
Collection<CheckErrorResult> errors, boolean onlyAutomatic) {
// Configuration
String templates = getSpecificProperty("link_templates", true, true, false);
List<String> linkTemplates = null;
if (templates != null) {
linkTemplates = WPCConfiguration.convertPropertyToStringList(templates);
}
templates = getSpecificProperty("oldid_templates", true, true, false);
List<String[]> oldidTemplates = null;
if (templates != null) {
oldidTemplates = WPCConfiguration.convertPropertyToStringArrayList(templates);
}
templates = getSpecificProperty("history_templates", true, true, false);
List<String[]> historyTemplates = null;
if (templates != null) {
historyTemplates = WPCConfiguration.convertPropertyToStringArrayList(templates);
}
templates = getSpecificProperty("prefix_index_templates", true, true, false);
List<String[]> prefixIndexTemplates = null;
if (templates != null) {
prefixIndexTemplates = WPCConfiguration.convertPropertyToStringArrayList(templates);
}
// Analyze each external link
boolean result = false;
List<PageElementExternalLink> links = analysis.getExternalLinks();
if (links == null) {
return result;
}
EnumWikipedia wiki = analysis.getWikipedia();
for (PageElementExternalLink link : links) {
ArticleUrl articleUrl = ArticleUrl.isArticleUrl(wiki, link.getLink());
if (articleUrl != null) {
int index = link.getBeginIndex();
if ((analysis.getSurroundingTag(PageElementTag.TAG_HTML_CODE, index) != null) ||
(analysis.getSurroundingTag(PageElementTag.TAG_WIKI_SOURCE, index) != null) ||
(analysis.getSurroundingTag(PageElementTag.TAG_WIKI_SYNTAXHIGHLIGHT, index) != null)) {
articleUrl = null;
}
}
if (articleUrl != null) {
if (errors == null) {
return true;
}
result = true;
boolean errorReported = false;
AnalysisInformation info = new AnalysisInformation(
analysis, link, articleUrl, wiki, errors);
// Check if link is in image as a link attribute
if (!errorReported) {
errorReported = checkImageLink(info);
}
// Retrieve information about link
info.computeLinkInformation();
// Check if link is in template
info.computeIsInTemplate(linkTemplates);
// Restrict automatic modifications
info.computeIsAutomatic();
// Check if link is in a timeline tag
if (!errorReported) {
errorReported = checkTimeline(info);
}
// Check if link is in a ref tag
if (!errorReported) {
errorReported = checkRefTag(info);
}
// Check links to special pages
if (!errorReported) {
errorReported = checkSpecialPrefixIndexLink(info, prefixIndexTemplates);
}
// Check special kinds of links
if (!errorReported) {
errorReported = checkOldidLink(info, oldidTemplates);
}
if (!errorReported) {
errorReported = checkHistoryLink(info, historyTemplates);
}
// Link with text
if (!errorReported) {
errorReported = reportLinkWithText(info);
}
// Link without text
if (!errorReported) {
errorReported = reportLinkWithoutText(info);
}
}
}
return result;
}
/**
* Analyze cases of external link in image link attribute.
*
* @param info Analysis information.
* @return True if error has been reported.
*/
private boolean checkImageLink(AnalysisInformation info) {
// Check if link is an image link attribute
int beginIndex = info.link.getBeginIndex();
PageElementImage image = info.analysis.isInImage(beginIndex);
if (image == null) {
return false;
}
Parameter imgParameter = image.getParameter(MagicWord.IMG_LINK);
if (imgParameter == null) {
return false;
}
int beginParam = image.getBeginIndex() + imgParameter.getBeginOffset();
int endParam = image.getBeginIndex() + imgParameter.getEndOffset();
if ((beginParam >= beginIndex) || (endParam <= beginIndex)) {
return false;
}
// Decide if replacement can be automatic
if ((info.articleUrl.getAttributes() != null) ||
(info.articleUrl.getFragment() != null)) {
info.automatic = Boolean.FALSE;
} else if (info.link.hasSquare()) {
info.automatic = Boolean.FALSE;
} else {
String article = info.articleUrl.getTitle();
int colonIndex = article.indexOf(':');
if (colonIndex <= 0) {
info.automatic = Boolean.FALSE;
} else if (!Page.areSameTitle(article.substring(colonIndex + 1), image.getImage())) {
info.automatic = Boolean.FALSE;
} else {
Namespace imageNamespace = info.analysis.getWikiConfiguration().getNamespace(Namespace.IMAGE);
if (!imageNamespace.isPossibleName(article.substring(0, colonIndex).trim())) {
info.automatic = Boolean.FALSE;
}
}
}
// Report error
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, beginParam - 1, endParam);
errorResult.addReplacement("", Boolean.TRUE.equals(info.automatic));
info.errors.add(errorResult);
return true;
}
/**
* Analyze cases of link inside timeline tags.
*
* @param info Analysis information.
* @return True if error has been reported.
*/
private boolean checkTimeline(
AnalysisInformation info) {
PageElementTag timelineTag = info.analysis.getSurroundingTag(
PageElementTag.TAG_WIKI_TIMELINE, info.beginIndex);
if (timelineTag == null) {
return false;
}
info.automatic = Boolean.FALSE;
if (info.isInTemplate) {
return false;
}
boolean timelineOk = true;
int timelineEnd = info.endIndex;
if (info.contents.charAt(timelineEnd) == '\"') {
timelineEnd++;
}
int timelineBegin = info.beginIndex;
if (info.contents.charAt(timelineBegin - 1) == '\"') {
timelineBegin--;
}
while ((timelineBegin > 0) &&
(info.contents.charAt(timelineBegin - 1) == ' ')) {
timelineBegin--;
}
if (info.contents.startsWith("link:", timelineBegin - "link:".length())) {
timelineBegin -= "link:".length();
} else {
timelineOk = false;
}
while ((timelineBegin > 0) &&
(info.contents.charAt(timelineBegin - 1) == ' ')) {
timelineBegin--;
}
String displayedText = null;
if (timelineBegin > 0) {
if (info.contents.charAt(timelineBegin - 1) == '\"') {
timelineBegin--;
int tmpIndex = timelineBegin;
while ((tmpIndex > 0) &&
("\"\n".indexOf(info.contents.charAt(tmpIndex - 1)) < 0)) {
tmpIndex--;
}
if ((tmpIndex > 0) &&
(info.contents.charAt(tmpIndex - 1) == '\"')) {
displayedText = info.contents.substring(tmpIndex, timelineBegin);
}
timelineBegin = tmpIndex - 1;
} else {
int tmpIndex = timelineBegin;
while ((tmpIndex > 0) &&
(" :".indexOf(info.contents.charAt(tmpIndex - 1)) < 0)) {
tmpIndex--;
}
if (tmpIndex > 0) {
displayedText = info.contents.substring(tmpIndex, timelineBegin);
}
timelineBegin = tmpIndex;
}
}
if (displayedText == null) {
timelineOk = false;
}
while ((timelineBegin > 0) &&
(info.contents.charAt(timelineBegin - 1) == ' ')) {
timelineBegin--;
}
if (info.contents.startsWith("text:", timelineBegin - "text:".length())) {
timelineBegin -= "text:".length();
} else {
timelineOk = false;
}
if (timelineOk) {
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, timelineBegin, timelineEnd);
errorResult.addReplacement(
"text:\"" +
PageElementInternalLink.createInternalLink(
info.article, info.articleUrl.getFragment(), displayedText) +
"\"");
info.errors.add(errorResult);
return true;
}
return false;
}
/**
* Analyze cases of links inside ref tags.
*
* @param info Analysis information.
* @return True if error has been reported.
*/
public boolean checkRefTag(AnalysisInformation info) {
PageElementTag refTag = info.analysis.getSurroundingTag(
PageElementTag.TAG_WIKI_REF, info.beginIndex);
if (refTag == null) {
return false;
}
// Determine if the link is the full tag
boolean full = true;
int tmpIndex = info.beginIndex;
while ((tmpIndex > refTag.getValueBeginIndex()) &&
(info.contents.charAt(tmpIndex - 1) == ' ')) {
tmpIndex--;
}
if (tmpIndex > refTag.getValueBeginIndex()) {
full = false;
}
tmpIndex = info.endIndex;
while ((tmpIndex < refTag.getValueEndIndex()) &&
(info.contents.charAt(tmpIndex) == ' ')) {
tmpIndex++;
}
if (tmpIndex < refTag.getValueEndIndex()) {
full = false;
}
if (full) {
info.automatic = Boolean.FALSE;
}
// Check if there's an equivalent link or text before
tmpIndex = refTag.getCompleteBeginIndex();
while ((tmpIndex > 0) &&
(info.contents.charAt(tmpIndex - 1) == ' ')) {
tmpIndex--;
}
if (tmpIndex > 0) {
PageElementInternalLink previousLink = info.analysis.isInInternalLink(tmpIndex - 1);
if ((previousLink != null) &&
Page.areSameTitle(previousLink.getLink(), info.article)) {
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, previousLink.getBeginIndex(), refTag.getCompleteEndIndex());
errorResult.addReplacement(
info.contents.substring(previousLink.getBeginIndex(), previousLink.getEndIndex()));
info.errors.add(errorResult);
return true;
} else if (tmpIndex > info.article.length()) {
String textBefore = info.contents.substring(tmpIndex - info.article.length(), tmpIndex);
if (Page.areSameTitle(info.article, textBefore)) {
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, tmpIndex - info.article.length(), refTag.getCompleteEndIndex());
errorResult.addReplacement(
PageElementInternalLink.createInternalLink(info.article, info.articleUrl.getFragment(), textBefore));
info.errors.add(errorResult);
return true;
}
}
}
return false;
}
/**
* Analyze cases of links with Special:PrefixIndex.
*
* @param info Analysis information.
* @param prefixIndexTemplates Templates that can be used for links with Special:PrefixIndex.
* @return True if error has been reported.
*/
private boolean checkSpecialPrefixIndexLink(
AnalysisInformation info, List<String[]> prefixIndexTemplates) {
// Check if templates are defined
if ((prefixIndexTemplates == null) || (prefixIndexTemplates.size() == 0)) {
return false;
}
// Check if it is Special:PrefixIndex link
int colonIndex = info.article.indexOf(':');
if ((colonIndex <= 0) || (colonIndex >= info.article.length() - 1)) {
return false;
}
String namespace = info.article.substring(0, colonIndex);
Namespace specialNamespace = info.wiki.getWikiConfiguration().getNamespace(Namespace.SPECIAL);
if ((specialNamespace == null) || !specialNamespace.isPossibleName(namespace)) {
return false;
}
String specialPageName = info.article.substring(colonIndex + 1);
SpecialPage specialPrefixIndex = info.wiki.getWikiConfiguration().getSpecialPageByName(SpecialPage.PREFIX_INDEX);
if ((specialPrefixIndex == null) || !specialPrefixIndex.isPossibleAlias(specialPageName)) {
return false;
}
// Retrieve information
String prefix = null;
if (info.articleUrl.getAttributes() != null) {
for (Map.Entry<String, String> attribute : info.articleUrl.getAttributes().entrySet()) {
String key = attribute.getKey();
if ("prefix".equals(key)) {
prefix = attribute.getValue();
while ((prefix.length() > 0) && (prefix.charAt(prefix.length() - 1) == '+')) {
prefix = prefix.substring(0, prefix.length() - 1);
}
} else if ("namespace".equals(key)) {
// Should we check for namespace=0 ?
} else {
return false;
}
}
}
if ((prefix == null) || (prefix.isEmpty())) {
return false;
}
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, info.beginIndex, info.endIndex);
for (String[] prefixIndexTemplate : prefixIndexTemplates) {
if ((prefixIndexTemplate != null) && (prefixIndexTemplate.length > 0)) {
StringBuilder replacement = new StringBuilder();
replacement.append("{{");
replacement.append(prefixIndexTemplate[0]);
replacement.append("|");
String articleParam = null;
if (prefixIndexTemplate.length > 1) {
if ((prefixIndexTemplate[1].length() > 0) && !"1".equals(prefixIndexTemplate[1])) {
articleParam = prefixIndexTemplate[1];
}
}
if ((articleParam != null) || (prefix.contains("="))) {
replacement.append((articleParam != null) ? articleParam : "1");
replacement.append("=");
}
replacement.append(prefix);
replacement.append("|");
String textParam = null;
if (prefixIndexTemplate.length > 2) {
if ((prefixIndexTemplate[2].length() > 0) && !"2".equals(prefixIndexTemplate[2])) {
textParam = prefixIndexTemplate[2];
}
}
if ((textParam != null) ||
((info.text != null) && (info.text.contains("=")))) {
replacement.append((textParam != null) ? textParam : "2");
replacement.append("=");
}
if (info.text != null) {
replacement.append(info.text);
}
replacement.append("}}");
errorResult.addReplacement(replacement.toString());
addBasicReplacement(info, errorResult);
}
}
info.errors.add(errorResult);
return true;
}
/**
* Analyze cases of links with oldid=xxx.
*
* @param info Analysis information.
* @param oldidTemplates Templates that can be used for links with oldid.
* @return True if error has been reported.
*/
private boolean checkOldidLink(
AnalysisInformation info, List<String[]> oldidTemplates) {
// Check if old id templates are defined
if ((oldidTemplates == null) || (oldidTemplates.size() == 0)) {
return false;
}
// Check if it is an old id link
String oldid = null;
if (info.articleUrl.getAttributes() != null) {
for (Map.Entry<String, String> attribute : info.articleUrl.getAttributes().entrySet()) {
String key = attribute.getKey();
if ("oldid".equals(key)) {
oldid = attribute.getValue();
} else {
return false;
}
}
}
if ((oldid == null) || (oldid.isEmpty())) {
return false;
}
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, info.beginIndex, info.endIndex);
for (String[] oldidTemplate : oldidTemplates) {
if ((oldidTemplate != null) && (oldidTemplate.length > 0)) {
StringBuilder replacement = new StringBuilder();
replacement.append("{{");
replacement.append(oldidTemplate[0]);
replacement.append("|");
String articleParam = null;
if (oldidTemplate.length > 1) {
if ((oldidTemplate[1].length() > 0) && !"1".equals(oldidTemplate[1])) {
articleParam = oldidTemplate[1];
}
}
if ((articleParam != null) || (info.article.contains("="))) {
replacement.append((articleParam != null) ? articleParam : "1");
replacement.append("=");
}
replacement.append(info.article);
replacement.append("|");
String oldidParam = null;
if (oldidTemplate.length > 2) {
if ((oldidTemplate[2].length() > 0) && !"2".equals(oldidTemplate[2])) {
oldidParam = oldidTemplate[2];
}
}
if ((oldidParam != null) || (oldid.contains("="))) {
replacement.append((oldidParam != null) ? oldidParam : "2");
replacement.append("=");
}
replacement.append(oldid);
replacement.append("|");
String textParam = null;
if (oldidTemplate.length > 3) {
if ((oldidTemplate[3].length() > 0) && !"3".equals(oldidTemplate[3])) {
textParam = oldidTemplate[3];
}
}
if ((textParam != null) ||
((info.text != null) && (info.text.contains("=")))) {
replacement.append((textParam != null) ? textParam : "3");
replacement.append("=");
}
if (info.text != null) {
replacement.append(info.text);
}
replacement.append("}}");
errorResult.addReplacement(replacement.toString());
addBasicReplacement(info, errorResult);
}
}
info.errors.add(errorResult);
return true;
}
/**
* Analyze cases of links with action=history.
*
* @param info Analysis information.
* @param historyTemplates Templates that can be used for links with action=history.
* @return True if error has been reported.
*/
private boolean checkHistoryLink(
AnalysisInformation info, List<String[]> historyTemplates) {
// Check if history templates are defined
if ((historyTemplates == null) || (historyTemplates.size() == 0)) {
return false;
}
// Check if it is an history link
boolean isHistory = false;
if (info.articleUrl.getAttributes() != null) {
for (Map.Entry<String, String> attribute : info.articleUrl.getAttributes().entrySet()) {
String key = attribute.getKey();
if ("action".equals(key)) {
if (!"history".equals(attribute.getValue())) {
return false;
}
isHistory = true;
} else {
return false;
}
}
}
if (!isHistory) {
return false;
}
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, info.beginIndex, info.endIndex);
for (String[] historyTemplate : historyTemplates) {
if ((historyTemplate != null) && (historyTemplate.length > 0)) {
StringBuilder replacement = new StringBuilder();
replacement.append("{{");
replacement.append(historyTemplate[0]);
replacement.append("|");
String articleParam = null;
if (historyTemplate.length > 1) {
if ((historyTemplate[1].length() > 0) && !"1".equals(historyTemplate[1])) {
articleParam = historyTemplate[1];
}
}
if ((articleParam != null) || (info.article.contains("="))) {
replacement.append((articleParam != null) ? articleParam : "1");
replacement.append("=");
}
replacement.append(info.article);
replacement.append("|");
String textParam = null;
if (historyTemplate.length > 2) {
if ((historyTemplate[2].length() > 0) && !"2".equals(historyTemplate[2])) {
textParam = historyTemplate[2];
}
}
if ((textParam != null) ||
((info.text != null) && (info.text.contains("=")))) {
replacement.append((textParam != null) ? textParam : "3");
replacement.append("=");
}
if (info.text != null) {
replacement.append(info.text);
}
replacement.append("}}");
errorResult.addReplacement(replacement.toString());
addBasicReplacement(info, errorResult);
}
}
info.errors.add(errorResult);
return true;
}
/**
* Basic reporting for a link with text.
*
* @param info Analysis information.
* @return True if error has been reported.
*/
private boolean reportLinkWithText(AnalysisInformation info) {
if (info.text == null) {
return false;
}
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, info.beginIndex, info.endIndex);
addBasicReplacement(info, errorResult);
info.errors.add(errorResult);
return true;
}
/**
* Basic reporting for a link without text.
*
* @param info Analysis information.
* @return True if error has been reported.
*/
private boolean reportLinkWithoutText(AnalysisInformation info) {
if (info.text != null) {
return false;
}
// Link without text but previous text
int tmpIndex = info.beginIndex;
while ((tmpIndex > 0) &&
(info.contents.charAt(tmpIndex - 1) == ' ')) {
tmpIndex--;
}
if (tmpIndex > info.article.length()) {
String textBefore = info.contents.substring(tmpIndex - info.article.length(), tmpIndex);
if (Page.areSameTitle(info.article, textBefore)) {
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, tmpIndex - info.article.length(), info.endIndex);
errorResult.addReplacement(
PageElementInternalLink.createInternalLink(
(info.needColon ? ":" : "") + info.articleUrl.getTitleAndFragment(), textBefore),
info.automatic);
info.errors.add(errorResult);
return true;
}
}
// Link without text
CheckErrorResult errorResult = createCheckErrorResult(
info.analysis, info.beginIndex, info.endIndex);
String question = GT._("What text should be displayed by the link?");
AddInternalLinkActionProvider action = new AddInternalLinkActionProvider(
info.article, info.articleUrl.getFragment(), null, null, null,
question, info.articleUrl.getTitleAndFragment().replaceAll("\\_", " "), checker);
errorResult.addPossibleAction(
GT._("Convert into an internal link"),
action);
info.errors.add(errorResult);
return true;
}
/**
* Add a basic replacement proposal.
*
* @param info Analysis information.
* @param errorResult Error result.
*/
private void addBasicReplacement(
AnalysisInformation info, CheckErrorResult errorResult) {
errorResult.addReplacement(
PageElementInternalLink.createInternalLink(
(info.needColon ? ":" : "") + info.articleUrl.getTitleAndFragment(), info.text),
info.automatic);
if (info.text != null) {
errorResult.addReplacement(info.text);
}
}
/**
* Analyze internal links.
*
* @param analysis Page analysis.
* @param errors Errors found in the page.
* @param onlyAutomatic True if analysis could be restricted to errors automatically fixed.
* @return Flag indicating if the error was found.
*/
private boolean analyzeInternalLinks(
PageAnalysis analysis,
Collection<CheckErrorResult> errors, boolean onlyAutomatic) {
boolean result = false;
List<PageElementInternalLink> links = analysis.getInternalLinks();
if (links == null) {
return result;
}
EnumWikipedia wiki = analysis.getWikipedia();
String host = wiki.getSettings().getHost();
for (PageElementInternalLink link : links) {
String target = link.getLink();
if ((target != null) && (target.length() >= host.length()) &&
Page.areSameTitle(host, target.substring(0, host.length()))) {
if (errors == null) {
return true;
}
result = true;
CheckErrorResult errorResult = createCheckErrorResult(
analysis, link.getBeginIndex(), link.getEndIndex());
errors.add(errorResult);
}
}
return result;
}
/**
* Automatic fixing of all the errors in the page.
*
* @param analysis Page analysis.
* @return Page contents after fix.
*/
@Override
protected String internalAutomaticFix(PageAnalysis analysis) {
return fixUsingAutomaticReplacement(analysis);
}
/**
* Bot fixing of all the errors in the page.
*
* @param analysis Page analysis.
* @return Page contents after fix.
*/
@Override
protected String internalBotFix(PageAnalysis analysis) {
return fixUsingAutomaticBotReplacement(analysis);
}
/**
* @return Map of parameters (Name -> description).
* @see org.wikipediacleaner.api.check.algorithm.CheckErrorAlgorithmBase#getParameters()
*/
@Override
public Map<String, String> getParameters() {
Map<String, String> parameters = super.getParameters();
parameters.put("history_templates", GT._("Templates to be used for linking to the history of an article"));
parameters.put("link_templates", GT._("Templates using external links"));
parameters.put("oldid_templates", GT._("Templates to be used for linking to an old version of an article"));
parameters.put("prefix_index_templates", GT._("Templates to be used instead of Special:PrefixIndex"));
return parameters;
}
/**
* Bean for holding analysis information.
*/
private static class AnalysisInformation {
/** Page analysis */
public final PageAnalysis analysis;
/** Article contents */
public final String contents;
/** External link */
public final PageElementExternalLink link;
/** Information about article URL */
public final ArticleUrl articleUrl;
/** Article title */
public final String article;
/** Wiki */
public final EnumWikipedia wiki;
/** Errors */
public final Collection<CheckErrorResult> errors;
/** Begin index */
public int beginIndex;
/** End index */
public int endIndex;
/** Link text */
public String text;
/** True if replacement can be automatic */
public Boolean automatic;
/** True if internal needs to be prefixed with a colon */
public Boolean needColon;
/** True if link is defined by a template */
public Boolean isInTemplate;
public AnalysisInformation(
PageAnalysis analysis,
PageElementExternalLink link,
ArticleUrl articleUrl,
EnumWikipedia wiki,
Collection<CheckErrorResult> errors) {
this.analysis = analysis;
this.contents = analysis.getContents();
this.link = link;
this.articleUrl = articleUrl;
this.article = articleUrl.getTitle();
this.wiki = wiki;
this.errors = errors;
this.beginIndex = link.getBeginIndex();
this.endIndex = link.getEndIndex();
this.text = link.getText();
this.automatic = Boolean.TRUE;
this.needColon = null;
this.isInTemplate = null;
}
/**
* Compute complementary information about the link
*/
public void computeLinkInformation() {
if (link.hasSquare()) {
if ((beginIndex > 0) && (contents.charAt(beginIndex - 1) == '[') &&
(endIndex < contents.length()) && (contents.charAt(endIndex) == ']')) {
beginIndex--;
endIndex++;
}
}
Page articlePage = DataManager.getPage(
analysis.getWikipedia(), article, null, null, null);
needColon = Boolean.FALSE;
if (articlePage.getNamespace() != null) {
int ns = articlePage.getNamespace().intValue();
if (ns % 2 == 0) {
if ((ns != Namespace.MAIN) &&
(ns != Namespace.USER) &&
(ns != Namespace.HELP) &&
(ns != Namespace.MEDIAWIKI) &&
(ns != Namespace.TEMPLATE) &&
(ns != Namespace.WIKIPEDIA)) {
needColon = Boolean.TRUE;
}
}
}
}
/**
* Compute if link is defined by a template.
*
* @param linkTemplates List of link templates.
*/
public void computeIsInTemplate(List<String> linkTemplates) {
isInTemplate = Boolean.FALSE;
if (linkTemplates != null) {
PageElementTemplate template = analysis.isInTemplate(beginIndex);
if (template != null) {
for (String linkTemplate : linkTemplates) {
String[] elements = linkTemplate.split("\\|");
if ((elements.length > 2) &&
Page.areSameTitle(elements[0], template.getTemplateName()) &&
link.getLink().trim().equals(template.getParameterValue(elements[1]))) {
text = template.getParameterValue(elements[2]);
beginIndex = template.getBeginIndex();
endIndex = template.getEndIndex();
isInTemplate = true;
}
}
}
}
}
/**
* Compute restrictions on automatic replacement.
*/
public void computeIsAutomatic() {
if (Page.areSameTitle(article, analysis.getPage().getTitle())) {
automatic = false;
}
if (articleUrl.getAttributes() != null) {
for (Map.Entry<String, String> attribute : articleUrl.getAttributes().entrySet()) {
String key = attribute.getKey();
if ("venotify".equals(key)) {
if (!"created".equals(attribute.getValue())) {
automatic = false;
}
} else if ("action".equals(key)) {
if (!"edit".equals(attribute.getValue())) {
automatic = false;
}
} else if (!"redlink".equals(key)) {
automatic = false;
}
}
}
}
}
}