/*
* 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.net.MalformedURLException;
import java.net.URL;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.wikipediacleaner.api.check.AddTextActionProvider;
import org.wikipediacleaner.api.check.CheckErrorResult;
import org.wikipediacleaner.api.check.CheckLanguageLinkActionProvider;
import org.wikipediacleaner.api.check.CheckErrorResult.ErrorLevel;
import org.wikipediacleaner.api.constants.CWConfigurationError;
import org.wikipediacleaner.api.constants.EnumWikipedia;
import org.wikipediacleaner.api.constants.WPCConfiguration;
import org.wikipediacleaner.api.data.Interwiki;
import org.wikipediacleaner.api.data.Page;
import org.wikipediacleaner.api.data.PageAnalysis;
import org.wikipediacleaner.api.data.PageElementExternalLink;
import org.wikipediacleaner.api.data.PageElementTemplate;
import org.wikipediacleaner.gui.swing.component.MWPane;
import org.wikipediacleaner.i18n.GT;
import org.wikipediacleaner.utils.StringChecker;
import org.wikipediacleaner.utils.StringCheckerUnauthorizedCharacters;
/**
* Algorithm for analyzing error 091 of check wikipedia project.
* Error 091: Interwiki link written as external link
*/
public class CheckErrorAlgorithm091 extends CheckErrorAlgorithmBase {
/**
* String checker for text inputed by user.
*/
private final StringChecker checker;
/**
* Possible global fixes.
*/
private final static String[] globalFixes = new String[] {
GT._("Convert them to internal links"),
};
public CheckErrorAlgorithm091() {
super("Interwiki link written as external link");
checker = new StringCheckerUnauthorizedCharacters("[]\"");
}
/**
* Possible separation characters at the end of the internal link.
*/
private final static String SEPARATION_CHARACTERS = ",.";
/**
* 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) || (analysis.getInternalLinks() == null)) {
return false;
}
// Retrieve configuration
EnumWikipedia wiki = analysis.getWikipedia();
CWConfigurationError error68 = wiki.getCWConfiguration().getErrorConfiguration(68);
List<String> templatesList = null;
if (error68 != null) {
String templatesParam = error68.getSpecificProperty("template", true, false, false, false);
if (templatesParam != null) {
templatesList = WPCConfiguration.convertPropertyToStringList(templatesParam);
}
}
String strOnlyLanguage = getSpecificProperty("only_language", true, false, false);
boolean onlyLanguage = (strOnlyLanguage != null) ? Boolean.valueOf(strOnlyLanguage) : true;
String strOnlyLocal = getSpecificProperty("only_local", true, false, false);
boolean onlyLocal = (strOnlyLocal != null) ? Boolean.valueOf(strOnlyLocal) : true;
String templates = getSpecificProperty("link_templates", true, true, false);
List<String> linkTemplates = null;
if (templates != null) {
linkTemplates = WPCConfiguration.convertPropertyToStringList(templates);
}
// Analyze each external link
boolean result = false;
List<PageElementExternalLink> links = analysis.getExternalLinks();
if (links == null) {
return result;
}
String contents = analysis.getContents();
for (PageElementExternalLink link : links) {
// Check if this is a external link to an other wiki
boolean fullLink = true;
String linkDest = link.getLink();
Interwiki interwiki = getInterwiki(wiki, linkDest);
if (interwiki == null) {
try {
URL url = new URL(linkDest);
String query = url.getQuery();
if ((query != null) && (query.length() > 0)) {
String[] elements = query.split("\\&");
for (String element : elements) {
String[] parts = element.split("\\=");
if ((parts != null) && (parts.length > 1)) {
Interwiki tmp = getInterwiki(wiki, parts[1]);
if (tmp != null) {
interwiki = tmp;
linkDest = parts[1];
fullLink = false;
}
}
}
}
} catch (MalformedURLException e) {
// Nothing to be done
}
}
String article = null;
String articleName = null;
if (interwiki != null) {
article = interwiki.isArticleUrl(linkDest);
if (article != null) {
int questionMark = article.indexOf('?');
if (questionMark < 0) {
articleName = article;
} else {
articleName = article.substring(0, questionMark);
fullLink = false;
}
}
}
if ((interwiki != null) && (article != null) && (articleName != null)) {
// Decide if error should be reported
String prefix = interwiki.getPrefix();
String language = interwiki.getLanguage();
boolean local = interwiki.getLocal();
EnumWikipedia fromWiki = null;
if (prefix != null) {
fromWiki = EnumWikipedia.getWikipedia(prefix);
if (!prefix.equals(fromWiki.getSettings().getCode())) {
fromWiki = null;
}
}
boolean isError = true;
if (isError && (article.length() == 0) && (!local || link.getText() == null)) {
isError = false;
}
if (fromWiki == wiki) {
isError = false;
}
if ((prefix == null) || (prefix.length() == 0)) {
isError = false;
}
if (onlyLanguage && (language == null)) {
isError = false;
}
if (onlyLocal && !local) {
isError = false;
}
// Mark error
if (isError) {
if (errors == null) {
return true;
}
result = true;
int beginIndex = link.getBeginIndex();
int endIndex = link.getEndIndex();
if ((beginIndex > 0) && (contents.charAt(beginIndex - 1) == '[') &&
(endIndex < contents.length()) && (contents.charAt(endIndex) == ']')) {
beginIndex--;
endIndex++;
}
// Compute informations
String text = link.getText();
// Check if link is in template
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();
}
}
}
}
// Check language link
CheckErrorResult errorResult = createCheckErrorResult(
analysis, beginIndex, endIndex,
fullLink ? ErrorLevel.ERROR : ErrorLevel.WARNING);
if ((fromWiki != null) && (articleName.length() >0)) {
errorResult.addPossibleAction(
GT._("Check language links"),
new CheckLanguageLinkActionProvider(
fromWiki, analysis.getWikipedia(),
articleName, text));
}
// Use templates
if ((templatesList != null) &&
(templatesList.size() > 0) &&
(articleName.length() > 0) &&
(language != null)) {
for (String template : templatesList) {
String[] templateArgs = template.split("\\|");
if (templateArgs.length >= 5) {
String templateName = templateArgs[0];
String paramLocalTitle = templateArgs[1];
String paramLang = templateArgs[2];
String paramLangDefaultValue = null;
int equalIndex = paramLang.indexOf('=');
if (equalIndex > 0) {
paramLangDefaultValue = paramLang.substring(equalIndex + 1);
paramLang = paramLang.substring(0, equalIndex);
}
String paramOriginalTitle = templateArgs[3];
String paramText = templateArgs[4];
String textPrefix =
"{{" + templateName + "|" + paramLocalTitle + "=";
StringBuilder textSuffix = new StringBuilder();
if ((prefix != null) && !prefix.equals(paramLangDefaultValue)) {
textSuffix.append('|');
textSuffix.append(paramLang);
textSuffix.append('=');
textSuffix.append(prefix);
}
textSuffix.append('|');
textSuffix.append(paramOriginalTitle);
textSuffix.append('=');
textSuffix.append(articleName);
textSuffix.append('|');
textSuffix.append(paramText);
textSuffix.append('=');
textSuffix.append((text != null) ? text : article);
textSuffix.append("}}");
String question = GT._("What is the title of the page on this wiki ?");
AddTextActionProvider action = null;
if ((text != null) && (!text.equals(article))) {
String[] possibleValues = { null, article, text };
action = new AddTextActionProvider(
textPrefix, textSuffix.toString(), null, question,
possibleValues, false, null, checker);
} else {
action = new AddTextActionProvider(
textPrefix, textSuffix.toString(), null, question,
articleName, checker);
}
errorResult.addPossibleAction(
GT._("Replace using template {0}", "{{" + templateArgs[0] + "}}"),
action);
}
}
}
// Create internal link
if (articleName.length() > 0) {
if (!link.hasSquare() || link.hasSecondSquare()) {
int lastSure = article.length();
while ((lastSure > 0) &&
(SEPARATION_CHARACTERS.indexOf(article.charAt(lastSure - 1)) >= 0)) {
lastSure--;
}
if ((text == null) && (lastSure < article.length())) {
while (lastSure <= article.length()) {
String actualArticle = article.substring(0, lastSure);
errorResult.addReplacement(
"[[:" + prefix + ":" + actualArticle + "|" + actualArticle + "]]" + article.substring(lastSure));
lastSure++;
}
} else {
boolean first = (errorResult.getPossibleActions() == null) || (errorResult.getPossibleActions().isEmpty());
errorResult.addReplacement(
"[[:" + prefix + ":" + article + "|" + (text != null ? text : article) + "]]",
first && fullLink);
}
}
}
errors.add(errorResult);
}
}
}
return result;
}
/**
* @param wiki Current wiki.
* @param link External link.
* @return Interwiki matching the external link if it exists.
*/
private Interwiki getInterwiki(EnumWikipedia wiki, String link) {
Interwiki result = null;
List<Interwiki> interwikis = wiki.getWikiConfiguration().getInterwikis();
if (interwikis != null) {
for (Interwiki interwiki : interwikis) {
String tmp = interwiki.isArticleUrl(link);
if (tmp != null) {
if ((result == null) || (interwiki.getLanguage() != null)) {
result = interwiki;
}
}
}
}
return result;
}
/**
* 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 fix(globalFixes[0], analysis, null);
}
/**
* @return List of possible global fixes.
*/
@Override
public String[] getGlobalFixes() {
return globalFixes;
}
/**
* Fix all the errors in the page.
*
* @param fixName Fix name (extracted from getGlobalFixes()).
* @param analysis Page analysis.
* @param textPane Text pane.
* @return Page contents after fix.
*/
@Override
public String fix(String fixName, PageAnalysis analysis, MWPane textPane) {
return fixUsingAutomaticReplacement(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("link_templates", GT._("Templates using external links"));
parameters.put("only_language", GT._("To report only links to other languages"));
parameters.put("only_local", GT._("To report only links to local wikis"));
return parameters;
}
}