001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.tools;
003
004import java.io.BufferedReader;
005import java.io.IOException;
006import java.net.URL;
007
008import org.openstreetmap.josm.Main;
009import org.openstreetmap.josm.tools.LanguageInfo.LocaleType;
010
011/**
012 * Read a trac-wiki page.
013 *
014 * @author imi
015 */
016public class WikiReader {
017
018    private final String baseurl;
019
020    /**
021     * Constructs a new {@code WikiReader} for the given base URL.
022     * @param baseurl The wiki base URL
023     */
024    public WikiReader(String baseurl) {
025        this.baseurl = baseurl;
026    }
027
028    /**
029     * Constructs a new {@code WikiReader}.
030     */
031    public WikiReader() {
032        this(Main.pref.get("help.baseurl", Main.getJOSMWebsite()));
033    }
034
035    /**
036     * Returns the base URL of wiki.
037     * @return the base URL of wiki
038     * @since 7434
039     */
040    public final String getBaseUrlWiki() {
041        return baseurl + "/wiki/";
042    }
043
044    /**
045     * Read the page specified by the url and return the content.
046     *
047     * If the url is within the baseurl path, parse it as an trac wikipage and replace relative paths etc..
048     * @param url the URL to read
049     * @return The page as string
050     *
051     * @throws IOException Throws, if the page could not be loaded.
052     */
053    public String read(String url) throws IOException {
054        URL u = new URL(url);
055        try (BufferedReader in = Utils.openURLReader(u)) {
056            boolean txt = url.endsWith("?format=txt");
057            if (url.startsWith(getBaseUrlWiki()) && !txt)
058                return readFromTrac(in, u);
059            return readNormal(in, !txt);
060        }
061    }
062
063    /**
064     * Reads the localized version of the given wiki page.
065     * @param text The page title, without locale prefix
066     * @return the localized version of the given wiki page
067     * @throws IOException if any I/O error occurs
068     */
069    public String readLang(String text) throws IOException {
070        String languageCode;
071        String res = "";
072
073        languageCode = LanguageInfo.getWikiLanguagePrefix(LocaleType.DEFAULTNOTENGLISH);
074        if (languageCode != null) {
075            res = readLang(new URL(getBaseUrlWiki() + languageCode + text));
076        }
077
078        if (res.isEmpty()) {
079            languageCode = LanguageInfo.getWikiLanguagePrefix(LocaleType.BASELANGUAGE);
080            if (languageCode != null) {
081                res = readLang(new URL(getBaseUrlWiki() + languageCode + text));
082            }
083        }
084
085        if (res.isEmpty()) {
086            languageCode = LanguageInfo.getWikiLanguagePrefix(LocaleType.ENGLISH);
087            if (languageCode != null) {
088                res = readLang(new URL(getBaseUrlWiki() + languageCode + text));
089            }
090        }
091
092        if (res.isEmpty()) {
093            throw new IOException(text + " does not exist");
094        } else {
095            return res;
096        }
097    }
098
099    private String readLang(URL url) throws IOException {
100        try (BufferedReader in = Utils.openURLReader(url)) {
101            return readFromTrac(in, url);
102        } catch (IOException e) {
103            Main.addNetworkError(url, Utils.getRootCause(e));
104            throw e;
105        }
106    }
107
108    private static String readNormal(BufferedReader in, boolean html) throws IOException {
109        StringBuilder b = new StringBuilder();
110        for (String line = in.readLine(); line != null; line = in.readLine()) {
111            if (!line.contains("[[TranslatedPages]]")) {
112                b.append(line.replaceAll(" />", ">")).append('\n');
113            }
114        }
115        return html ? "<html>" + b + "</html>" : b.toString();
116    }
117
118    protected String readFromTrac(BufferedReader in, URL url) throws IOException {
119        boolean inside = false;
120        boolean transl = false;
121        boolean skip = false;
122        StringBuilder b = new StringBuilder();
123        StringBuilder full = new StringBuilder();
124        for (String line = in.readLine(); line != null; line = in.readLine()) {
125            full.append(line);
126            if (line.contains("<div id=\"searchable\">")) {
127                inside = true;
128            } else if (line.contains("<div class=\"wiki-toc trac-nav\"")) {
129                transl = true;
130            } else if (line.contains("<div class=\"wikipage searchable\">")) {
131                inside = true;
132            } else if (line.contains("<div class=\"buttons\">")) {
133                inside = false;
134            } else if (line.contains("<h3>Attachments</h3>")) {
135                inside = false;
136            } else if (line.contains("<div id=\"attachments\">")) {
137                inside = false;
138            } else if (line.contains("<div class=\"trac-modifiedby\">")) {
139                skip = true;
140            }
141            if (inside && !transl && !skip) {
142                // add a border="0" attribute to images, otherwise the internal help browser
143                // will render a thick  border around images inside an <a> element
144                // remove width information to avoid distorded images (fix #11262)
145                b.append(line.replaceAll("<img ", "<img border=\"0\" ")
146                         .replaceAll("width=\"(\\d+)\"", "")
147                         .replaceAll("<span class=\"icon\">.</span>", "")
148                         .replaceAll("href=\"/", "href=\"" + baseurl + '/')
149                         .replaceAll(" />", ">"))
150                         .append('\n');
151            } else if (transl && line.contains("</div>")) {
152                transl = false;
153            }
154            if (line.contains("</div>")) {
155                skip = false;
156            }
157        }
158        if (b.indexOf("      Describe ") >= 0
159        || b.indexOf(" does not exist. You can create it here.</p>") >= 0)
160            return "";
161        if (b.length() == 0)
162            b = full;
163        return "<html><base href=\""+url.toExternalForm() +"\"> " + b + "</html>";
164    }
165}