public class Token {
    @SerializedName("access_token")
    private String mToken;

    @SerializedName("token_type")
    private String mType;

    @SerializedName("expires_in")
    private int mExpiresTime;

    /**
     * Retrieve the access token.
     *
     * @return the access token that will be used for authentication.
     */
    final public String getToken() {
        return mToken;
    }

    /**
     * Retrieves the type of the token.
     *
     * @return a representation string of the privilege of the current session.
     */
    final public String getType() {
        return mType;
    }

    /**
     * Retrieves the expires time of the token.
     *
     * @return a millisecond representation of the expiration time.
     */
    final public int getExpirationTime() {
        return mExpiresTime;
    }
} @SuppressWarnings("unchecked")
public final class AbstractRequest<T> extends Request<T> {
    private final Gson mReader = new Gson();
    private final Map<String, String> mParameters;
    private final Map<String, String> mHeaders;
    private final Type mType;
    private final String mParent;
    private final Response.Listener<T> mListener;
    private final boolean mJsonBody;

    /**
     * (non-doc)
     */
    public AbstractRequest(Builder<?, T> builder) {
        super(builder.mMethod, "https://" + builder.mHost + ":443" + builder.mPath, builder.mErrorListener);
        this.mType = builder.mType;
        this.mParameters = builder.mParameters;
        this.mHeaders = builder.mHeaders;
        this.mParent = builder.mParent;
        this.mListener = builder.mListener;
        this.mJsonBody = builder.mJsonBody;
        setTag(builder.mIdentifier);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    final public String getBodyContentType() {
        return mJsonBody
                ? "application/json; charset=UTF-8"
                : "application/x-www-form-urlencoded; charset=UTF-8";
    }

    /**
     * {@inheritDoc}
     */
    @Override
    final protected Map<String, String> getParams() {
        return mParameters;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    final public Map<String, String> getHeaders() {
        return mHeaders;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    final protected void deliverResponse(T response) {
        if (mListener != null) {
            mListener.onResponse(response);
        }
    }

    /**
     * {@inheritDoc}
     */
    @Override
    final protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            final String json =
                    new String(response.data, HttpHeaderParser.parseCharset(response.headers));

            final JsonElement element = mParent != null
                    ? mReader.fromJson(json, JsonObject.class).get(mParent)
                    : mReader.fromJson(json, JsonObject.class);
            return Response.success(
                    (T) mReader.fromJson(element, mType), HttpHeaderParser.parseCacheHeaders(response));
        } catch (UnsupportedEncodingException e) {
            return Response.error(new ParseError(e));
        } catch (JsonSyntaxException e) {
            return Response.error(new ParseError(e));
        }
    }

    /**
     * (non-doc)
     */
    public static class Builder<J extends Builder, T> {
        protected final Map<String, String> mParameters = new HashMap<>();
        protected final Map<String, String> mHeaders = new HashMap<>();
        protected final Type mType;
        protected final int mMethod;
        protected String mParent;
        protected String mPath;
        protected String mHost;
        protected Response.ErrorListener mErrorListener;
        protected Response.Listener<T> mListener;
        protected String mIdentifier;
        protected RequestQueue mClient;
        protected boolean mJsonBody;

        /**
         * (non-doc)
         */
        public Builder(Type type) {
            this(type, Method.GET);
        }

        /**
         * (non-doc)
         */
        public Builder(Type type, int method) {
            this(type, method, null);
        }

        /**
         * (non-doc)
         */
        public Builder(Type type, int method, String parent) {
            this.mType = type;
            this.mMethod = method;
            this.mParent = parent;
        }

        /**
         * (non-doc)
         */
        final protected J setJsonBody(boolean isJsonBody) {
            mJsonBody = isJsonBody;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J setClient(RequestQueue client) {
            mClient = client;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J setPath(String path) {
            mPath = path;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J setHost(String host) {
            mHost = host;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J addParameter(String name, String value) {
            mParameters.put(name, value);
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J addHeader(String name, String value) {
            mHeaders.put(name, value);
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J setListener(Response.Listener listener) {
            mListener = listener;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J setErrorListener(Response.ErrorListener listener) {
            mErrorListener = listener;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public J setTag(String tag) {
            mIdentifier = tag;
            return (J) this;
        }

        /**
         * (non-doc)
         */
        final public AbstractRequest<T> build() {
            final AbstractRequest<T> request = new AbstractRequest<>(this);
            mClient.add(request);
            return request;
        }
    }

    /**
     * (non-doc)
     */
    public static class ListType implements ParameterizedType {
        private final Type mType;

        /**
         * Constructor.
         */
        public ListType(Type type) {
            this.mType = type;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Type[] getActualTypeArguments() {
            return new Type[]{mType};
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Type getRawType() {
            return ArrayList.class;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Type getOwnerType() {
            return null;
        }
    }

    /**
     * (non-doc)
     */
    public static class PageType implements ParameterizedType {
        private final Type mType;

        /**
         * Constructor.
         */
        public PageType(Type type) {
            this.mType = type;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Type[] getActualTypeArguments() {
            return new Type[]{mType};
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Type getRawType() {
            return Page.class;
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public Type getOwnerType() {
            return null;
        }
    }
} public final class AlbumListRequest extends AbstractRequest.Builder<AlbumListRequest, List<Album>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Album.class);

    /**
     * (non-doc)
     */
    public AlbumListRequest() {
        super(PARAMETER_TYPE, Request.Method.GET, "albums");
    }

    /**
     * (non-doc)
     */
    public AlbumListRequest setAlbums(String... id) {
        setPath("/v1/albums");
        return addParameter("ids", TextUtils.join(",", id));
    }
} public final class AlbumRequest extends AbstractRequest.Builder<AlbumRequest, Album> {
    /**
     * (non-doc)
     */
    public AlbumRequest() {
        super(Album.class);
    }

    /**
     * (non-doc)
     */
    public AlbumRequest setAlbum(String album) {
        return setPath(String.format(Locale.ENGLISH, "/v1/albums/%s", album));
    }
} public final class AlbumTracksRequest extends AbstractPageRequest<AlbumTracksRequest, SimpleTrack> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimpleTrack.class);

    /**
     * (non-doc)
     */
    public AlbumTracksRequest() {
        super(PARAMETER_TYPE, "tracks");
    }

    /**
     * (non-doc)
     */
    public AlbumTracksRequest setAlbum(String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/albums/%s/tracks", id));
    }
} public final class ArtistAlbumsRequest extends AbstractPageRequest<ArtistAlbumsRequest, SimpleAlbum> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimpleAlbum.class);

    /**
     * (non-doc)
     */
    public ArtistAlbumsRequest() {
        super(PARAMETER_TYPE, "albums");
    }

    /**
     * (non-doc)
     */
    public ArtistAlbumsRequest setArtist(String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/artists/%s/albums", id));
    }

    /**
     * (non-doc)
     */
    public ArtistAlbumsRequest setAlbumType(String... type) {
        return addParameter("album_type", TextUtils.join(",", type));
    }

    /**
     * (non-doc)
     */
    public ArtistAlbumsRequest setMarket(String market) {
        return addParameter("market", market);
    }
} public final class ArtistListRequest extends AbstractRequest.Builder<ArtistListRequest, List<Artist>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Artist.class);

    /**
     * (non-doc)
     */
    public ArtistListRequest() {
        super(PARAMETER_TYPE, Request.Method.GET, "artists");
    }

    /**
     * (non-doc)
     */
    public ArtistListRequest setArtists(String... id) {
        setPath("/v1/artists");
        return addParameter("ids", TextUtils.join(",", id));
    }
} public final class ArtistRelatedRequest extends AbstractRequest.Builder<ArtistRelatedRequest, List<Artist>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Artist.class);

    /**
     * (non-doc)
     */
    public ArtistRelatedRequest() {
        super(PARAMETER_TYPE, Request.Method.GET, "artists");
    }

    /**
     * (non-doc)
     */
    public ArtistRelatedRequest setArtist(String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/artists/%s/related-artists", id));
    }
} public final class ArtistRequest extends AbstractRequest.Builder<ArtistRequest, Artist> {
    /**
     * (non-doc)
     */
    public ArtistRequest() {
        super(Artist.class);
    }

    /**
     * (non-doc)
     */
    public ArtistRequest setArtist(String artist) {
        return setPath(String.format(Locale.ENGLISH, "/v1/artists/%s", artist));
    }
} public final class ArtistTopTrackRequest extends AbstractRequest.Builder<ArtistTopTrackRequest, List<Track>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Track.class);

    /**
     * (non-doc)
     */
    public ArtistTopTrackRequest() {
        super(PARAMETER_TYPE, Request.Method.GET, "tracks");
    }

    /**
     * (non-doc)
     */
    public ArtistTopTrackRequest setArtist(String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/artists/%s/top-tracks", id));
    }

    /**
     * (non-doc)
     */
    public ArtistTopTrackRequest setCountry(String market) {
        return addParameter("country", market);
    }
} public final class AuthoriseClientFlowRequest extends AbstractRequest.Builder<AuthoriseClientFlowRequest, Token> {
    /**
     * (non-doc)
     */
    public AuthoriseClientFlowRequest() {
        super(Token.class, Request.Method.POST, null);
        setPath("/api/token");
    }

    /**
     * (non-doc)
     */
    public AuthoriseClientFlowRequest setAuthorisation(String id, String secret) {
        return addHeader(
                "Authorization",
                "Basic " + Base64.encodeToString((id + ":" + secret).getBytes(), Base64.NO_WRAP));
    }

    /**
     * (non-doc)
     */
    public AuthoriseClientFlowRequest setType(String type) {
        return addParameter("grant_type", type);
    }

    /**
     * (non-doc)
     */
    public AuthoriseClientFlowRequest setScopes(String... scopes) {
        return addParameter("scope", TextUtils.join(" ", scopes));
    }

    /**
     * (non-doc)
     */
    public AuthoriseClientFlowRequest setRedirectUrl(String url) {
        return addParameter("redirect_uri", url);
    }
} public final class AuthoriseRefreshRequest extends AbstractRequest.Builder<AuthoriseRefreshRequest, Token> {
    /**
     * (non-doc)
     */
    public AuthoriseRefreshRequest() {
        super(Token.class, Request.Method.POST, null);
        setPath("/api/token");
        addParameter("grant_type", "authorization_code");
    }

    /**
     * (non-doc)
     */
    public AuthoriseRefreshRequest setAuthorisation(String id, String secret) {
        return addHeader(
                "Authorization",
                "Basic " + Base64.encodeToString((id + ":" + secret).getBytes(), Base64.NO_WRAP));
    }

    /**
     * (non-doc)
     */
    public AuthoriseRefreshRequest setCode(String code) {
        return addParameter("code", code);
    }

    /**
     * (non-doc)
     */
    public AuthoriseRefreshRequest setRedirectUri(String uri) {
        return addParameter("redirect_uri", uri);
    }
} public class PlaylistAddTracksRequest extends AbstractRequest.Builder<PlaylistAddTracksRequest, Snapshot> {
    /**
     * (non-doc)
     */
    public PlaylistAddTracksRequest() {
        super(Snapshot.class, Request.Method.POST);
    }

    /**
     * (non-doc)
     */
    final public PlaylistAddTracksRequest setPlaylist(String user, String playlist) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists/%s/tracks", user, playlist));
    }

    /**
     * (non-doc)
     */
    final public PlaylistAddTracksRequest setTracks(int position, String... ids) {
        addParameter("position", String.valueOf(position));
        return addParameter("uris", TextUtils.join(",", ids));
    }
} public class PlaylistChangeDetailsRequest extends AbstractRequest.Builder<PlaylistChangeDetailsRequest, Void> {
    /**
     * (non-doc)
     */
    public PlaylistChangeDetailsRequest() {
        super(Void.class, Request.Method.PUT);
        setJsonBody(true);
    }

    /**
     * (non-doc)
     */
    final public PlaylistChangeDetailsRequest setPlaylist(String user, String playlist) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists/%s", user, playlist));
    }

    /**
     * (non-doc)
     */
    final public PlaylistChangeDetailsRequest serName(String name) {
        return addParameter("name", name);
    }

    /**
     * (non-doc)
     */
    final public PlaylistChangeDetailsRequest setPublic(boolean isPublic) {
        return addParameter("public", isPublic ? "true" : "false");
    }
} public class PlaylistCreateRequest extends AbstractRequest.Builder<PlaylistCreateRequest, Playlist> {
    /**
     * (non-doc)
     */
    public PlaylistCreateRequest() {
        super(Playlist.class, Request.Method.POST);
        setJsonBody(true);
    }

    /**
     * (non-doc)
     */
    final public PlaylistCreateRequest setUser(String user) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists", user));
    }

    /**
     * (non-doc)
     */
    final public PlaylistCreateRequest serName(String name) {
        return addParameter("name", name);
    }

    /**
     * (non-doc)
     */
    final public PlaylistCreateRequest setPublic(boolean isPublic) {
        return addParameter("public", isPublic ? "true" : "false");
    }
} public final class PlaylistListRequest extends AbstractPageRequest<PlaylistListRequest, SimplePlaylist> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimplePlaylist.class);

    /**
     * (non-doc)
     */
    public PlaylistListRequest() {
        super(PARAMETER_TYPE);
    }

    /**
     * (non-doc)
     */
    final public PlaylistListRequest setUser(String user) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists", user));
    }
} public class PlaylistReplaceTracksRequest extends AbstractRequest.Builder<PlaylistReplaceTracksRequest, Snapshot> {
    /**
     * (non-doc)
     */
    public PlaylistReplaceTracksRequest() {
        super(Snapshot.class, Request.Method.PUT);
    }

    /**
     * (non-doc)
     */
    final public PlaylistReplaceTracksRequest setPlaylist(String user, String playlist) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists/%s/tracks", user, playlist));
    }

    /**
     * (non-doc)
     */
    final public PlaylistReplaceTracksRequest setTracks(String... ids) {
        return addParameter("uris", TextUtils.join(",", ids));
    }
} public final class PlaylistRequest extends AbstractRequest.Builder<PlaylistRequest, Playlist> {
    /**
     * (non-doc)
     */
    public PlaylistRequest() {
        super(Playlist.class);
    }

    /**
     * (non-doc)
     */
    public PlaylistRequest setPlaylist(String user, String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists/%s", user, id));
    }

    /**
     * (non-doc)
     */
    public PlaylistRequest setFields(String field) {
        return addParameter("fields", field);
    }
} public final class PlaylistTrackRequest extends AbstractPageRequest<PlaylistTrackRequest, Playlist.Information> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(Playlist.Information.class);

    /**
     * (non-doc)
     */
    public PlaylistTrackRequest() {
        super(PARAMETER_TYPE);
    }

    /**
     * (non-doc)
     */
    public PlaylistTrackRequest setPlaylist(String user, String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s/playlists/%s/tracks", user, id));
    }

    /**
     * (non-doc)
     */
    public PlaylistTrackRequest setFields(String field) {
        return addParameter("fields", field);
    }
} public final class SearchAlbumRequest extends SearchRequest<SearchAlbumRequest, SimpleAlbum> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimpleAlbum.class);

    /**
     * (non-doc)
     */
    public SearchAlbumRequest() {
        super(PARAMETER_TYPE, "album");
    }
} public final class SearchArtistRequest extends SearchRequest<SearchArtistRequest, Artist> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(Artist.class);

    /**
     * (non-doc)
     */
    public SearchArtistRequest() {
        super(PARAMETER_TYPE, "artist");
    }
} public final class SearchPlaylistRequest extends SearchRequest<SearchPlaylistRequest, SimplePlaylist> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimplePlaylist.class);

    /**
     * (non-doc)
     */
    public SearchPlaylistRequest() {
        super(PARAMETER_TYPE, "playlist");
    }
} public final class SearchTrackRequest extends SearchRequest<SearchTrackRequest, Track> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(Track.class);

    /**
     * (non-doc)
     */
    public SearchTrackRequest() {
        super(PARAMETER_TYPE, "track");
    }
} public final class TrackListRequest extends AbstractRequest.Builder<TrackListRequest, List<Track>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Track.class);

    /**
     * (non-doc)
     */
    public TrackListRequest() {
        super(PARAMETER_TYPE, Request.Method.GET, "tracks");
    }

    /**
     * (non-doc)
     */
    public TrackListRequest setTracks(String... id) {
        setPath("/v1/tracks");
        return addParameter("ids", TextUtils.join(",", id));
    }
} public final class TrackRequest extends AbstractRequest.Builder<TrackRequest, Track> {
    /**
     * (non-doc)
     */
    public TrackRequest() {
        super(Track.class);
    }

    /**
     * (non-doc)
     */
    public TrackRequest setTrack(String track) {
        return setPath(String.format(Locale.ENGLISH, "/v1/track/%s", track));
    }
} public final class BrowseAlbumRequest extends AbstractPageRequest<BrowseAlbumRequest, SimpleAlbum> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimpleAlbum.class);

    /**
     * (non-doc)
     */
    public BrowseAlbumRequest() {
        super(PARAMETER_TYPE, "albums");
        setPath("/v1/browse/new-releases");
    }

    /**
     * (non-doc)
     */
    public BrowseAlbumRequest setMarket(String market) {
        return addParameter("market", market);
    }
} public final class BrowsePlaylistRequest extends AbstractPageRequest<BrowsePlaylistRequest, SimplePlaylist> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(SimplePlaylist.class);

    /**
     * (non-doc)
     */
    public BrowsePlaylistRequest() {
        super(PARAMETER_TYPE, "playlists");
        setPath("/v1/browse/featured-playlists");
    }

    /**
     * (non-doc)
     */
    public BrowsePlaylistRequest setCountry(String country) {
        return addParameter("country", country);
    }

    /**
     * (non-doc)
     */
    public BrowsePlaylistRequest setLocale(String locale) {
        return addParameter("locale", locale);
    }

    /**
     * (non-doc)
     */
    public BrowsePlaylistRequest setTimestamp(String timestamp) {
        return addParameter("timestamp", timestamp);
    }
} public final class FollowAddRequest extends AbstractRequest.Builder<FollowAddRequest, Void> {
    public final static String TYPE_ARTIST = "artist";
    public final static String TYPE_USER = "user";

    /**
     * (non-doc)
     */
    public FollowAddRequest() {
        super(Void.class, Request.Method.PUT);
        setPath("/v1/me/following");
    }

    /**
     * (non-doc)
     */
    public FollowAddRequest setIds(String... ids) {
        return addParameter("ids", TextUtils.join(",", ids));
    }

    /**
     * (non-doc)
     */
    public FollowAddRequest setType(String type) {
        return addParameter("type", type);
    }
} public final class FollowCheckRequest extends AbstractRequest.Builder<FollowCheckRequest, List<Boolean>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Boolean.class);

    public final static String TYPE_ARTIST = "artist";
    public final static String TYPE_USER = "user";

    /**
     * (non-doc)
     */
    public FollowCheckRequest() {
        super(PARAMETER_TYPE);
        setPath("/v1/me/following");
    }

    /**
     * (non-doc)
     */
    public FollowCheckRequest setIds(String... ids) {
        return addParameter("ids", TextUtils.join(",", ids));
    }

    /**
     * (non-doc)
     */
    public FollowCheckRequest setType(String type) {
        return addParameter("type", type);
    }
} public final class FollowRemoveRequest extends AbstractRequest.Builder<FollowRemoveRequest, Void> {
    public final static String TYPE_ARTIST = "artist";
    public final static String TYPE_USER = "user";

    /**
     * (non-doc)
     */
    public FollowRemoveRequest() {
        super(Void.class, Request.Method.DELETE);
        setPath("/v1/me/following");
    }

    /**
     * (non-doc)
     */
    public FollowRemoveRequest setIds(String... ids) {
        return addParameter("ids", TextUtils.join(",", ids));
    }

    /**
     * (non-doc)
     */
    public FollowRemoveRequest setType(String type) {
        return addParameter("type", type);
    }
} public final class MusicAddRequest extends AbstractRequest.Builder<MusicAddRequest, Void> {
    /**
     * (non-doc)
     */
    public MusicAddRequest() {
        super(Void.class, Request.Method.PUT, null);
    }

    /**
     * (non-doc)
     */
    public MusicAddRequest setTracks(String... ids) {
        setPath("/v1/me/tracks");
        return addParameter("ids", TextUtils.join(",", ids));
    }
} public final class MusicRemoveRequest extends AbstractRequest.Builder<MusicRemoveRequest, Void> {
    /**
     * (non-doc)
     */
    public MusicRemoveRequest() {
        super(Void.class, Request.Method.DELETE, null);
    }

    /**
     * (non-doc)
     */
    public MusicRemoveRequest setTracks(String... ids) {
        setPath("/v1/me/tracks");
        return addParameter("ids", TextUtils.join(",", ids));
    }
} public final class MusicTrackCheckRequest extends AbstractRequest.Builder<MusicTrackCheckRequest, List<Boolean>> {
    private final static AbstractRequest.ListType PARAMETER_TYPE = new AbstractRequest.ListType(Boolean.class);

    /**
     * (non-doc)
     */
    public MusicTrackCheckRequest() {
        super(PARAMETER_TYPE, Request.Method.GET, null);
    }

    /**
     * (non-doc)
     */
    public MusicTrackCheckRequest setIds(String... ids) {
        setPath("v1/me/tracks/contains");
        return addParameter("ids", TextUtils.join(",", ids));
    }
} public final class MusicTrackRequest extends AbstractPageRequest<MusicTrackRequest, Track> {
    private final static AbstractRequest.PageType PARAMETER_TYPE = new AbstractRequest.PageType(Track.class);

    /**
     * (non-doc)
     */
    public MusicTrackRequest() {
        super(PARAMETER_TYPE, null);
        setPath("/v1/me/tracks");
    }
} public final class UserElseRequest extends AbstractRequest.Builder<UserElseRequest, SimpleUser> {
    /**
     * (non-doc)
     */
    public UserElseRequest() {
        super(SimpleUser.class);
    }

    /**
     * (non-doc)
     */
    public UserElseRequest setUser(String id) {
        return setPath(String.format(Locale.ENGLISH, "/v1/users/%s", id));
    }
} public final class UserRequest extends AbstractRequest.Builder<UserRequest, User> {
    /**
     * (non-doc)
     */
    public UserRequest() {
        super(User.class);
        setPath("/v1/me");
    }
}
import com.android.volley.RequestQueue;
import me.siegenthaler.spotify.webapi.android.model.Token;
import me.siegenthaler.spotify.webapi.android.request.AbstractRequest;
import me.siegenthaler.spotify.webapi.android.request.AlbumListRequest;
import me.siegenthaler.spotify.webapi.android.request.AlbumRequest;
import me.siegenthaler.spotify.webapi.android.request.AlbumTracksRequest;
import me.siegenthaler.spotify.webapi.android.request.ArtistAlbumsRequest;
import me.siegenthaler.spotify.webapi.android.request.ArtistListRequest;
import me.siegenthaler.spotify.webapi.android.request.ArtistRelatedRequest;
import me.siegenthaler.spotify.webapi.android.request.ArtistRequest;
import me.siegenthaler.spotify.webapi.android.request.ArtistTopTrackRequest;
import me.siegenthaler.spotify.webapi.android.request.AuthoriseClientFlowRequest;
import me.siegenthaler.spotify.webapi.android.request.AuthoriseRefreshRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistAddTracksRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistChangeDetailsRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistCreateRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistListRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistReplaceTracksRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistRequest;
import me.siegenthaler.spotify.webapi.android.request.PlaylistTrackRequest;
import me.siegenthaler.spotify.webapi.android.request.SearchAlbumRequest;
import me.siegenthaler.spotify.webapi.android.request.SearchArtistRequest;
import me.siegenthaler.spotify.webapi.android.request.SearchPlaylistRequest;
import me.siegenthaler.spotify.webapi.android.request.SearchTrackRequest;
import me.siegenthaler.spotify.webapi.android.request.TrackListRequest;
import me.siegenthaler.spotify.webapi.android.request.TrackRequest;
import me.siegenthaler.spotify.webapi.android.request.browse.BrowseAlbumRequest;
import me.siegenthaler.spotify.webapi.android.request.browse.BrowsePlaylistRequest;
import me.siegenthaler.spotify.webapi.android.request.follow.FollowAddRequest;
import me.siegenthaler.spotify.webapi.android.request.follow.FollowCheckRequest;
import me.siegenthaler.spotify.webapi.android.request.follow.FollowRemoveRequest;
import me.siegenthaler.spotify.webapi.android.request.music.MusicAddRequest;
import me.siegenthaler.spotify.webapi.android.request.music.MusicRemoveRequest;
import me.siegenthaler.spotify.webapi.android.request.music.MusicTrackCheckRequest;
import me.siegenthaler.spotify.webapi.android.request.music.MusicTrackRequest;
import me.siegenthaler.spotify.webapi.android.request.profile.UserElseRequest;
import me.siegenthaler.spotify.webapi.android.request.profile.UserRequest;
/*
 * Copyright (C) 2014 Siegenthaler Solutions.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package me.siegenthaler.spotify.webapi.android;



/**
 * (non-doc)
 */
public class ClientRestAPI {
    /**
     * Default port of Spotify API calls.
     */
    private static final int DEFAULT_PORT = 443;

    /**
     * Default http scheme of Spotify API calls.
     */
    private static final String DEFAULT_SCHEME = "https";

    /**
     * Default host of Spotify API calls.
     */
    private static final String DEFAULT_HOST = "api.spotify.com";

    /**
     * Default host of Spotify authentication API calls.
     */
    private static final String DEFAULT_AUTHENTICATION_HOST = "accounts.spotify.com";

    private final RequestQueue mRequestQueue;
    private Token mToken = null;

    /**
     * (non-doc)
     */
    public ClientRestAPI(RequestQueue queue) {
        this.mRequestQueue = queue;
    }

    /**
     * (non-doc)
     */
    public RequestQueue getRequestQueue() {
        return mRequestQueue;
    }

    /**
     * (non-doc)
     */
    public void setToken(Token token) {
        mToken = token;
    }

    /**
     * (non-doc)
     */
    public AuthoriseClientFlowRequest authorise(String clientId, String clientSecret) {
        return addAuthenticationHeader(new AuthoriseClientFlowRequest())
                .setAuthorisation(clientId, clientSecret)
                .setType("client_credentials");
    }

    /**
     * (non-doc)
     */
    public AuthoriseRefreshRequest refresh(String clientId, String clientSecret, String code, String redirectUri) {