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