public class CharacterResourceDto extends MarvelResourceDto {
} 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 ComicResourceDto extends MarvelResourceDto {
} 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 ComicsQuery {
  private static final String QUERY_FORMAT = "format";
  private static final String QUERY_FORMAT_TYPE = "formatType";
  private static final String QUERY_NO_VARIANTS = "noVariants";
  private static final String QUERY_DATE_DESCRIPTOR = "dateDescriptor";
  private static final String QUERY_DATE_RANGE = "dateRange";
  private static final String QUERY_TITLE = "title";
  private static final String QUERY_TITLE_STARTS_WITH = "titleStartsWith";
  private static final String QUERY_START_YEAR = "startYear";
  private static final String QUERY_ISSUE_NUMBER = "issueNumber";
  private static final String QUERY_DIAMOND_CODE = "diamondCode";
  private static final String QUERY_DIGITAL_ID = "digitalId";
  private static final String QUERY_UPC = "upc";
  private static final String QUERY_ISBN = "isbn";
  private static final String QUERY_EAN = "ean";
  private static final String QUERY_ISSN = "issn";
  private static final String QUERY_HAS_DIGITAL_ISSUE = "hasDigitalIssue";
  private static final String QUERY_MODIFIED_SINCE = "modifiedSince";
  private static final String QUERY_CREATORS = "creators";
  private static final String QUERY_CHARACTERS = "characters";
  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_SHARED_APPEARANCES = "appearances";
  private static final String QUERY_COLLABORATORS = "collaborators";
  private static final String QUERY_ORDER_BY = "orderBy";
  private static final String QUERY_LIMIT = "limit";
  private static final String QUERY_OFFSET = "offset";

  private String format;
  private String formatType;
  private boolean noVariants;
  private String dateDescriptor;
  private String dateRange;
  private String title;
  private String titleStartsWith;
  private int startYear;
  private int issueNumber;
  private String diamondCode;
  private int digitalId;
  private String upc;
  private String isbn;
  private String ean;
  private String issn;
  private boolean hasDigitalIssue;
  private String modifiedSince;
  private String creators;
  private String characters;
  private String series;
  private String events;
  private String stories;
  private String sharedAppearances;
  private String collaborators;
  private String orderBy;
  private int limit;
  private int offset;

  ComicsQuery(String format, String formatType, boolean noVariants, String dateDescriptor,
      String dateRange, String title, String titleStartsWith, int startYear, int issueNumber,
      String diamondCode, int digitalId, String upc, String isbn, String ean, String issn,
      boolean hasDigitalIssue, String modifiedSince, String creators, String characters,
      String series, String events, String stories, String sharedAppearances, String collaborators,
      String orderBy, int limit, int offset) {
    this.format = format;
    this.formatType = formatType;
    this.noVariants = noVariants;
    this.dateDescriptor = dateDescriptor;
    this.dateRange = dateRange;
    this.title = title;
    this.titleStartsWith = titleStartsWith;
    this.startYear = startYear;
    this.issueNumber = issueNumber;
    this.diamondCode = diamondCode;
    this.digitalId = digitalId;
    this.upc = upc;
    this.isbn = isbn;
    this.ean = ean;
    this.issn = issn;
    this.hasDigitalIssue = hasDigitalIssue;
    this.modifiedSince = modifiedSince;
    this.creators = creators;
    this.characters = characters;
    this.series = series;
    this.events = events;
    this.stories = stories;
    this.sharedAppearances = sharedAppearances;
    this.collaborators = collaborators;
    this.orderBy = orderBy;
    this.limit = limit;
    this.offset = offset;
  }

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

    if (format != null) {
      returnValues.put(QUERY_FORMAT, format);
    }

    if (formatType != null) {
      returnValues.put(QUERY_FORMAT_TYPE, formatType);
    }

    if (noVariants) {
      returnValues.put(QUERY_NO_VARIANTS, noVariants);
    }

    if (dateDescriptor != null) {
      returnValues.put(QUERY_DATE_DESCRIPTOR, dateDescriptor);
    }

    if (dateRange != null) {
      returnValues.put(QUERY_DATE_RANGE, dateRange);
    }
    if (title != null) {
      returnValues.put(QUERY_TITLE, title);
    }
    if (titleStartsWith != null) {
      returnValues.put(QUERY_TITLE_STARTS_WITH, titleStartsWith);
    }

    if (startYear > 0) {
      returnValues.put(QUERY_START_YEAR, startYear);
    }

    if (issueNumber > 0) {
      returnValues.put(QUERY_ISSUE_NUMBER, issueNumber);
    }

    if (diamondCode != null) {
      returnValues.put(QUERY_DIAMOND_CODE, diamondCode);
    }

    if (digitalId > 0) {
      returnValues.put(QUERY_DIGITAL_ID, digitalId);
    }

    if (upc != null) {
      returnValues.put(QUERY_UPC, upc);
    }

    if (isbn != null) {
      returnValues.put(QUERY_ISBN, isbn);
    }

    if (ean != null) {
      returnValues.put(QUERY_EAN, ean);
    }

    if (issn != null) {
      returnValues.put(QUERY_ISSN, issn);
    }

    if (hasDigitalIssue) {
      returnValues.put(QUERY_HAS_DIGITAL_ISSUE, hasDigitalIssue);
    }

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

    if (creators != null) {
      returnValues.put(QUERY_CREATORS, creators);
    }

    if (characters != null) {
      returnValues.put(QUERY_CHARACTERS, characters);
    }

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

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

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

    if (sharedAppearances != null) {
      returnValues.put(QUERY_SHARED_APPEARANCES, sharedAppearances);
    }

    if (collaborators != null) {
      returnValues.put(QUERY_COLLABORATORS, collaborators);
    }

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

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

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

    return returnValues;
  }


  public enum FormatType {
    COMIC("comic"),
    COLLECTION("collection");

    private final String formatType;

    private FormatType(final String formatType) {
      this.formatType = formatType;
    }

    @Override public String toString() {
      return formatType;
    }
  }

  public enum DateDescriptor {
    LAST_WEEK("last week"),
    THIS_WEEK("this week"),
    NEXT_WEEK("next week"),
    THIS_MONTH("this month");

    private final String dateDescriptor;

    private DateDescriptor(final String dateDescriptor) {
      this.dateDescriptor = dateDescriptor;
    }

    @Override public String toString() {
      return dateDescriptor;
    }
  }

  public static class Builder {
    private static final String LIST_SEPARATOR = ",";
    public final static int MAX_SIZE = 100;

    private Format format;
    private FormatType formatType;
    private boolean noVariants;
    private DateDescriptor dateDescriptor;
    private Date dateRange;
    private String title;
    private String titleStartsWith;
    private int startYear;
    private int issueNumber;
    private String diamondCode;
    private int digitalId;
    private String upc;
    private String isbn;
    private String ean;
    private String issn;
    private boolean hasDigitalIssue;
    private Date modifiedSince;
    private List<Integer> creators = new ArrayList<>();
    private List<Integer> characters = new ArrayList<>();
    private List<Integer> series = new ArrayList<>();
    private List<Integer> events = new ArrayList<>();
    private List<Integer> stories = new ArrayList<>();
    private List<Integer> sharedAppearances = new ArrayList<>();
    private List<Integer> collaborators = new ArrayList<>();
    private OrderBy orderBy;
    private int limit;
    private int offset;
    private boolean orderByAscendant;

    private Builder() {
    }

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

    public Builder withFormat(Format format) {
      this.format = format;
      return this;
    }

    public Builder withFormatType(FormatType formatType) {
      this.formatType = formatType;
      return this;
    }

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

    public Builder withDateDescriptor(DateDescriptor dateDescriptor) {
      this.dateDescriptor = dateDescriptor;
      return this;
    }

    public Builder withDateRange(Date date) {
      checkNotNull(date);
      dateRange = date;
      return this;
    }

    public Builder withTitle(String title) {
      this.title = title;
      return this;
    }

    public Builder withTitleStartsWith(String titleStartsWith) {
      this.titleStartsWith = titleStartsWith;
      return this;
    }

    public Builder withStartYear(int year) {
      this.startYear = year;
      return this;
    }

    public Builder withIssueNumber(int issueNumber) {
      this.issueNumber = issueNumber;
      return this;
    }

    public Builder withDiamondCode(String diamondCode) {
      this.diamondCode = diamondCode;
      return this;
    }

    public Builder withDigitalId(int digitalId) {
      this.digitalId = digitalId;
      return this;
    }

    public Builder withUpc(String upc) {
      this.upc = upc;
      return this;
    }

    public Builder withIsbn(String isbn) {
      this.isbn = isbn;
      return this;
    }

    public Builder withEan(String ean) {
      this.ean = ean;
      return this;
    }

    public Builder withIssn(String issn) {
      this.issn = issn;
      return this;
    }

    public Builder withHasDigitalIssue() {
      hasDigitalIssue = true;
      return this;
    }

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

    public Builder addCreator(int creatorId) {
      creators.add(creatorId);
      return this;
    }

    public Builder addCreator(List<Integer> creatorIds) {
      checkNotNull(creatorIds);
      creators.addAll(creatorIds);
      return this;
    }

    public Builder addCharacter(int characterId) {
      characters.add(characterId);
      return this;
    }

    public Builder addCharacter(List<Integer> characterIds) {
      checkNotNull(characterIds);
      characters.addAll(characterIds);
      return this;
    }

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

    public Builder addSerie(List<Integer> serieIds) {
      checkNotNull(serieIds);
      series.addAll(serieIds);
      return this;
    }

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

    public Builder addEvent(List<Integer> eventIds) {
      checkNotNull(eventIds);
      events.addAll(eventIds);
      return this;
    }

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

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

    public Builder addSharedAppearance(int characterId) {
      sharedAppearances.add(characterId);
      return this;
    }

    public Builder addSharedAppearance(List<Integer> characterIds) {
      checkNotNull(characterIds);
      sharedAppearances.addAll(characterIds);
      return this;
    }

    public Builder addCollaborator(int creatorId) {
      collaborators.add(creatorId);
      return this;
    }

    public Builder addCollaborator(List<Integer> creatorIds) {
      checkNotNull(creatorIds);
      collaborators.addAll(creatorIds);
      return this;
    }

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

    public Builder withOrderBy(OrderBy orderBy) {
      return withOrderBy(orderBy, true);
    }

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

    public Builder withOffset(int offset) {
      this.offset = offset;
      return this;
    }

    public ComicsQuery build() {
      String dataRangeAsString = convertDate(dateRange);
      String modifiedSinceAsString = convertDate(modifiedSince);
      String creatorsAsString = convertToList(creators);
      String charactersAsString = convertToList(characters);
      String seriesAsString = convertToList(series);
      String eventsAsString = convertToList(events);
      String storiesAsString = convertToList(stories);
      String sharedAppearancesAsString = convertToList(sharedAppearances);
      String collaboratorsAsString = convertToList(collaborators);
      String orderByAsString = convertOrderBy(orderBy, orderByAscendant);
      String formatAsString = (format != null) ? format.toString() : null;
      String formatTypeAsString = (formatType != null) ? formatType.toString() : null;
      String dateDescriptorAsString = (dateDescriptor != null) ? dateDescriptor.toString() : null;

      return new ComicsQuery(formatAsString, formatTypeAsString, noVariants,
          dateDescriptorAsString, dataRangeAsString, title, titleStartsWith, startYear,
          issueNumber, diamondCode, digitalId, upc, isbn, ean, issn, hasDigitalIssue,
          modifiedSinceAsString, creatorsAsString, charactersAsString, seriesAsString,
          eventsAsString, storiesAsString, sharedAppearancesAsString, collaboratorsAsString,
          orderByAsString, 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 checkNotNull(Object object) {
      if (object == null) {
        throw new IllegalArgumentException("the argument 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 CreatorResourceDto extends MarvelResourceDto {
  @SerializedName("role") private String role;

  public String getRole() {
    return role;
  }
} public class EventResourceDto extends MarvelResourceDto {
} public enum Format {
  COMIC("comic"),
  MAGAZINE("magazine"),
  TRADE_PAPERBACK("trade paperback"),
  HARDCOVER("hardcover"),
  DIGEST("digest"),
  GRAPHIC_NOVEL("graphic novel"),
  DIGITAL_COMIC("digital comic"),
  INFINITE_COMIC("infinite comic");

  private final String format;

  private Format(final String format) {
    this.format = format;
  }

  @Override public String toString() {
    return format;
  }
} public class MarvelDate {
  @SerializedName("type") private String type;
  @SerializedName("date") private String date;

  public String getType() {
    return type;
  }

  public String getDate() {
    return date;
  }
} public class MarvelImage {
  private static final String SEPARATOR = "/";
  private static final String DOT = ".";
  @SerializedName("path") private String path;
  @SerializedName("extension") private String extension;

  public String getPath() {
    return path;
  }

  public String getExtension() {
    return extension;
  }

  public String getImageUrl(Size size) {
    if (size == Size.FULLSIZE) {
      return path + DOT + extension;
    } else {
      return path + SEPARATOR + size.toString() + DOT + extension;
    }
  }

  @Override public String toString() {
    return "MarvelImage{" + "path='" + path + '\'' + ", extension='" + extension + '\'' + '}';
  }

  public enum Size {
    /** 50x75px */
    PORTRAIT_SMALL("portrait_small"),
    /** 100x150px */
    PORTRAIT_MEDIUM("portrait_medium"),
    /** 150x225px */
    PORTRAIT_XLARGE("portrait_xlarge"),
    /** 168x252px */
    PORTRAIT_FANTASTIC("portrait_fantastic"),
    /** 300x450px */
    PORTRAIT_UNCANNY("portrait_uncanny"),
    /** 216x324px */
    PORTRAIT_INCREDIBLE("portrait_incredible"),
    /** 65x45px */
    STANDARD_SMALL("standard_small"),
    /** 100x100px */
    STANDARD_MEDIUM("standard_medium"),
    /** 140x140px */
    STANDARD_LARGE("standard_large"),
    /** 200x200px */
    STANDARD_XLARGE("standard_xlarge"),
    /** 250x250px */
    STANDARD_FANTASTIC("standard_fantastic"),
    /** 180x180px */
    STANDARD_AMAZING("standard_amazing"),
    /** 120x90px */
    LANDSCAPE_SMALL("landscape_small"),
    /** 175x130px */
    LANDSCAPE_MEDIUM("landscape_medium"),
    /** 190x140px */
    LANDSCAPE_LARGE("landscape_large"),
    /** 270x200px */
    LANDSCAPE_XLARGE("landscape_xlarge"),
    /** 250x156px */
    LANDSCAPE_AMAZING("landscape_amazing"),
    /** 464x261px */
    LANDSCAPE_INCREDIBLE("landscape_incredible"),
    DETAIL("detail"),
    FULLSIZE("fullsize");

    private final String size;

    private Size(final String size) {
      this.size = size;
    }

    @Override public String toString() {
      return size;
    }
  }
} public class MarvelPrice {
  @SerializedName("type") private String type;
  @SerializedName("price") private float price;

  public String getType() {
    return type;
  }

  public float getPrice() {
    return price;
  }
} public class MarvelResources<T> {
  @SerializedName("available") private int available;
  @SerializedName("returned") private int returned;
  @SerializedName("collectionURI") private String collectionUri;
  @SerializedName("items") private List<T> items;

  public int getAvailable() {
    return available;
  }

  public int getReturned() {
    return returned;
  }

  public String getCollectionUri() {
    return collectionUri;
  }

  public List<T> getItems() {
    return items;
  }

  @Override public String toString() {
    return "MarvelResources{"
           + "available="
           + available
           + ", returned="
           + returned
           + ", collectionUri='"
           + collectionUri
           + '\''
           + ", items="
           + items
           +
           '}';
  }
} 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 MarvelUrl {
  @SerializedName("type") private String type;
  @SerializedName("url") private String url;

  public String getType() {
    return type;
  }

  public String getUrl() {
    return url;
  }

  @Override public String toString() {
    return "MarvelUrl{" + "type='" + type + '\'' + ", url='" + url + '\'' + '}';
  }
} public enum OrderBy {
  NAME("name"),
  MODIFIED("modified");

  private final String orderBy;

  private OrderBy(final String orderBy) {
    this.orderBy = orderBy;
  }

  @Override public String toString() {
    return orderBy;
  }
} public class StoryResourceDto extends MarvelResourceDto {
  @SerializedName("type") private String type;

  public String getType() {
    return type;
  }

  @Override public String toString() {
    return "StoryResourceDto{"
           + "name="
           + super.getName()
           + "resourceUri="
           + super.getResourceUri()
           + "type='"
           + type
           + '\''
           +
           '}';
  }
} public class TextObject {
  @SerializedName("type") private String type;
  @SerializedName("language") private String language;
  @SerializedName("text") private String text;

  public String getType() {
    return type;
  }

  public String getLanguage() {
    return language;
  }

  public String getText() {
    return text;
  }
}
import com.karumi.marvelapiclient.model.CharacterResourceDto;
import com.karumi.marvelapiclient.model.ComicDto;
import com.karumi.marvelapiclient.model.ComicResourceDto;
import com.karumi.marvelapiclient.model.ComicsDto;
import com.karumi.marvelapiclient.model.ComicsQuery;
import com.karumi.marvelapiclient.model.CreatorResourceDto;
import com.karumi.marvelapiclient.model.EventResourceDto;
import com.karumi.marvelapiclient.model.Format;
import com.karumi.marvelapiclient.model.MarvelDate;
import com.karumi.marvelapiclient.model.MarvelImage;
import com.karumi.marvelapiclient.model.MarvelPrice;
import com.karumi.marvelapiclient.model.MarvelResources;
import com.karumi.marvelapiclient.model.MarvelResponse;
import com.karumi.marvelapiclient.model.MarvelUrl;
import com.karumi.marvelapiclient.model.OrderBy;
import com.karumi.marvelapiclient.model.StoryResourceDto;
import com.karumi.marvelapiclient.model.TextObject;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.junit.Test;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/*
 *   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;



public class ComicApiClientTest extends ApiClientTest {

  private static final String ANY_PUBLIC_KEY = "1234";
  private static final String ANY_PRIVATE_KEY = "abcd";
  private static final String ANY_URL = "http://fake.marvel.com/";
  private static final int ANY_OFFSET = 1;
  private static final int ANY_LIMIT = 10;
  private static final int INVALID_LIMIT = 0;
  private static final String ANY_TITLE = "name";
  private static final String ANY_START_TITLE = "name";
  private static final int ANY_START_YEAR = 2002;
  private static final int ANY_ISSUE_NUMBER = 1;
  private static final String ANY_DIAMOND_CODE = "any";
  private static final String ANY_UPC = "1";
  private static final String ANY_ISBN = "1";
  private static final String ANY_EAN = "1";
  private static final String ANY_ISSN = "1";
  private static final int ANY_SERIE = 1;
  private static final int ANY_STORY = 1;
  private static final int ANY_CREATOR = 1;
  private static final int ANY_CHARACTER = 3;
  private static final int ANY_SHARED_APPEARANCES = 4;
  private static final int ANY_EVENT_1 = 1;
  private static final int ANY_EVENT_2 = 2;
  private static final int ANY_COLLABORATOR_1 = 1;
  private static final int ANY_COLLABORATOR_2 = 2;
  private static final String ANY_DATE_RANGE = "2015-01-09T22:10:45-0800";
  private static final String ANY_MODIFIED_SINCE = "2015-01-09T22:10:45-0800";
  private static final String ORDER_NAME_DESCEDANT_VALUE = "-name";
  private static final String INVALID_COMIC_ID = "";
  private static final String ANY_NOT_FOUND_ID = "1234";
  private static final String ANY_COMIC_ID = "123456";
  private static final String EVENTS_REQUEST = "1,2";
  private static final String COLLABORATORS_REQUEST = "1,2";
  private static final String LAST_WEEK_REQUEST = "last%20week";

  @Test public void shouldRequestComicsByOffsetAndLimitWithAsParams() throws Exception {
    ComicApiClient comicApiClient = givenComicApiClient();
    enqueueMockResponse();

    comicApiClient.getAll(ANY_OFFSET, ANY_LIMIT);

    assertRequestSentToContains("offset=" + ANY_OFFSET, "limit=" + ANY_LIMIT);
  }

  @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionWhenLimitIsZero()
      throws Exception {
    ComicApiClient comicApiClient = givenComicApiClient();
    enqueueMockResponse();

    comicApiClient.getAll(ANY_OFFSET, INVALID_LIMIT);
  }

  @Test public void shouldUseAllTheRequestParamsAddedFromQueryWhenSendIt() throws Exception {
    ComicApiClient comicApiClient = givenComicApiClient();
    enqueueMockResponse();

    ComicsQuery query = ComicsQuery.Builder.create()
        .withFormat(Format.COMIC)