001// License: GPL. For details, see Readme.txt file.
002package org.openstreetmap.gui.jmapviewer.tilesources;
003
004import java.util.Map;
005import java.util.HashMap;
006import java.util.Random;
007import java.util.regex.Pattern;
008import java.util.regex.Matcher;
009
010public class TemplatedTMSTileSource extends TMSTileSource {
011
012    private Random rand = null;
013    private String[] randomParts = null;
014    private Map<String, String> headers = new HashMap<>();
015
016    public static final String PATTERN_ZOOM    = "\\{(?:(\\d+)-)?z(?:oom)?([+-]\\d+)?\\}";
017    public static final String PATTERN_X       = "\\{x\\}";
018    public static final String PATTERN_Y       = "\\{y\\}";
019    public static final String PATTERN_Y_YAHOO = "\\{!y\\}";
020    public static final String PATTERN_NEG_Y   = "\\{-y\\}";
021    public static final String PATTERN_SWITCH  = "\\{switch:([^}]+)\\}";
022    public static final String PATTERN_HEADER  = "\\{header\\(([^,]+),([^}]+)\\)\\}";
023
024    public static final String[] ALL_PATTERNS = {
025        PATTERN_HEADER, PATTERN_ZOOM, PATTERN_X, PATTERN_Y, PATTERN_Y_YAHOO, PATTERN_NEG_Y,
026        PATTERN_SWITCH
027    };
028
029    public TemplatedTMSTileSource(String name, String url, String id, int maxZoom) {
030        super(name, url, id, maxZoom);
031        handleTemplate();
032    }
033
034    public TemplatedTMSTileSource(String name, String url, String id, int minZoom, int maxZoom) {
035        super(name, url, id, minZoom, maxZoom);
036        handleTemplate();
037    }
038
039    private void handleTemplate() {
040        // Capturing group pattern on switch values
041        Matcher m = Pattern.compile(".*"+PATTERN_SWITCH+".*").matcher(baseUrl);
042        if (m.matches()) {
043            rand = new Random();
044            randomParts = m.group(1).split(",");
045        }
046        Pattern pattern = Pattern.compile(PATTERN_HEADER);
047        StringBuffer output = new StringBuffer();
048        Matcher matcher = pattern.matcher(baseUrl);
049        while (matcher.find()) {
050            headers.put(matcher.group(1),matcher.group(2));
051            matcher.appendReplacement(output, "");
052        }
053        matcher.appendTail(output);
054        baseUrl = output.toString();
055    }
056
057    public Map<String, String> getHeaders() {
058        return headers;
059    }
060
061    @Override
062    public String getTileUrl(int zoom, int tilex, int tiley) {
063        int finalZoom = zoom;
064        Matcher m = Pattern.compile(".*"+PATTERN_ZOOM+".*").matcher(this.baseUrl);
065        if (m.matches()) {
066            if(m.group(1) != null) {
067                finalZoom = Integer.valueOf(m.group(1))-zoom;
068            }
069            if(m.group(2) != null) {
070                String ofs = m.group(2);
071                if(ofs.startsWith("+"))
072                    ofs = ofs.substring(1);
073                finalZoom += Integer.valueOf(ofs);
074            }
075        }
076        String r = this.baseUrl
077            .replaceAll(PATTERN_ZOOM, Integer.toString(finalZoom))
078            .replaceAll(PATTERN_X, Integer.toString(tilex))
079            .replaceAll(PATTERN_Y, Integer.toString(tiley))
080            .replaceAll(PATTERN_Y_YAHOO, Integer.toString((int)Math.pow(2, zoom-1)-1-tiley))
081            .replaceAll(PATTERN_NEG_Y, Integer.toString((int)Math.pow(2, zoom)-1-tiley));
082        if (rand != null) {
083            r = r.replaceAll(PATTERN_SWITCH, randomParts[rand.nextInt(randomParts.length)]);
084        }
085        return r;
086    }
087}