001/*
002 * flattr4j - A Java library for Flattr
003 *
004 * Copyright (C) 2011 Richard "Shred" Körber
005 *   http://flattr4j.shredzone.org
006 *
007 * This program is free software: you can redistribute it and/or modify
008 * it under the terms of the GNU General Public License / GNU Lesser
009 * General Public License as published by the Free Software Foundation,
010 * either version 3 of the License, or (at your option) any later version.
011 *
012 * Licensed under the Apache License, Version 2.0 (the "License");
013 * you may not use this file except in compliance with the License.
014 *
015 * This program is distributed in the hope that it will be useful,
016 * but WITHOUT ANY WARRANTY; without even the implied warranty of
017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
018 */
019package org.shredzone.flattr4j.web.builder;
020
021import java.io.Serializable;
022import java.net.URL;
023import java.util.Map;
024import java.util.TreeMap;
025
026import org.shredzone.flattr4j.model.AutoSubmission;
027import org.shredzone.flattr4j.model.Thing;
028import org.shredzone.flattr4j.web.BadgeType;
029
030/**
031 * Builds a static Flattr button tag. A static button works without JavaScript, but does
032 * not offer enhanced features like a click counter.
033 * <p>
034 * The builder uses sensible default settings that can be changed by using its methods.
035 * All methods return a reference to the builder itself, so method calls can be
036 * daisy-chained.
037 * <p>
038 * Example:
039 * <code>String button = new StaticButtonBuilder().url(thingUrl).toString();</code>
040 *
041 * @author Richard "Shred" Körber
042 */
043public class StaticButtonBuilder implements Serializable {
044    private static final long serialVersionUID = 3266441765264183202L;
045
046    private String url;
047    private String badgeUrl;
048    private BadgeType type;
049    private String style;
050    private String styleClass;
051    private TreeMap<String, String> attributes = new TreeMap<String, String>();
052
053    /**
054     * Link to the Thing page at Flattr.
055     */
056    public StaticButtonBuilder thing(String url) {
057        this.url = url;
058        return this;
059    }
060
061    /**
062     * Link to the Thing page at Flattr by {@link AutoSubmission}. If the Thing does not
063     * exist yet, it will be created on the first click.
064     */
065    public StaticButtonBuilder thing(AutoSubmission submission) {
066        this.url = submission.toUrl();
067        return this;
068    }
069
070    /**
071     * Link to the Thing page at Flattr.
072     */
073    public StaticButtonBuilder thing(Thing thing) {
074        return thing(thing.getLink());
075    }
076
077    /**
078     * Selects the badge type to be used. Optional, defaults to the default badge.
079     */
080    public StaticButtonBuilder badge(BadgeType type) {
081        this.type = type;
082        return this;
083    }
084
085    /**
086     * A URL to a custom badge image. If this url is given, an invocation of the
087     * {@link #badge(org.shredzone.flattr4j.web.BadgeType)} method is ignored.
088     *
089     * @param url
090     *            Button image URL
091     */
092    public StaticButtonBuilder badgeUrl(String url) {
093        this.badgeUrl = url;
094        return this;
095    }
096
097    /**
098     * A URL to a custom badge image. Convenience method that takes an URL object.
099     */
100    public StaticButtonBuilder badgeUrl(URL url) {
101        return badgeUrl(url.toString());
102    }
103
104    /**
105     * CSS style to be used.
106     */
107    public StaticButtonBuilder style(String style) {
108        this.style = style;
109        return this;
110    }
111
112    /**
113     * CSS class to be used.
114     */
115    public StaticButtonBuilder styleClass(String styleClass) {
116        this.styleClass = styleClass;
117        return this;
118    }
119
120    /**
121     * Adds a custom HTML attribute to the generated link tag. If an attribute has already
122     * been added, its value will be replaced. Attributes are written to the tag in
123     * alphabetical order.
124     * <p>
125     * Attributes are added without further checks. It is your responsibility to take care
126     * for HTML compliance.
127     *
128     * @param attribute
129     *            HTML attribute to be added
130     * @param value
131     *            Value of that attribute. The builder takes care for proper HTML
132     *            escaping.
133     */
134    public StaticButtonBuilder attribute(String attribute, String value) {
135        String check = attribute.trim().toLowerCase();
136        if ("class".equals(check) || "style".equals(check) || "href".equals(check)) {
137            throw new IllegalArgumentException("attribute \"" + check + "\" is reserved");
138        }
139
140        this.attributes.put(attribute, value);
141        return this;
142    }
143
144    /**
145     * Builds a static button tag of the current setup.
146     */
147    @Override
148    public String toString() {
149        if (url == null) {
150            throw new IllegalStateException("thing url is required, but missing");
151        }
152
153        StringBuilder sb = new StringBuilder();
154        sb.append("<a");
155
156        if (styleClass != null) {
157            sb.append(" class=\"").append(escape(styleClass)).append('"');
158        }
159
160        if (style != null) {
161            sb.append(" style=\"").append(escape(style)).append('"');
162        }
163
164        sb.append(" href=\"").append(escape(url)).append('"');
165
166        for (Map.Entry<String, String> entry : attributes.entrySet()) {
167            sb.append(' ').append(entry.getKey()).append("=\"");
168            sb.append(escape(entry.getValue()));
169            sb.append('"');
170        }
171
172        sb.append('>');
173
174        if (badgeUrl != null) {
175            sb.append("<img src=\"").append(escape(badgeUrl)).append('"')
176                            .append(" alt=\"Flattr this\"")
177                            .append(" title=\"Flattr this\"")
178                            .append(" border=\"0\"")
179                            .append(" />");
180
181        } else {
182            BadgeType useType = (type != null ? type : BadgeType.DEFAULT);
183            sb.append("<img src=\"").append(useType.getUrl()).append('"')
184                            .append(" width=\"").append(useType.getWidth()).append('"')
185                            .append(" height=\"").append(useType.getHeight()).append('"')
186                            .append(" alt=\"Flattr this\"")
187                            .append(" title=\"Flattr this\"")
188                            .append(" border=\"0\"")
189                            .append(" />");
190        }
191
192        sb.append("</a>");
193
194        return sb.toString();
195    }
196
197    /**
198     * Escapes a string for use in HTML attributes.
199     *
200     * @param str
201     *            Attribute to be escaped
202     * @return Escaped attribute
203     */
204    private String escape(String str) {
205        return str.replace("&", "&amp;").replace("<", "&lt;").replace("\"", "&quot;");
206    }
207
208}