001/*
002 * Copyright (c) 2012, the Last.fm Java Project and Committers
003 * All rights reserved.
004 *
005 * Redistribution and use of this software in source and binary forms, with or without modification, are
006 * permitted provided that the following conditions are met:
007 *
008 * - Redistributions of source code must retain the above
009 *   copyright notice, this list of conditions and the
010 *   following disclaimer.
011 *
012 * - Redistributions in binary form must reproduce the above
013 *   copyright notice, this list of conditions and the
014 *   following disclaimer in the documentation and/or other
015 *   materials provided with the distribution.
016 *
017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
018 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
019 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
020 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
021 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
023 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
024 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
025 */
026
027package de.umass.lastfm;
028
029import java.text.DateFormat;
030import java.text.ParseException;
031import java.text.SimpleDateFormat;
032import java.util.*;
033
034import de.umass.util.MapUtilities;
035import de.umass.xml.DomElement;
036
037/**
038 * Bean for Events.
039 *
040 * @author Janni Kovacs
041 */
042public class Event extends ImageHolder {
043
044        static final ItemFactory<Event> FACTORY = new EventFactory();
045
046        private static final DateFormat DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss", Locale.ENGLISH);
047
048        private int id;
049        private String title;
050        private Collection<String> artists;
051        private String headliner;
052        private Collection<TicketSupplier> tickets;
053
054        private Date startDate;
055        private Date endDate;
056
057        private String description;
058        private String url;
059        private String website;
060        private int attendance;
061        private int reviews;
062
063        private Venue venue;
064        private AttendanceStatus userAttendanceStatus;
065
066        private Event() {
067        }
068
069        public Collection<String> getArtists() {
070                return artists;
071        }
072
073        public int getAttendance() {
074                return attendance;
075        }
076
077        public String getDescription() {
078                return description;
079        }
080
081        public String getHeadliner() {
082                return headliner;
083        }
084
085        public int getId() {
086                return id;
087        }
088
089        public int getReviews() {
090                return reviews;
091        }
092
093        /**
094         * Returns the start date and time of this event. Note that the time might not be correct, but instead a random time, if not set to a
095         * proper value on last.fm (happens often).
096         *
097         * @return start date
098         */
099        public Date getStartDate() {
100                return startDate;
101        }
102
103        /**
104         * Returns the event's end date, or <code>null</code> if not available. End dates are only supplied for events such as festivals, which
105         * last longer than one day.
106         *
107         * @return end date
108         */
109        public Date getEndDate() {
110                return endDate;
111        }
112
113        public String getTitle() {
114                return title;
115        }
116
117        /**
118         * Returns the last.fm event url, i.e. https://www.last.fm/event/event-id
119         *
120         * @return last.fm url
121         */
122        public String getUrl() {
123                return url;
124        }
125
126        /**
127         * Returns the event website url, if available.
128         *
129         * @return event website url
130         */
131        public String getWebsite() {
132                return website;
133        }
134
135        public Collection<TicketSupplier> getTicketSuppliers() {
136                return tickets;
137        }
138
139        public Venue getVenue() {
140                return venue;
141        }
142
143        public AttendanceStatus getAttendanceStatus() {
144                return this.userAttendanceStatus;
145        }
146
147        /**
148         * Get the metadata for an event on Last.fm. Includes attendance and lineup information.
149         *
150         * @param eventId The numeric last.fm event id
151         * @param apiKey A Last.fm API key.
152         * @return Event metadata
153         */
154        public static Event getInfo(String eventId, String apiKey) {
155                Result result = Caller.getInstance().call("event.getInfo", apiKey, "event", eventId);
156                return ResponseBuilder.buildItem(result, Event.class);
157        }
158
159        /**
160         * Set a user's attendance status for an event.
161         *
162         * @param eventId The numeric last.fm event id
163         * @param status The attendance status
164         * @param session A Session instance
165         * @return the Result of the operation.
166         * @see de.umass.lastfm.Event.AttendanceStatus
167         * @see de.umass.lastfm.Authenticator
168         */
169        public static Result attend(String eventId, AttendanceStatus status, Session session) {
170                return Caller.getInstance().call("event.attend", session, "event", eventId, "status", String.valueOf(status.getId()));
171        }
172
173        /**
174         * Share an event with one or more Last.fm users or other friends.
175         *
176         * @param eventId An event ID
177         * @param recipients A comma delimited list of email addresses or Last.fm usernames. Maximum is 10.
178         * @param message An optional message to send with the recommendation.
179         * @param session A Session instance
180         * @return the Result of the operation
181         */
182        public static Result share(String eventId, String recipients, String message, Session session) {
183                return Caller.getInstance().call("event.share", session, "event", eventId, "recipient", recipients, "message", message);
184        }
185
186        /**
187         * Get a list of attendees for an event.
188         *
189         * @param eventId The numeric last.fm event id
190         * @param apiKey A Last.fm API key
191         * @return a list of users who attended the given event
192         */
193        public static Collection<User> getAttendees(String eventId, String apiKey) {
194                Result result = Caller.getInstance().call("event.getAttendees", apiKey, "event", eventId);
195                return ResponseBuilder.buildCollection(result, User.class);
196        }
197
198        /**
199         * Get shouts for an event.
200         *
201         * @param eventId The numeric last.fm event id
202         * @param apiKey A Last.fm API key.
203         * @return a page of <code>Shout</code>s
204         */
205        public static PaginatedResult<Shout> getShouts(String eventId, String apiKey) {
206                return getShouts(eventId, -1, -1, apiKey);
207        }
208
209        /**
210         * Get shouts for an event.
211         *
212         * @param eventId The numeric last.fm event id
213         * @param page The page number to fetch
214         * @param apiKey A Last.fm API key.
215         * @return a page of <code>Shout</code>s
216         */
217        public static PaginatedResult<Shout> getShouts(String eventId, int page, String apiKey) {
218                return getShouts(eventId, page, -1, apiKey);
219        }
220
221        /**
222         * Get shouts for an event.
223         *
224         * @param eventId The numeric last.fm event id
225         * @param page The page number to fetch
226         * @param limit An integer used to limit the number of shouts returned per page or -1 for default
227         * @param apiKey A Last.fm API key.
228         * @return a page of <code>Shout</code>s
229         */
230        public static PaginatedResult<Shout> getShouts(String eventId, int page, int limit, String apiKey) {
231                Map<String, String> params = new HashMap<String, String>();
232                params.put("event", eventId);
233                MapUtilities.nullSafePut(params, "limit", limit);
234                MapUtilities.nullSafePut(params, "page", page);
235                Result result = Caller.getInstance().call("event.getShouts", apiKey, params);
236                return ResponseBuilder.buildPaginatedResult(result, Shout.class);
237        }
238
239        /**
240         * Enumeration for the attendance status parameter of the <code>attend</code> operation.
241         */
242        public static enum AttendanceStatus {
243
244                ATTENDING(0),
245                MAYBE_ATTENDING(1),
246                NOT_ATTENDING(2);
247
248                private int id;
249
250                private AttendanceStatus(int id) {
251                        this.id = id;
252                }
253
254                public int getId() {
255                        return id;
256                }
257
258                public static AttendanceStatus getByID(int statusId) {
259                        for (AttendanceStatus status : AttendanceStatus.values()) {
260                                if(status.id == statusId)
261                                        return status;
262                        }
263                        return null;
264                }
265        }
266
267        public static class TicketSupplier {
268                private String name;
269                private String website;
270
271                public TicketSupplier(String name, String website) {
272                        this.name = name;
273                        this.website = website;
274                }
275
276                public String getName() {
277                        return name;
278                }
279
280                public String getWebsite() {
281                        return website;
282                }
283        }
284
285        private static class EventFactory implements ItemFactory<Event> {
286                public Event createItemFromElement(DomElement element) {
287//                      if (element == null)
288//                              return null;
289                        Event event = new Event();
290                        ImageHolder.loadImages(event, element);
291                        event.id = Integer.parseInt(element.getChildText("id"));
292                        event.title = element.getChildText("title");
293                        event.description = element.getChildText("description");
294                        event.url = element.getChildText("url");
295                        if (element.hasChild("attendance"))
296                                event.attendance = Integer.parseInt(element.getChildText("attendance"));
297                        if (element.hasChild("reviews"))
298                                event.reviews = Integer.parseInt(element.getChildText("reviews"));
299                        try {
300                                event.startDate = DATE_FORMAT.parse(element.getChildText("startDate"));
301                                if (element.hasChild("endDate")) {
302                                        event.endDate = DATE_FORMAT.parse(element.getChildText("endDate"));
303                                }
304                        } catch (ParseException e1) {
305                                // Date format not valid !?, should definitely not happen.
306                        }
307                        event.headliner = element.getChild("artists").getChildText("headliner");
308                        event.artists = new ArrayList<String>();
309                        for (DomElement artist : element.getChild("artists").getChildren("artist")) {
310                                event.artists.add(artist.getText());
311                        }
312                        event.website = element.getChildText("website");
313                        event.tickets = new ArrayList<TicketSupplier>();
314                        if (element.hasChild("tickets")) {
315                                for (DomElement ticket : element.getChild("tickets").getChildren("ticket")) {
316                                        event.tickets.add(new TicketSupplier(ticket.getAttribute("supplier"), ticket.getText()));
317                                }
318                        }
319                        if(element.hasAttribute("status"))
320                                event.userAttendanceStatus = AttendanceStatus.getByID(Integer.parseInt(element.getAttribute("status")));
321                        if(element.hasChild("venue"))
322                                event.venue = ResponseBuilder.buildItem(element.getChild("venue"), Venue.class);
323                        return event;
324                }
325        }
326}