public class BintrayCallException extends HttpResponseException {

    private int statusCode;
    private String reason;
    private String message;

    public BintrayCallException(int statusCode, String reason, String message) {
        super(statusCode, reason);
        this.statusCode = statusCode;
        this.reason = reason;
        this.message = message;
    }

    public BintrayCallException(HttpResponse response) {
        super(response.getStatusLine().getStatusCode(), response.getStatusLine().getReasonPhrase());
        String message = " ";
        String entity = null;
        int statusCode = response.getStatusLine().getStatusCode();
        if (response.getEntity() != null && statusCode != 405 && statusCode != 500) {
            try {
                entity = IOUtils.toString(response.getEntity().getContent());
                ObjectMapper mapper = ObjectMapperHelper.get();
                JsonNode node = mapper.readTree(entity);
                message = node.get("message").getTextValue();
            } catch (IOException | NullPointerException e) {
                //Null entity?
                if (entity != null) {
                    message = entity;
                }
            }
        }
        this.statusCode = statusCode;
        this.reason = response.getStatusLine().getReasonPhrase();
        this.message = message;
    }

    public BintrayCallException(Exception e) {
        super(HttpStatus.SC_BAD_REQUEST, e.getMessage());
        this.statusCode = HttpStatus.SC_BAD_REQUEST;
        this.reason = e.getMessage();
        this.message = (e.getCause() == null) ? " " : " : " + e.getCause().getMessage();
    }

    public int getStatusCode() {
        return statusCode;
    }

    public String getReason() {
        return reason;
    }

    @Override
    public String getMessage() {
        return message;
    }

    public void setMessage(String newMessage) {
        this.message = newMessage;
    }

    @Override
    public String toString() {
        return statusCode + ", " + reason + " " + message;
    }

} public class ObjectMapperHelper {

    public static ObjectMapper get() {
        return buildDetailsMapper();
    }

    private static ObjectMapper buildDetailsMapper() {
        ObjectMapper mapper = new ObjectMapper(new JsonFactory());

        // TODO: when moving to Jackson 2.x these can be replaced with JodaModule
        mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
        mapper.configure(SerializationConfig.Feature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false);

        //Don't include keys with null values implicitly, only explicitly set values should be sent over
        mapper.configure(DeserializationConfig.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY, false);
        mapper.configure(SerializationConfig.Feature.WRITE_NULL_MAP_VALUES, false);
        mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
        return mapper;
    }
} @JsonIgnoreProperties(ignoreUnknown = true)
public class PackageDetails {

    //Properties marked with @JsonPropery here are serialized to the create \ update package requests, the rest are
    // only deserialized when getting the package info
    @JsonProperty(value = "name")
    private String name;
    @JsonIgnore
    private String repo;
    @JsonIgnore
    private String owner;
    @JsonIgnore
    private String subject;
    @JsonProperty(value = "desc")
    private String description;
    @JsonProperty(value = "labels")
    private List<String> labels;
    @JsonIgnore
    private List<String> attributeNames;
    @JsonIgnore
    private Integer followersCount;
    @JsonIgnore
    private DateTime created;
    @JsonProperty(value = "website_url")
    private String websiteUrl;
    @JsonProperty(value = "issue_tracker_url")
    private String issueTrackerUrl;
    @JsonProperty(value = "github_repo")
    private String gitHubRepo;
    @JsonProperty(value = "github_release_notes_file")
    private String releaseNotesFile;
    @JsonProperty(value = "public_download_numbers")
    private Boolean publicDownloadNumbers;
    @JsonProperty(value = "public_stats")
    private Boolean publicStats;
    @JsonIgnore
    private List<String> linkedRepos;
    @JsonIgnore
    private List<String> versions;
    @JsonProperty(value = "licenses")
    private List<String> licenses;
    @JsonIgnore
    private String latestVersion;
    @JsonIgnore
    private DateTime updated;
    @JsonIgnore
    private Integer rating;
    @JsonIgnore
    private Integer ratingCount;
    @JsonIgnore
    private List<String> systemIds;
    @JsonProperty(value = "vcs_url")
    private String vcsUrl;
    @JsonIgnore
    private List<Attribute> attributes;

    //All other props that don't have specific fields
    private Map<String, Object> other = new HashMap<>();

    @JsonAnySetter
    public void set(String name, Object value) {
        other.put(name, value);
    }

    @JsonAnyGetter
    public Map<String, Object> other() {
        return other;
    }

    @JsonCreator
    public PackageDetails() {
    }

    public PackageDetails(String name) {
        this.name = name;
    }

    public static ObjectMapper getObjectMapper() {
        return ObjectMapperHelper.get();
    }

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

    public PackageDetails description(String description) {
        this.description = description;
        return this;
    }

    public PackageDetails labels(List<String> labels) {
        this.labels = labels;
        return this;
    }

    public PackageDetails websiteUrl(String websiteUrl) {
        this.websiteUrl = websiteUrl;
        return this;
    }

    public PackageDetails issueTrackerUrl(String issueTrackerUrl) {
        this.issueTrackerUrl = issueTrackerUrl;
        return this;
    }

    public PackageDetails gitHubRepo(String gitHubRepo) {
        this.gitHubRepo = gitHubRepo;
        return this;
    }

    public PackageDetails releaseNotesFile(String releaseNotesFile) {
        this.releaseNotesFile = releaseNotesFile;
        return this;
    }

    public PackageDetails publicDownloadNumbers(Boolean publicDownloadNumbers) {
        this.publicDownloadNumbers = publicDownloadNumbers;
        return this;
    }

    public PackageDetails publicStats(Boolean publicStats) {
        this.publicStats = publicStats;
        return this;
    }

    public PackageDetails licenses(List<String> licenses) {
        this.licenses = licenses;
        return this;
    }

    public PackageDetails vcsUrl(String vcsUrl) {
        this.vcsUrl = vcsUrl;
        return this;
    }

    public PackageDetails attributes(List<Attribute> attributes) {
        this.attributes = attributes;
        return this;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @JsonIgnore
    public String getRepo() {
        return repo;
    }

    @JsonProperty(value = "repo")
    public void setRepo(String repo) {
        this.repo = repo;
    }

    @JsonIgnore
    public String getOwner() {
        return owner;
    }

    @JsonProperty(value = "owner")
    public void setOwner(String owner) {
        this.owner = owner;
    }

    @JsonIgnore
    public String getSubject() {
        return subject;
    }

    @JsonProperty(value = "subject")
    public void setSubject(String subject) {
        this.subject = subject;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<String> getLabels() {
        return labels;
    }

    public void setLabels(List<String> labels) {
        this.labels = labels;
    }

    @JsonIgnore
    public List<String> getAttributeNames() {
        return attributeNames;
    }

    @JsonProperty(value = "attribute_names")
    public void setAttributeNames(List<String> attributeNames) {
        this.attributeNames = attributeNames;
    }

    @JsonIgnore
    public Integer getFollowersCount() {
        return followersCount;
    }

    @JsonProperty(value = "followers_count")
    public void setFollowersCount(Integer followersCount) {
        this.followersCount = followersCount;
    }

    @JsonIgnore
    public DateTime getCreated() {
        return created;
    }

    @JsonProperty(value = "created")
    public void setCreated(DateTime created) {
        this.created = created;
    }

    public String getWebsiteUrl() {
        return websiteUrl;
    }

    public void setWebsiteUrl(String websiteUrl) {
        this.websiteUrl = websiteUrl;
    }

    public String getIssueTrackerUrl() {
        return issueTrackerUrl;
    }

    public void setIssueTrackerUrl(String issueTrackerUrl) {
        this.issueTrackerUrl = issueTrackerUrl;
    }

    public String getGitHubRepo() {
        return gitHubRepo;
    }

    public void setGitHubRepo(String gitHubRepo) {
        this.gitHubRepo = gitHubRepo;
    }

    public String getReleaseNotesFile() {
        return releaseNotesFile;
    }

    public void setReleaseNotesFile(String releaseNotesFile) {
        this.releaseNotesFile = releaseNotesFile;
    }

    public Boolean getPublicDownloadNumbers() {
        return publicDownloadNumbers;
    }

    public void setPublicDownloadNumbers(Boolean publicDownloadNumbers) {
        this.publicDownloadNumbers = publicDownloadNumbers;
    }

    public Boolean getPublicStats() {
        return publicStats;
    }

    public void setPublicStats(Boolean publicStats) {
        this.publicStats = publicStats;
    }

    @JsonIgnore
    public List<String> getLinkedRepos() {
        return linkedRepos;
    }

    @JsonProperty("linked_to_repos")
    public void setLinkedRepos(List<String> linkedRepos) {
        this.linkedRepos = linkedRepos;
    }

    @JsonIgnore
    public List<String> getVersions() {
        return versions;
    }

    @JsonProperty("versions")
    public void setVersions(List<String> versions) {
        this.versions = versions;
    }

    public List<String> getLicenses() {
        return licenses;
    }

    public void setLicenses(List<String> licenses) {
        this.licenses = licenses;
    }

    @JsonIgnore
    public String getLatestVersion() {
        return latestVersion;
    }

    @JsonProperty(value = "latest_version")
    public void setLatestVersion(String latestVersion) {
        this.latestVersion = latestVersion;
    }

    @JsonIgnore
    public DateTime getUpdated() {
        return updated;
    }

    @JsonProperty(value = "updated")
    public void setUpdated(DateTime updated) {
        this.updated = updated;
    }

    @JsonIgnore
    public Integer getRating() {
        return rating;
    }

    @JsonProperty(value = "rating")
    public void setRating(Integer rating) {
        this.rating = rating;
    }

    @JsonIgnore
    public Integer getRatingCount() {
        return ratingCount;
    }

    @JsonProperty(value = "rating_count")
    public void setRatingCount(Integer ratingCount) {
        this.ratingCount = ratingCount;
    }

    @JsonIgnore
    public List<String> getSystemIds() {
        return systemIds;
    }

    @JsonProperty(value = "system_ids")
    public void setSystemIds(List<String> systemIds) {
        this.systemIds = systemIds;
    }

    public String getVcsUrl() {
        return vcsUrl;
    }

    public void setVcsUrl(String vcsUrl) {
        this.vcsUrl = vcsUrl;
    }

    @JsonIgnore
    public List<Attribute> getAttributes() {
        return attributes;
    }

    @JsonProperty("attributes")
    public void setAttributes(List<Attribute> attributes) {
        this.attributes = attributes;
    }
} @JsonIgnoreProperties(ignoreUnknown = true)
public class RepositoryDetails {

    //Properties marked with @JsonPropery here are serialized to the create \ update version requests, the rest are
    // only deserialized when getting the repo info
    @JsonIgnore
    String name;
    @JsonIgnore
    String owner;
    @JsonProperty
    String type;
    @JsonProperty(value = "private")
    Boolean isPrivate;
    @JsonProperty
    Boolean premium;
    @JsonProperty(value = "desc")
    String description;
    @JsonProperty
    List<String> labels;
    @JsonProperty
    Integer yum_metadata_depth;
    @JsonIgnore
    DateTime created;
    @JsonIgnore
    Integer packageCount;
    @JsonIgnore
    Boolean updateExisting; //Property is not used in the Bintray API but Artifactory uses is in it's Bintray integration

    //All other props that don't have specific fields
    private Map<String, Object> other = new HashMap<>();

    @JsonAnySetter
    public void set(String name, Object value) {
        other.put(name, value);
    }

    @JsonAnyGetter
    public Map<String, Object> other() {
        return other;
    }

    public static ObjectMapper getObjectMapper() {
        return ObjectMapperHelper.get();
    }

    @JsonIgnore
    public String getName() {
        return name;
    }

    @JsonProperty(value = "name")
    public RepositoryDetails setName(String name) {
        this.name = name;
        return this;
    }

    public String getType() {
        return type;
    }

    public Boolean getIsPrivate() {
        return isPrivate;
    }

    public RepositoryDetails setIsPrivate(Boolean isPrivate) {
        this.isPrivate = isPrivate;
        return this;
    }

    public Boolean getPremium() {
        return premium;
    }

    public RepositoryDetails setPremium(Boolean premium) {
        this.premium = premium;
        return this;
    }

    public RepositoryDetails setType(String type) {
        this.type = type;
        return this;
    }

    public Integer getYumMetadataDepth() {
        return yum_metadata_depth;
    }

    public RepositoryDetails setYumMetadataDepth(Integer yum_metadata_depth) {
        this.yum_metadata_depth = yum_metadata_depth;
        return this;
    }

    public String getOwner() {
        return owner;
    }

    public RepositoryDetails setOwner(String owner) {
        this.owner = owner;
        return this;
    }

    public String getDescription() {
        return description;
    }

    public RepositoryDetails setDescription(String description) {
        this.description = description;
        return this;
    }

    @JsonIgnore
    public DateTime getCreated() {
        return created;
    }

    @JsonProperty(value = "created")
    public RepositoryDetails setCreated(DateTime created) {
        this.created = created;
        return this;
    }

    public List<String> getLabels() {
        return labels;
    }

    public RepositoryDetails setLabels(List<String> labels) {
        this.labels = labels;
        return this;
    }

    @JsonIgnore
    public Integer getPackageCount() {
        return packageCount;
    }

    @JsonProperty(value = "package_count")
    public void setPackageCount(Integer packageCount) {
        this.packageCount = packageCount;
    }

    @JsonIgnore
    public Boolean getUpdateExisting() {
        return updateExisting;
    }

    @JsonProperty(value = "updateExisting")
    public void setUpdateExisting(Boolean updateExisting) {
        this.updateExisting = updateExisting;
    }
} public interface AttributesSearchQuery {
    AttributesSearchQueryClause byAttributeName(String name);
} public interface PackageHandle extends Handle<Pkg> {

    RepositoryHandle repository();

    VersionHandle version(String versionName);

    Pkg get() throws IOException, BintrayCallException;

    PackageHandle update(PackageDetails packageDetails) throws IOException, BintrayCallException;

    PackageHandle delete() throws BintrayCallException;

    boolean exists() throws BintrayCallException;

    VersionHandle createVersion(VersionDetails versionDetails) throws IOException, BintrayCallException;

    PackageHandle setAttributes(PackageDetails packageDetails) throws IOException, BintrayCallException;

    PackageHandle setAttributes(List<Attribute> attributes) throws IOException, BintrayCallException;

    PackageHandle updateAttributes(PackageDetails packageDetails) throws IOException, BintrayCallException;

    PackageHandle updateAttributes(List<Attribute> attributes) throws IOException, BintrayCallException;

    String name();

    String getCurrentPackageUri();
} public interface RepositoryHandle extends Handle<Repository> {

    SubjectHandle owner();

    Repository get() throws IOException, BintrayCallException;

    RepositoryHandle update(RepositoryDetails repositoryDetails) throws IOException, BintrayCallException;

    PackageHandle pkg(String name);

    PackageHandle createPkg(PackageDetails packageDetails) throws IOException, BintrayCallException;

    String name();

    AttributesSearchQuery searchForPackage();

    RepositoryHandle delete() throws BintrayCallException;

    boolean exists() throws BintrayCallException;

    String getRepositoryUri();
} public interface SubjectHandle extends Handle<Subject> {

    String name();

    Subject get() throws IOException, BintrayCallException;

    RepositoryHandle repository(String name);

    RepositoryHandle createRepo(RepositoryDetails repoDetails) throws IOException, BintrayCallException;

    ProductHandle product(String name);

    ProductHandle createProduct(ProductDetails productDetails) throws IOException, BintrayCallException;
} public interface Pkg {

    String name();

    String repository();

    String owner();

    String description();

    List<String> labels();

    List<String> attributeNames();

    Integer rating();

    Integer ratingCount();

    Integer followersCount();

    DateTime created();

    List<String> versions();

    String latestVersion();

    DateTime updated();

    List<String> linkedToRepos();

    List<String> systemIds();

    List<String> licenses();

    String vcsUrl();

    Object getFieldByKey(String key);
} public interface Repository {

    String getName();

    String getOwner();

    String getType();

    Boolean isPrivate();

    Boolean isPremium();

    String getDesc();

    List<String> getLabels();

    DateTime getCreated();

    Integer getPackageCount();

    Object getFieldByKey(String key);
} public class PackageImpl implements Pkg {
    private static final Logger log = LoggerFactory.getLogger(PackageImpl.class);

    private String name;
    private String repository;
    private String owner;
    private String description;
    private List<String> labels;
    private List<String> attributeNames;
    private Integer rating;
    private Integer ratingCount;
    private Integer followersCount;
    private DateTime created;
    private List<String> versions;
    private String latestVersion;
    private DateTime updated;
    private List<String> linkedToRepos;
    private List<String> systemIds;
    private List<String> licenses;
    private String vcsUrl;
    private Map<String, Object> other;

    public PackageImpl(PackageDetails packageDetails) {
        this.name = packageDetails.getName();
        this.repository = packageDetails.getRepo();
        this.owner = packageDetails.getOwner();
        this.description = packageDetails.getDescription();
        this.labels = packageDetails.getLabels();
        this.attributeNames = packageDetails.getAttributeNames();
        this.ratingCount = packageDetails.getRatingCount();
        this.followersCount = packageDetails.getFollowersCount();
        this.created = packageDetails.getCreated();
        this.versions = packageDetails.getVersions();
        this.latestVersion = packageDetails.getLatestVersion();
        this.updated = packageDetails.getUpdated();
        this.linkedToRepos = packageDetails.getLinkedRepos();
        this.systemIds = packageDetails.getSystemIds();
        this.licenses = packageDetails.getLicenses();
        this.vcsUrl = packageDetails.getVcsUrl();
        this.other = packageDetails.other();
    }

    public PackageImpl(String name, String repository, String owner, String description, List<String> labels,
                       List<String> attributeNames, Integer rating, Integer ratingCount, Integer followersCount,
                       DateTime created, List<String> versions, String latestVersion, DateTime updated,
                       List<String> linkedToRepos, List<String> systemIds) {
        this.name = name;
        this.repository = repository;
        this.owner = owner;
        this.description = description;
        this.labels = labels;
        this.attributeNames = attributeNames;
        this.rating = rating;
        this.ratingCount = ratingCount;
        this.followersCount = followersCount;
        this.created = created;
        this.versions = versions;
        this.latestVersion = latestVersion;
        this.updated = updated;
        this.linkedToRepos = linkedToRepos;
        this.systemIds = systemIds;
    }

    public static String getCreateUpdateJson(PackageDetails packageDetails) throws IOException {
        ObjectMapper mapper = ObjectMapperHelper.get();
        String jsonContent;
        try {
            jsonContent = mapper.writeValueAsString(packageDetails);
        } catch (IOException e) {
            log.error("Can't process the json file: " + e.getMessage());
            throw e;
        }
        return jsonContent;
    }

    @Override
    public String name() {
        return name;
    }

    @Override
    public String repository() {
        return repository;
    }

    @Override
    public String owner() {
        return owner;
    }

    @Override
    public String description() {
        return description;
    }

    @Override
    public List<String> labels() {
        return labels;
    }

    @Override
    public List<String> attributeNames() {
        return attributeNames;
    }

    @Override
    public Integer rating() {
        return rating;
    }

    @Override
    public Integer ratingCount() {
        return ratingCount;
    }

    @Override
    public Integer followersCount() {
        return followersCount;
    }

    @Override
    public DateTime created() {
        return created;
    }

    @Override
    public List<String> versions() {
        return versions;
    }

    @Override
    public String latestVersion() {
        return latestVersion;
    }

    @Override
    public DateTime updated() {
        return updated;
    }

    @Override
    public List<String> linkedToRepos() {
        return linkedToRepos;
    }

    @Override
    public List<String> systemIds() {
        return systemIds;
    }

    @Override
    public List<String> licenses() {
        return licenses;
    }

    @Override
    public String vcsUrl() {
        return vcsUrl;
    }

    @Override
    public Object getFieldByKey(String key) {
        return other.get(key);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        PackageImpl aPackage = (PackageImpl) o;

        if (!name.equals(aPackage.name)) return false;

        return true;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    @Override
    public String toString() {
        return "Package{" +
                "getName='" + name + '\'' +
                ", repository='" + repository + '\'' +
                ", owner='" + owner + '\'' +
                ", description='" + description + '\'' +
                ", labels=" + labels +
                ", attributeNames=" + attributeNames +
                ", rating=" + rating +
                ", ratingCount=" + ratingCount +
                ", followersCount=" + followersCount +
                ", created=" + created +
                ", versions=" + versions +
                ", latestVersion='" + latestVersion + '\'' +
                ", updated=" + updated +
                ", linkedToRepos='" + linkedToRepos + '\'' +
                ", systemIds=" + systemIds +
                '}';
    }
} public class RepositoryImpl implements Repository {
    private static final Logger log = LoggerFactory.getLogger(RepositoryImpl.class);

    private String name;
    private String owner;
    private String type;
    private Boolean isPrivate;
    private Boolean premium;
    private String desc;
    private List<String> labels;
    private DateTime created;
    private Integer packageCount;
    private Map<String ,Object> other;

    public RepositoryImpl() {
    }

    public RepositoryImpl(RepositoryDetails repositoryDetails) {
        this.name = repositoryDetails.getName();
        this.owner = repositoryDetails.getOwner();
        this.type = repositoryDetails.getType();
        this.isPrivate = repositoryDetails.getIsPrivate();
        this.premium = repositoryDetails.getPremium();
        this.desc = repositoryDetails.getDescription();
        this.labels = repositoryDetails.getLabels();
        this.created = repositoryDetails.getCreated();
        this.packageCount = repositoryDetails.getPackageCount();
        this.other = repositoryDetails.other();
    }

    public RepositoryImpl(String name, String owner, String type, Boolean isPrivate, Boolean premium, String desc,
                          List<String> labels, DateTime created, Integer packageCount) {
        this.name = name;
        this.owner = owner;
        this.type = type;
        this.isPrivate = isPrivate;
        this.premium = premium;
        this.desc = desc;
        this.labels = labels;
        this.created = created;
        this.packageCount = packageCount;
    }

    public static String getCreateJson(RepositoryDetails repositoryDetails) throws IOException {
        ObjectMapper mapper = ObjectMapperHelper.get();
        try {
            return mapper.writeValueAsString(repositoryDetails);
        } catch (IOException e) {
            log.error("Can't process the json file: " + e.getMessage());
            log.debug("{}", e);
            throw e;
        }
    }

    /**
     * PATCH repo only accepts description and label updates, name is needed for URL creation, because of the special
     * ignore and property structure of the RepositoryDetails class this method just uses a json generator to write
     * the update json.
     */
    public static String getUpdateJson(RepositoryDetails repositoryDetails) throws IOException {
        StringWriter writer = new StringWriter();
        JsonGenerator jGen = ObjectMapperHelper.get().getJsonFactory().createJsonGenerator(writer);
        jGen.writeStartObject();
        jGen.writeStringField("name", repositoryDetails.getName());
        jGen.writeStringField("desc", repositoryDetails.getDescription());
        if (repositoryDetails.getLabels().size() > 0) {
            jGen.writeArrayFieldStart("labels");
            for (String label : repositoryDetails.getLabels()) {
                jGen.writeString(label);
            }
            jGen.writeEndArray();
        }
        jGen.writeEndObject();
        jGen.close();
        writer.close();
        return writer.toString();
    }


    @Override
    public String getName() {
        return name;
    }

    @Override
    public String getOwner() {
        return owner;
    }

    @Override
    public String getType() {
        return type;
    }

    @Override
    public Boolean isPrivate() {
        return isPrivate;
    }

    @Override
    public Boolean isPremium() {
        return premium;
    }

    @Override
    public String getDesc() {
        return desc;
    }

    @Override
    public List<String> getLabels() {
        return labels;
    }

    @Override
    public DateTime getCreated() {
        return created;
    }

    @Override
    public Integer getPackageCount() {
        return packageCount;
    }

    @Override
    public Object getFieldByKey(String key) {
        return other.get(key);
    }
}
import com.jfrog.bintray.client.api.BintrayCallException;
import com.jfrog.bintray.client.api.ObjectMapperHelper;
import com.jfrog.bintray.client.api.details.PackageDetails;
import com.jfrog.bintray.client.api.details.RepositoryDetails;
import com.jfrog.bintray.client.api.handle.AttributesSearchQuery;
import com.jfrog.bintray.client.api.handle.PackageHandle;
import com.jfrog.bintray.client.api.handle.RepositoryHandle;
import com.jfrog.bintray.client.api.handle.SubjectHandle;
import com.jfrog.bintray.client.api.model.Pkg;
import com.jfrog.bintray.client.api.model.Repository;
import com.jfrog.bintray.client.impl.model.PackageImpl;
import com.jfrog.bintray.client.impl.model.RepositoryImpl;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.entity.ContentType;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.jfrog.bintray.client.api.BintrayClientConstatnts.API_PKGS;
import static com.jfrog.bintray.client.api.BintrayClientConstatnts.API_REPOS;
package com.jfrog.bintray.client.impl.handle;




/**
 * @author Dan Feldman
 */
class RepositoryHandleImpl implements RepositoryHandle {
    private static final Logger log = LoggerFactory.getLogger(RepositoryHandleImpl.class);

    private BintrayImpl bintrayHandle;
    private SubjectHandleImpl owner;
    private String name;
    private AttributesSearchQueryImpl searchQuery = null;

    public RepositoryHandleImpl(BintrayImpl bintrayHandle, SubjectHandleImpl owner, String repoName) {
        this.bintrayHandle = bintrayHandle;
        this.owner = owner;
        this.name = repoName;
    }

    @Override
    public SubjectHandle owner() {
        return owner;
    }

    @Override
    public Repository get() throws IOException, BintrayCallException {
        HttpResponse response = bintrayHandle.get(getRepositoryUri(), null);
        RepositoryDetails repoDetails;
        InputStream jsonContentStream = response.getEntity().getContent();
        ObjectMapper mapper = ObjectMapperHelper.get();
        try {
            repoDetails = mapper.readValue(jsonContentStream, RepositoryDetails.class);
        } catch (IOException e) {
            log.error("Can't parse the json file: " + e.getMessage());
            throw e;
        }
        return new RepositoryImpl(repoDetails);
    }

    @Override
    public RepositoryHandle update(RepositoryDetails repositoryDetails) throws IOException, BintrayCallException {
        Map<String, String> headers = new HashMap<>();
        String jsonContent = RepositoryImpl.getUpdateJson(repositoryDetails);
        BintrayImpl.addContentTypeJsonHeader(headers);
        bintrayHandle.patch(getRepositoryUri(), headers, IOUtils.toInputStream(jsonContent));
        return this;
    }

    @Override
    public PackageHandle pkg(String packageName) {
        return new PackageHandleImpl(bintrayHandle, this, packageName);
    }

    @Override
    public PackageHandle createPkg(PackageDetails packageDetails) throws IOException, BintrayCallException {
        String jsonContent = PackageImpl.getCreateUpdateJson(packageDetails);