public final class CharacterApiClient extends MarvelApiClient {

  public CharacterApiClient(MarvelApiConfig marvelApiConfig) {
    super(marvelApiConfig);
  }

  public MarvelResponse<CharactersDto> getAll(int offset, int limit) throws MarvelApiException {
    CharactersQuery query =
        CharactersQuery.Builder.create().withOffset(offset).withLimit(limit).build();
    return getAll(query);
  }

  public MarvelResponse<CharactersDto> getAll(CharactersQuery charactersQuery)
      throws MarvelApiException {
    CharacterApiRest api = getApi(CharacterApiRest.class);

    Map<String, Object> queryAsMap = charactersQuery.toMap();
    Call<MarvelResponse<CharactersDto>> call = api.getCharacters(queryAsMap);
    return execute(call);
  }

  public MarvelResponse<CharacterDto> getCharacter(String characterId) throws MarvelApiException {
    if (characterId == null || characterId.isEmpty()) {
      throw new IllegalArgumentException("The CharacterId must not be null or empty");
    }
    CharacterApiRest api = getApi(CharacterApiRest.class);

    Call<MarvelResponse<CharactersDto>> call = api.getCharacter(characterId);
    MarvelResponse<CharactersDto> characters = execute(call);
    CharactersDto charactersDto = characters.getResponse();
    if (charactersDto != null && charactersDto.getCount() > 0) {
      CharacterDto characterDto = charactersDto.getCharacters().get(0);
      MarvelResponse<CharacterDto> characterResponse = new MarvelResponse<>(characters);
      characterResponse.setResponse(characterDto);
      return characterResponse;
    } else {
      throw new MarvelApiException("Character not found", null);
    }
  }
} public final class ComicApiClient extends MarvelApiClient {

  public ComicApiClient(MarvelApiConfig marvelApiConfig) {
    super(marvelApiConfig);
  }

  public MarvelResponse<ComicsDto> getAll(int offset, int limit) throws MarvelApiException {
    ComicsQuery query = ComicsQuery.Builder.create().withOffset(offset).withLimit(limit).build();
    return getAll(query);
  }

  public MarvelResponse<ComicsDto> getAll(ComicsQuery comicsQuery) throws MarvelApiException {
    ComicApiRest api = getApi(ComicApiRest.class);

    Map<String, Object> queryAsMap = comicsQuery.toMap();
    Call<MarvelResponse<ComicsDto>> call = api.getComics(queryAsMap);
    return execute(call);
  }

  public MarvelResponse<ComicDto> getComic(String comicId) throws MarvelApiException {
    if (comicId == null || comicId.isEmpty()) {
      throw new IllegalArgumentException("The ComicId must not be null or empty");
    }
    ComicApiRest api = getApi(ComicApiRest.class);

    Call<MarvelResponse<ComicsDto>> call = api.getComic(comicId);
    MarvelResponse<ComicsDto> comics = execute(call);
    ComicsDto comicsDto = comics.getResponse();
    if (comicsDto != null && comicsDto.getCount() > 0) {
      ComicDto comicDto = comicsDto.getComics().get(0);
      MarvelResponse<ComicDto> comicResponse = new MarvelResponse<>(comics);
      comicResponse.setResponse(comicDto);
      return comicResponse;
    } else {
      throw new MarvelApiException("Comic not found", null);
    }
  }
} public class MarvelApiConfig {

  private static MarvelApiConfig singleton;
  private final String publicKey;
  private final String privateKey;
  private final boolean debug;
  private final Retrofit retrofit;

  MarvelApiConfig(String publicKey, String privateKey, Retrofit retrofit, boolean debug) {
    this.publicKey = publicKey;
    this.privateKey = privateKey;
    this.retrofit = retrofit;
    this.debug = debug;
  }

  public static MarvelApiConfig with(String publicKey, String privateKey) {
    if (singleton == null) {
      singleton = new Builder(publicKey, privateKey).build();
    }
    return singleton;
  }

  public Retrofit getRetrofit() {
    return retrofit;
  }

  /**
   * Fluent API for creating {@link MarvelApiConfig} instances.
   */
  @SuppressWarnings("UnusedDeclaration") public static class Builder {

    private static final String MARVEL_API_BASE_URL = "https://gateway.marvel.com/v1/public/";
    private final String privateKey;
    private final String publicKey;
    private boolean debug;
    private Retrofit retrofit;
    private String baseUrl = MARVEL_API_BASE_URL;
    private TimeProvider timeProvider = new TimeProvider();

    public Builder(String publicKey, String privateKey) {
      if (publicKey == null) {
        throw new IllegalArgumentException("publicKey must not be null.");
      }

      if (privateKey == null) {
        throw new IllegalArgumentException("privateKey must not be null.");
      }

      this.publicKey = publicKey;
      this.privateKey = privateKey;
    }

    public Builder debug() {
      this.debug = true;
      return this;
    }

    public Builder baseUrl(String url) {
      this.baseUrl = url;
      return this;
    }

    public Builder retrofit(Retrofit retrofit) {
      if (retrofit == null) {
        throw new IllegalArgumentException("retrofit must not be null.");
      }
      this.retrofit = retrofit;
      return this;
    }

    public MarvelApiConfig build() {
      if (retrofit == null) {
        retrofit = buildRetrofit();
      }

      return new MarvelApiConfig(publicKey, privateKey, retrofit, debug);
    }

    private Retrofit buildRetrofit() {
      OkHttpClient.Builder builder = new OkHttpClient.Builder()
        .addInterceptor(new AuthInterceptor(publicKey, privateKey, timeProvider));
      if (debug) {
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        builder.addInterceptor(interceptor);
      }

      OkHttpClient client = builder.build();
      
      return new Retrofit.Builder().baseUrl(baseUrl)
          .client(client)
          .addConverterFactory(GsonConverterFactory.create())
          .build();
    }
  }
} public class MarvelApiException extends Exception {
  private final int httpCode;
  private final String marvelCode;

  public MarvelApiException(int httpCode, String marvelCode, String description, Throwable cause) {
    super(description, cause);
    this.httpCode = httpCode;
    this.marvelCode = marvelCode;
  }

  public MarvelApiException(String message, Throwable cause) {
    this(-1, "", message, cause);
  }

  public int getHttpCode() {
    return httpCode;
  }

  public String getMarvelCode() {
    return marvelCode;
  }
} public final class SeriesApiClient extends MarvelApiClient {

  public SeriesApiClient(MarvelApiConfig marvelApiConfig) {
    super(marvelApiConfig);
  }

  public MarvelResponse<SeriesCollectionDto> getAll(int offset, int limit)
      throws MarvelApiException {
    SeriesQuery query = SeriesQuery.Builder.create().withOffset(offset).withLimit(limit).build();
    return getAll(query);
  }

  public MarvelResponse<SeriesCollectionDto> getAll(SeriesQuery seriesQuery)
      throws MarvelApiException {
    SeriesApiRest api = getApi(SeriesApiRest.class);

    Map<String, Object> queryAsMap = seriesQuery.toMap();
    Call<MarvelResponse<SeriesCollectionDto>> call = api.getSeries(queryAsMap);
    return execute(call);
  }

  public MarvelResponse<SeriesDto> getSeriesById(String seriesId) throws MarvelApiException {
    if (seriesId == null || seriesId.isEmpty()) {
      throw new IllegalArgumentException("The seriesId must not be null or empty");
    }
    SeriesApiRest api = getApi(SeriesApiRest.class);

    Call<MarvelResponse<SeriesCollectionDto>> call = api.getSerie(seriesId);
    MarvelResponse<SeriesCollectionDto> series = execute(call);
    SeriesCollectionDto seriesCollectionDto = series.getResponse();
    if (seriesCollectionDto != null && seriesCollectionDto.getCount() > 0) {
      SeriesDto seriesDto = seriesCollectionDto.getSeries().get(0);
      MarvelResponse<SeriesDto> serieResponse = new MarvelResponse<>(series);
      serieResponse.setResponse(seriesDto);
      return serieResponse;
    } else {
      throw new MarvelApiException("Series not found", null);
    }
  }

  public MarvelResponse<ComicsDto> getComicsBySeries(String seriesId, int offset, int limit)
      throws MarvelApiException {
    ComicsQuery query = ComicsQuery.Builder.create().withOffset(offset).withLimit(limit).build();
    return getComicsBySeries(seriesId, query);
  }

  public MarvelResponse<ComicsDto> getComicsBySeries(String seriesId, ComicsQuery comicsQuery)
      throws MarvelApiException {
    if (seriesId == null || seriesId.isEmpty()) {
      throw new IllegalArgumentException("The seriesId must not be null or empty");
    }
    SeriesApiRest api = getApi(SeriesApiRest.class);

    Map<String, Object> queryMap = comicsQuery.toMap();
    Call<MarvelResponse<ComicsDto>> call = api.getComicsBySerie(seriesId, queryMap);

    return execute(call);
  }
} public class CharacterDto {

  @SerializedName("id") private String id;
  @SerializedName("name") private String name;
  @SerializedName("description") private String description;
  @SerializedName("modified") private String modified;
  @SerializedName("resourceURI") private String resourceUri;
  @SerializedName("urls") private List<MarvelUrl> urls;
  @SerializedName("thumbnail") private MarvelImage thumbnail;
  @SerializedName("comics") private MarvelResources<ComicResourceDto> comics;
  @SerializedName("stories") private MarvelResources<StoryResourceDto> stories;
  @SerializedName("events") private MarvelResources<EventResourceDto> events;
  @SerializedName("series") private MarvelResources<SerieResourceDto> series;

  public String getId() {
    return id;
  }

  public String getName() {
    return name;
  }

  public String getDescription() {
    return description;
  }

  public String getModified() {
    return modified;
  }

  public String getResourceUri() {
    return resourceUri;
  }

  public List<MarvelUrl> getUrls() {
    return urls;
  }

  public MarvelImage getThumbnail() {
    return thumbnail;
  }

  public MarvelResources<ComicResourceDto> getComics() {
    return comics;
  }

  public MarvelResources<StoryResourceDto> getStories() {
    return stories;
  }

  public MarvelResources<EventResourceDto> getEvents() {
    return events;
  }

  public MarvelResources<SerieResourceDto> getSeries() {
    return series;
  }

  @Override public String toString() {
    return "CharacterDto{"
           + "id='"
           + id
           + '\''
           + ", name='"
           + name
           + '\''
           + ", description='"
           + description
           + '\''
           + ", modified='"
           + modified
           + '\''
           + ", resourceUri='"
           + resourceUri
           + '\''
           + ", urls="
           + urls
           + ", thumbnail="
           + thumbnail
           + ", comics="
           + comics
           + ", stories="
           + stories
           + ", events="
           + events
           + ", series="
           + series
           +
           '}';
  }
} public class CharactersDto extends MarvelCollection<CharacterDto> {

  public List<CharacterDto> getCharacters() {
    return getResults();
  }

  @Override public String toString() {
    return "CharactersDto{"
        + "offset="
        + getOffset()
        + ", limit="
        + getLimit()
        + ", total="
        + getTotal()
        + ", count="
        + getCount()
        + ", characters="
        + getCharacters().toString()
        + '}';
  }
} public class CharactersQuery {

  private static final String QUERY_NAME = "name";
  private static final String QUERY_NAME_START_WITH = "nameStartsWith";
  private static final String QUERY_MODIFIED_SINCE = "modifiedSince";
  private static final String QUERY_COMICS = "comics";
  private static final String QUERY_SERIES = "series";
  private static final String QUERY_EVENTS = "events";
  private static final String QUERY_STORIES = "stories";
  private static final String QUERY_ORDER_BY = "orderBy";
  private static final String QUERY_LIMIT = "limit";
  private static final String QUERY_OFFSET = "offset";

  private String name;
  private String nameStartWith;
  private String modifiedSince;
  private String comics;
  private String series;
  private String events;
  private String stories;
  private String orderBy;
  private int limit;
  private int offset;

  private CharactersQuery(String name, String nameStartWith, String modifiedSince, String comics,
      String series, String events, String stories, String orderBy, int limit, int offset) {
    this.name = name;
    this.nameStartWith = nameStartWith;
    this.modifiedSince = modifiedSince;
    this.comics = comics;
    this.series = series;
    this.events = events;
    this.stories = stories;
    this.orderBy = orderBy;
    this.limit = limit;
    this.offset = offset;
  }

  public Map<String, Object> toMap() {
    Map<String, Object> returnValues = new HashMap<>();

    if (name != null) {
      returnValues.put(CharactersQuery.QUERY_NAME, name);
    }

    if (nameStartWith != null) {
      returnValues.put(CharactersQuery.QUERY_NAME_START_WITH, nameStartWith);
    }

    if (modifiedSince != null) {
      returnValues.put(CharactersQuery.QUERY_MODIFIED_SINCE, modifiedSince);
    }

    if (comics != null) {
      returnValues.put(CharactersQuery.QUERY_COMICS, comics);
    }

    if (series != null) {
      returnValues.put(CharactersQuery.QUERY_SERIES, series);
    }

    if (events != null) {
      returnValues.put(CharactersQuery.QUERY_EVENTS, events);
    }

    if (stories != null) {
      returnValues.put(CharactersQuery.QUERY_STORIES, stories);
    }

    if (orderBy != null) {
      returnValues.put(CharactersQuery.QUERY_ORDER_BY, orderBy);
    }

    if (limit > 0) {
      returnValues.put(CharactersQuery.QUERY_LIMIT, limit);
    }

    if (offset > 0) {
      returnValues.put(CharactersQuery.QUERY_OFFSET, offset);
    }

    return returnValues;
  }


  public static class Builder {
    public final static int MAX_SIZE = 100;

    public static final String LIST_SEPARATOR = ",";
    private String name;
    private String nameStartWith;
    private Date modifiedSince;
    private List<Integer> comics = new ArrayList<>();
    private List<Integer> series = new ArrayList<>();
    private List<Integer> events = new ArrayList<>();
    private List<Integer> stories = new ArrayList<>();
    private OrderBy orderBy;
    private boolean orderByAscendant;
    private int limit;
    private int offset;

    private Builder() {
    }

    public static Builder create() {
      return new Builder();
    }

    public Builder withName(String name) {
      this.name = name;
      return this;
    }

    public Builder withNameStartWith(String nameStartWith) {
      this.nameStartWith = nameStartWith;
      return this;
    }

    public Builder withModifiedSince(Date modifiedSince) {
      this.modifiedSince = modifiedSince;
      return this;
    }

    public Builder addComic(int comic) {
      comics.add(comic);
      return this;
    }

    public Builder addComics(List<Integer> comics) {
      checkNull(comics);
      this.comics.addAll(comics);
      return this;
    }

    public Builder addSerie(int serie) {
      series.add(serie);
      return this;
    }

    public Builder addSeries(List<Integer> series) {
      checkNull(series);
      this.series.addAll(series);
      return this;
    }

    public Builder addEvent(int event) {
      events.add(event);
      return this;
    }

    public Builder addEvents(List<Integer> events) {
      checkNull(events);
      this.events.addAll(events);
      return this;
    }

    public Builder addStory(int story) {
      stories.add(story);
      return this;
    }

    public Builder addStory(List<Integer> stories) {
      checkNull(stories);
      this.stories.addAll(stories);
      return this;
    }

    public Builder withOrderBy(OrderBy orderBy, boolean ascendant) {
      this.orderBy = orderBy;
      this.orderByAscendant = ascendant;
      return this;
    }

    public Builder withOrderBy(OrderBy orderBy) {
      this.orderBy = orderBy;
      this.orderByAscendant = true;
      return this;
    }

    public Builder withLimit(int limit) {
      checkLimit(limit);
      this.limit = limit;
      return this;
    }

    public Builder withOffset(int offset) {
      if (offset < 0) {
        throw new IllegalArgumentException("offset must be bigger or equals than zero");
      }

      this.offset = offset;
      return this;
    }

    public CharactersQuery build() {
      String plainModifedSince = convertDate(modifiedSince);
      String plainComics = convertToList(comics);
      String plainEvents = convertToList(events);
      String plainSeries = convertToList(series);
      String plainStories = convertToList(stories);
      String plainOrderBy = convertOrderBy(orderBy, orderByAscendant);

      return new CharactersQuery(name, nameStartWith, plainModifedSince, plainComics, plainSeries,
          plainEvents, plainStories, plainOrderBy, limit, offset);
    }

    private void checkLimit(int limit) {
      if (limit <= 0) {
        throw new IllegalArgumentException("limit must be bigger than zero");
      }

      if (limit > MAX_SIZE) {
        throw new IllegalArgumentException("limit must be smaller than 100");
      }
    }

    private void checkNull(List<Integer> list) {
      if (list == null) {
        throw new IllegalArgumentException("the collection can not be null");
      }
    }

    private String convertDate(Date date) {
      if (date == null) {
        return null;
      }
      return DateUtil.parseDate(date);
    }

    private String convertOrderBy(OrderBy orderBy, boolean ascendant) {
      if (orderBy == null) {
        return null;
      }

      String plainOrderBy = orderBy.toString();
      return (ascendant) ? plainOrderBy : "-" + plainOrderBy;
    }

    private String convertToList(List<Integer> list) {
      String plainList = "";
      for (int i = 0; i < list.size(); i++) {
        plainList += Integer.toString(list.get(i));
        if (i < list.size() - 1) {
          plainList += LIST_SEPARATOR;
        }
      }
      return (plainList.isEmpty()) ? null : plainList;
    }
  }
} public class ComicDto {
  @SerializedName("id") private String id;
  @SerializedName("digitalId") private int digitalId;
  @SerializedName("title") private String title;
  @SerializedName("issueNumber") private double issueNumber;
  @SerializedName("variantDescription") private String variantDescription;
  @SerializedName("description") private String description;
  @SerializedName("modified") private String modified;
  @SerializedName("isbn") private String isbn;
  @SerializedName("upc") private String upc;
  @SerializedName("diamondCode") private String diamondCode;
  @SerializedName("ean") private String ean;
  @SerializedName("issn") private String issn;
  @SerializedName("format") private String format;
  @SerializedName("pageCount") private int pageCount;
  @SerializedName("textObjects") private List<TextObject> textObjects;
  @SerializedName("resourceURI") private String resourceURI;
  @SerializedName("urls") private List<MarvelUrl> urls;
  @SerializedName("series") private ComicResourceDto series;
  @SerializedName("variants") private List<MarvelResourceDto> variants;
  @SerializedName("collections") private List<MarvelCollection> collections;
  @SerializedName("collectedIssues") private List<MarvelCollection> collectedIssues;
  @SerializedName("dates") private List<MarvelDate> dates;
  @SerializedName("prices") private List<MarvelPrice> prices;
  @SerializedName("thumbnail") private MarvelImage thumbnail;
  @SerializedName("images") private List<MarvelImage> images;
  @SerializedName("creators") private MarvelResources<CreatorResourceDto> creators;
  @SerializedName("characters") private MarvelResources<CharacterResourceDto> characters;
  @SerializedName("stories") private MarvelResources<StoryResourceDto> stories;
  @SerializedName("events") private MarvelResources<EventResourceDto> events;

  public String getId() {
    return id;
  }

  public int getDigitalId() {
    return digitalId;
  }

  public String getTitle() {
    return title;
  }

  public double getIssueNumber() {
    return issueNumber;
  }

  public String getVariantDescription() {
    return variantDescription;
  }

  public String getDescription() {
    return description;
  }

  public String getModified() {
    return modified;
  }

  public String getIsbn() {
    return isbn;
  }

  public String getUpc() {
    return upc;
  }

  public String getDiamondCode() {
    return diamondCode;
  }

  public String getEan() {
    return ean;
  }

  public String getIssn() {
    return issn;
  }

  public String getFormat() {
    return format;
  }

  public int getPageCount() {
    return pageCount;
  }

  public List<TextObject> getTextObjects() {
    return textObjects;
  }

  public String getResourceURI() {
    return resourceURI;
  }

  public List<MarvelUrl> getUrls() {
    return urls;
  }

  public ComicResourceDto getSeries() {
    return series;
  }

  public List<MarvelResourceDto> getVariants() {
    return variants;
  }

  public List<MarvelCollection> getCollections() {
    return collections;
  }

  public List<MarvelCollection> getCollectedIssues() {
    return collectedIssues;
  }

  public List<MarvelDate> getDates() {
    return dates;
  }

  public List<MarvelPrice> getPrices() {
    return prices;
  }

  public MarvelImage getThumbnail() {
    return thumbnail;
  }

  public List<MarvelImage> getImages() {
    return images;
  }

  public MarvelResources<CreatorResourceDto> getCreators() {
    return creators;
  }

  public MarvelResources<CharacterResourceDto> getCharacters() {
    return characters;
  }

  public MarvelResources<StoryResourceDto> getStories() {
    return stories;
  }

  public MarvelResources<EventResourceDto> getEvents() {
    return events;
  }

  @Override public String toString() {
    return "ComicDto{" +
        "id='" + id + '\'' +
        ", digitalId=" + digitalId +
        ", title='" + title + '\'' +
        ", issueNumber=" + issueNumber +
        ", variantDescription='" + variantDescription + '\'' +
        ", description='" + description + '\'' +
        ", modified='" + modified + '\'' +
        ", isbn='" + isbn + '\'' +
        ", upc='" + upc + '\'' +
        ", diamondCode='" + diamondCode + '\'' +
        ", ean='" + ean + '\'' +
        ", issn='" + issn + '\'' +
        ", format='" + format + '\'' +
        ", pageCount=" + pageCount +
        ", textObjects=" + textObjects +
        ", resourceURI='" + resourceURI + '\'' +
        ", urls=" + urls +
        ", series=" + series +
        ", variants=" + variants +
        ", collections=" + collections +
        ", collectedIssues=" + collectedIssues +
        ", dates=" + dates +
        ", prices=" + prices +
        ", thumbnail=" + thumbnail +
        ", images=" + images +
        ", creators=" + creators +
        ", characters=" + characters +
        ", stories=" + stories +
        ", events=" + events +
        '}';
  }
} public class ComicsDto extends MarvelCollection<ComicDto> {

  public List<ComicDto> getComics() {
    return getResults();
  }

  @Override public String toString() {
    return "CharactersDto{"
        + "offset="
        + getOffset()
        + ", limit="
        + getLimit()
        + ", total="
        + getTotal()
        + ", count="
        + getCount()
        + ", characters="
        + getComics().toString()
        + '}';
  }
} public class MarvelResponse<T> {
  @SerializedName("code") private int code;
  @SerializedName("status") private String status;
  @SerializedName("copyright") private String copyright;
  @SerializedName("attributionText") private String attributionText;
  @SerializedName("attributionHTML") private String getAttributionHtml;
  @SerializedName("etag") private String etag;

  @SerializedName("data") private T response;

  public MarvelResponse() {
  }

  public MarvelResponse(MarvelResponse marvelResponse) {
    code = marvelResponse.getCode();
    status = marvelResponse.getStatus();
    copyright = marvelResponse.getCopyright();
    attributionText = marvelResponse.getAttributionText();
    getAttributionHtml = marvelResponse.getGetAttributionHtml();
    etag = marvelResponse.getEtag();
  }

  public int getCode() {
    return code;
  }

  public String getStatus() {
    return status;
  }

  public String getCopyright() {
    return copyright;
  }

  public String getAttributionText() {
    return attributionText;
  }

  public String getGetAttributionHtml() {
    return getAttributionHtml;
  }

  public T getResponse() {
    return response;
  }

  public String getEtag() {
    return etag;
  }

  @Override public String toString() {
    return "MarvelResponse{"
           + "code="
           + code
           + ", status='"
           + status
           + '\''
           + ", copyright='"
           + copyright
           + '\''
           + ", attributionText='"
           + attributionText
           + '\''
           + ", getAttributionHtml='"
           + getAttributionHtml
           + '\''
           + ", etag='"
           + etag
           + '\''
           + ", response="
           + response
           + '}';
  }

  public void setResponse(T response) {
    this.response = response;
  }
} public class SeriesDto {
  @SerializedName("id") private String id;
  @SerializedName("title") private String title;
  @SerializedName("description") private String description;
  @SerializedName("resourceURI") private String resourceURI;
  @SerializedName("urls") private List<MarvelUrl> urls;
  @SerializedName("startYear") private int startYear;
  @SerializedName("endYear") private int endYear;
  @SerializedName("rating") private String rating;
  @SerializedName("modified") private String modified;
  @SerializedName("thumbnail") private MarvelImage thumbnail;
  @SerializedName("comics") private MarvelResources<ComicResourceDto> comics;
  @SerializedName("stories") private MarvelResources<StoryResourceDto> stories;
  @SerializedName("events") private MarvelResources<EventResourceDto> events;
  @SerializedName("characters") private MarvelResources<CharacterResourceDto> characters;
  @SerializedName("creators") private MarvelResources<CreatorResourceDto> creators;
  @SerializedName("next") private MarvelResourceDto next;
  @SerializedName("previous") private MarvelResourceDto previous;

  public String getId() {
    return id;
  }

  public String getTitle() {
    return title;
  }

  public String getDescription() {
    return description;
  }

  public String getResourceURI() {
    return resourceURI;
  }

  public List<MarvelUrl> getUrls() {
    return urls;
  }

  public int getStartYear() {
    return startYear;
  }

  public int getEndYear() {
    return endYear;
  }

  public String getRating() {
    return rating;
  }

  public String getModified() {
    return modified;
  }

  public MarvelImage getThumbnail() {
    return thumbnail;
  }

  public MarvelResources<ComicResourceDto> getComics() {
    return comics;
  }

  public MarvelResources<StoryResourceDto> getStories() {
    return stories;
  }

  public MarvelResources<EventResourceDto> getEvents() {
    return events;
  }

  public MarvelResources<CharacterResourceDto> getCharacters() {
    return characters;
  }

  public MarvelResources<CreatorResourceDto> getCreators() {
    return creators;
  }

  public MarvelResourceDto getNext() {
    return next;
  }

  public MarvelResourceDto getPrevious() {
    return previous;
  }

  @Override public String toString() {
    return "SeriesDto{" +
        "id='" + id + '\'' +
        ", title='" + title + '\'' +
        ", description='" + description + '\'' +
        ", resourceURI='" + resourceURI + '\'' +
        ", urls=" + urls +
        ", startYear=" + startYear +
        ", endYear=" + endYear +
        ", rating='" + rating + '\'' +
        ", modified='" + modified + '\'' +
        ", thumbnail=" + thumbnail +
        ", comics=" + comics +
        ", stories=" + stories +
        ", events=" + events +
        ", characters=" + characters +
        ", creators=" + creators +
        ", next=" + next +
        ", previous=" + previous +
        '}';
  }
} public class SeriesCollectionDto extends MarvelCollection<SeriesDto> {

  public List<SeriesDto> getSeries() {
    return getResults();
  }

  @Override public String toString() {
    return "CharactersDto{"
        + "offset="
        + getOffset()
        + ", limit="
        + getLimit()
        + ", total="
        + getTotal()
        + ", count="
        + getCount()
        + ", characters="
        + getSeries().toString()
        + '}';
  }
}
import com.karumi.marvelapiclient.CharacterApiClient;
import com.karumi.marvelapiclient.ComicApiClient;
import com.karumi.marvelapiclient.MarvelApiConfig;
import com.karumi.marvelapiclient.MarvelApiException;
import com.karumi.marvelapiclient.SeriesApiClient;
import com.karumi.marvelapiclient.model.CharacterDto;
import com.karumi.marvelapiclient.model.CharactersDto;
import com.karumi.marvelapiclient.model.CharactersQuery;
import com.karumi.marvelapiclient.model.ComicDto;
import com.karumi.marvelapiclient.model.ComicsDto;
import com.karumi.marvelapiclient.model.MarvelResponse;
import com.karumi.marvelapiclient.model.SeriesDto;
import com.karumi.marvelapiclient.model.SeriesCollectionDto;
/*
 *   Copyright (C) 2015 Karumi.
 *   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 com.karumi.marvelapiclient.sample;


public class MarveApiClientDemo {
  public static void main(String[] args) {
    if (args.length < 3) {
      System.out.println("MarveApiClientDemo [publicKey] [privateKey] [operation]");
    }
    String publicKey = args[0];
    String privateKey = args[1];
    String operation = args[2];

    MarvelApiConfig marvelApiConfig =
        new MarvelApiConfig.Builder(publicKey, privateKey).debug().build();

    try {
      if (operation.equals("getCharacters")) {
        CharacterApiClient characterApiClient = new CharacterApiClient(marvelApiConfig);
        CharactersQuery spider =
            CharactersQuery.Builder.create().withOffset(0).withLimit(10).build();
        MarvelResponse<CharactersDto> all = characterApiClient.getAll(spider);
        System.out.println(all.toString());
      } else if (operation.equals("getCharacter")) {
        CharacterApiClient characterApiClient = new CharacterApiClient(marvelApiConfig);
        MarvelResponse<CharacterDto> character = characterApiClient.getCharacter("1011334");
        System.out.println(character.toString());
      } else if (operation.equals("getComics")) {
        ComicApiClient comicApiClient = new ComicApiClient(marvelApiConfig);
        MarvelResponse<ComicsDto> comics = comicApiClient.getAll(0, 10);