/*
 * Jellyfin API
 * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
 *
 * The version of the OpenAPI document: 10.11.6
 * 
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */

package org.openhab.binding.jellyfin.internal.gen.current.model;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * AlbumInfo
 */
@jakarta.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "OpenAPI Generator")
public class AlbumInfo {
    public static final String JSON_PROPERTY_NAME = "Name";
    private @org.eclipse.jdt.annotation.Nullable String name;

    public static final String JSON_PROPERTY_ORIGINAL_TITLE = "OriginalTitle";
    private @org.eclipse.jdt.annotation.Nullable String originalTitle;

    public static final String JSON_PROPERTY_PATH = "Path";
    private @org.eclipse.jdt.annotation.Nullable String path;

    public static final String JSON_PROPERTY_METADATA_LANGUAGE = "MetadataLanguage";
    private @org.eclipse.jdt.annotation.Nullable String metadataLanguage;

    public static final String JSON_PROPERTY_METADATA_COUNTRY_CODE = "MetadataCountryCode";
    private @org.eclipse.jdt.annotation.Nullable String metadataCountryCode;

    public static final String JSON_PROPERTY_PROVIDER_IDS = "ProviderIds";
    private @org.eclipse.jdt.annotation.Nullable Map<String, String> providerIds;

    public static final String JSON_PROPERTY_YEAR = "Year";
    private @org.eclipse.jdt.annotation.Nullable Integer year;

    public static final String JSON_PROPERTY_INDEX_NUMBER = "IndexNumber";
    private @org.eclipse.jdt.annotation.Nullable Integer indexNumber;

    public static final String JSON_PROPERTY_PARENT_INDEX_NUMBER = "ParentIndexNumber";
    private @org.eclipse.jdt.annotation.Nullable Integer parentIndexNumber;

    public static final String JSON_PROPERTY_PREMIERE_DATE = "PremiereDate";
    private @org.eclipse.jdt.annotation.Nullable OffsetDateTime premiereDate;

    public static final String JSON_PROPERTY_IS_AUTOMATED = "IsAutomated";
    private @org.eclipse.jdt.annotation.Nullable Boolean isAutomated;

    public static final String JSON_PROPERTY_ALBUM_ARTISTS = "AlbumArtists";
    private @org.eclipse.jdt.annotation.Nullable List<String> albumArtists = new ArrayList<>();

    public static final String JSON_PROPERTY_ARTIST_PROVIDER_IDS = "ArtistProviderIds";
    private @org.eclipse.jdt.annotation.Nullable Map<String, String> artistProviderIds = new HashMap<>();

    public static final String JSON_PROPERTY_SONG_INFOS = "SongInfos";
    private @org.eclipse.jdt.annotation.Nullable List<SongInfo> songInfos = new ArrayList<>();

    public AlbumInfo() {
    }

    public AlbumInfo name(@org.eclipse.jdt.annotation.Nullable String name) {
        this.name = name;
        return this;
    }

    /**
     * Gets or sets the name.
     * 
     * @return name
     */
    @JsonProperty(value = JSON_PROPERTY_NAME)
    public @org.eclipse.jdt.annotation.Nullable String getName() {
        return name;
    }

    @JsonProperty(value = JSON_PROPERTY_NAME)
    public void setName(@org.eclipse.jdt.annotation.Nullable String name) {
        this.name = name;
    }

    public AlbumInfo originalTitle(@org.eclipse.jdt.annotation.Nullable String originalTitle) {
        this.originalTitle = originalTitle;
        return this;
    }

    /**
     * Gets or sets the original title.
     * 
     * @return originalTitle
     */
    @JsonProperty(value = JSON_PROPERTY_ORIGINAL_TITLE)
    public @org.eclipse.jdt.annotation.Nullable String getOriginalTitle() {
        return originalTitle;
    }

    @JsonProperty(value = JSON_PROPERTY_ORIGINAL_TITLE)
    public void setOriginalTitle(@org.eclipse.jdt.annotation.Nullable String originalTitle) {
        this.originalTitle = originalTitle;
    }

    public AlbumInfo path(@org.eclipse.jdt.annotation.Nullable String path) {
        this.path = path;
        return this;
    }

    /**
     * Gets or sets the path.
     * 
     * @return path
     */
    @JsonProperty(value = JSON_PROPERTY_PATH)
    public @org.eclipse.jdt.annotation.Nullable String getPath() {
        return path;
    }

    @JsonProperty(value = JSON_PROPERTY_PATH)
    public void setPath(@org.eclipse.jdt.annotation.Nullable String path) {
        this.path = path;
    }

    public AlbumInfo metadataLanguage(@org.eclipse.jdt.annotation.Nullable String metadataLanguage) {
        this.metadataLanguage = metadataLanguage;
        return this;
    }

    /**
     * Gets or sets the metadata language.
     * 
     * @return metadataLanguage
     */
    @JsonProperty(value = JSON_PROPERTY_METADATA_LANGUAGE)
    public @org.eclipse.jdt.annotation.Nullable String getMetadataLanguage() {
        return metadataLanguage;
    }

    @JsonProperty(value = JSON_PROPERTY_METADATA_LANGUAGE)
    public void setMetadataLanguage(@org.eclipse.jdt.annotation.Nullable String metadataLanguage) {
        this.metadataLanguage = metadataLanguage;
    }

    public AlbumInfo metadataCountryCode(@org.eclipse.jdt.annotation.Nullable String metadataCountryCode) {
        this.metadataCountryCode = metadataCountryCode;
        return this;
    }

    /**
     * Gets or sets the metadata country code.
     * 
     * @return metadataCountryCode
     */
    @JsonProperty(value = JSON_PROPERTY_METADATA_COUNTRY_CODE)
    public @org.eclipse.jdt.annotation.Nullable String getMetadataCountryCode() {
        return metadataCountryCode;
    }

    @JsonProperty(value = JSON_PROPERTY_METADATA_COUNTRY_CODE)
    public void setMetadataCountryCode(@org.eclipse.jdt.annotation.Nullable String metadataCountryCode) {
        this.metadataCountryCode = metadataCountryCode;
    }

    public AlbumInfo providerIds(@org.eclipse.jdt.annotation.Nullable Map<String, String> providerIds) {
        this.providerIds = providerIds;
        return this;
    }

    public AlbumInfo putProviderIdsItem(String key, String providerIdsItem) {
        if (this.providerIds == null) {
            this.providerIds = new HashMap<>();
        }
        this.providerIds.put(key, providerIdsItem);
        return this;
    }

    /**
     * Gets or sets the provider ids.
     * 
     * @return providerIds
     */
    @JsonProperty(value = JSON_PROPERTY_PROVIDER_IDS)
    @JsonInclude(content = JsonInclude.Include.ALWAYS)
    public @org.eclipse.jdt.annotation.Nullable Map<String, String> getProviderIds() {
        return providerIds;
    }

    @JsonProperty(value = JSON_PROPERTY_PROVIDER_IDS)
    @JsonInclude(content = JsonInclude.Include.ALWAYS)
    public void setProviderIds(@org.eclipse.jdt.annotation.Nullable Map<String, String> providerIds) {
        this.providerIds = providerIds;
    }

    public AlbumInfo year(@org.eclipse.jdt.annotation.Nullable Integer year) {
        this.year = year;
        return this;
    }

    /**
     * Gets or sets the year.
     * 
     * @return year
     */
    @JsonProperty(value = JSON_PROPERTY_YEAR)
    public @org.eclipse.jdt.annotation.Nullable Integer getYear() {
        return year;
    }

    @JsonProperty(value = JSON_PROPERTY_YEAR)
    public void setYear(@org.eclipse.jdt.annotation.Nullable Integer year) {
        this.year = year;
    }

    public AlbumInfo indexNumber(@org.eclipse.jdt.annotation.Nullable Integer indexNumber) {
        this.indexNumber = indexNumber;
        return this;
    }

    /**
     * Get indexNumber
     * 
     * @return indexNumber
     */
    @JsonProperty(value = JSON_PROPERTY_INDEX_NUMBER)
    public @org.eclipse.jdt.annotation.Nullable Integer getIndexNumber() {
        return indexNumber;
    }

    @JsonProperty(value = JSON_PROPERTY_INDEX_NUMBER)
    public void setIndexNumber(@org.eclipse.jdt.annotation.Nullable Integer indexNumber) {
        this.indexNumber = indexNumber;
    }

    public AlbumInfo parentIndexNumber(@org.eclipse.jdt.annotation.Nullable Integer parentIndexNumber) {
        this.parentIndexNumber = parentIndexNumber;
        return this;
    }

    /**
     * Get parentIndexNumber
     * 
     * @return parentIndexNumber
     */
    @JsonProperty(value = JSON_PROPERTY_PARENT_INDEX_NUMBER)
    public @org.eclipse.jdt.annotation.Nullable Integer getParentIndexNumber() {
        return parentIndexNumber;
    }

    @JsonProperty(value = JSON_PROPERTY_PARENT_INDEX_NUMBER)
    public void setParentIndexNumber(@org.eclipse.jdt.annotation.Nullable Integer parentIndexNumber) {
        this.parentIndexNumber = parentIndexNumber;
    }

    public AlbumInfo premiereDate(@org.eclipse.jdt.annotation.Nullable OffsetDateTime premiereDate) {
        this.premiereDate = premiereDate;
        return this;
    }

    /**
     * Get premiereDate
     * 
     * @return premiereDate
     */
    @JsonProperty(value = JSON_PROPERTY_PREMIERE_DATE)
    public @org.eclipse.jdt.annotation.Nullable OffsetDateTime getPremiereDate() {
        return premiereDate;
    }

    @JsonProperty(value = JSON_PROPERTY_PREMIERE_DATE)
    public void setPremiereDate(@org.eclipse.jdt.annotation.Nullable OffsetDateTime premiereDate) {
        this.premiereDate = premiereDate;
    }

    public AlbumInfo isAutomated(@org.eclipse.jdt.annotation.Nullable Boolean isAutomated) {
        this.isAutomated = isAutomated;
        return this;
    }

    /**
     * Get isAutomated
     * 
     * @return isAutomated
     */
    @JsonProperty(value = JSON_PROPERTY_IS_AUTOMATED)
    public @org.eclipse.jdt.annotation.Nullable Boolean getIsAutomated() {
        return isAutomated;
    }

    @JsonProperty(value = JSON_PROPERTY_IS_AUTOMATED)
    public void setIsAutomated(@org.eclipse.jdt.annotation.Nullable Boolean isAutomated) {
        this.isAutomated = isAutomated;
    }

    public AlbumInfo albumArtists(@org.eclipse.jdt.annotation.Nullable List<String> albumArtists) {
        this.albumArtists = albumArtists;
        return this;
    }

    public AlbumInfo addAlbumArtistsItem(String albumArtistsItem) {
        if (this.albumArtists == null) {
            this.albumArtists = new ArrayList<>();
        }
        this.albumArtists.add(albumArtistsItem);
        return this;
    }

    /**
     * Gets or sets the album artist.
     * 
     * @return albumArtists
     */
    @JsonProperty(value = JSON_PROPERTY_ALBUM_ARTISTS)
    public @org.eclipse.jdt.annotation.Nullable List<String> getAlbumArtists() {
        return albumArtists;
    }

    @JsonProperty(value = JSON_PROPERTY_ALBUM_ARTISTS)
    public void setAlbumArtists(@org.eclipse.jdt.annotation.Nullable List<String> albumArtists) {
        this.albumArtists = albumArtists;
    }

    public AlbumInfo artistProviderIds(@org.eclipse.jdt.annotation.Nullable Map<String, String> artistProviderIds) {
        this.artistProviderIds = artistProviderIds;
        return this;
    }

    public AlbumInfo putArtistProviderIdsItem(String key, String artistProviderIdsItem) {
        if (this.artistProviderIds == null) {
            this.artistProviderIds = new HashMap<>();
        }
        this.artistProviderIds.put(key, artistProviderIdsItem);
        return this;
    }

    /**
     * Gets or sets the artist provider ids.
     * 
     * @return artistProviderIds
     */
    @JsonProperty(value = JSON_PROPERTY_ARTIST_PROVIDER_IDS)
    @JsonInclude(content = JsonInclude.Include.ALWAYS)
    public @org.eclipse.jdt.annotation.Nullable Map<String, String> getArtistProviderIds() {
        return artistProviderIds;
    }

    @JsonProperty(value = JSON_PROPERTY_ARTIST_PROVIDER_IDS)
    @JsonInclude(content = JsonInclude.Include.ALWAYS)
    public void setArtistProviderIds(@org.eclipse.jdt.annotation.Nullable Map<String, String> artistProviderIds) {
        this.artistProviderIds = artistProviderIds;
    }

    public AlbumInfo songInfos(@org.eclipse.jdt.annotation.Nullable List<SongInfo> songInfos) {
        this.songInfos = songInfos;
        return this;
    }

    public AlbumInfo addSongInfosItem(SongInfo songInfosItem) {
        if (this.songInfos == null) {
            this.songInfos = new ArrayList<>();
        }
        this.songInfos.add(songInfosItem);
        return this;
    }

    /**
     * Get songInfos
     * 
     * @return songInfos
     */
    @JsonProperty(value = JSON_PROPERTY_SONG_INFOS)
    public @org.eclipse.jdt.annotation.Nullable List<SongInfo> getSongInfos() {
        return songInfos;
    }

    @JsonProperty(value = JSON_PROPERTY_SONG_INFOS)
    public void setSongInfos(@org.eclipse.jdt.annotation.Nullable List<SongInfo> songInfos) {
        this.songInfos = songInfos;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        AlbumInfo albumInfo = (AlbumInfo) o;
        return Objects.equals(this.name, albumInfo.name) && Objects.equals(this.originalTitle, albumInfo.originalTitle)
                && Objects.equals(this.path, albumInfo.path)
                && Objects.equals(this.metadataLanguage, albumInfo.metadataLanguage)
                && Objects.equals(this.metadataCountryCode, albumInfo.metadataCountryCode)
                && Objects.equals(this.providerIds, albumInfo.providerIds) && Objects.equals(this.year, albumInfo.year)
                && Objects.equals(this.indexNumber, albumInfo.indexNumber)
                && Objects.equals(this.parentIndexNumber, albumInfo.parentIndexNumber)
                && Objects.equals(this.premiereDate, albumInfo.premiereDate)
                && Objects.equals(this.isAutomated, albumInfo.isAutomated)
                && Objects.equals(this.albumArtists, albumInfo.albumArtists)
                && Objects.equals(this.artistProviderIds, albumInfo.artistProviderIds)
                && Objects.equals(this.songInfos, albumInfo.songInfos);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, originalTitle, path, metadataLanguage, metadataCountryCode, providerIds, year,
                indexNumber, parentIndexNumber, premiereDate, isAutomated, albumArtists, artistProviderIds, songInfos);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append("class AlbumInfo {\n");
        sb.append("    name: ").append(toIndentedString(name)).append("\n");
        sb.append("    originalTitle: ").append(toIndentedString(originalTitle)).append("\n");
        sb.append("    path: ").append(toIndentedString(path)).append("\n");
        sb.append("    metadataLanguage: ").append(toIndentedString(metadataLanguage)).append("\n");
        sb.append("    metadataCountryCode: ").append(toIndentedString(metadataCountryCode)).append("\n");
        sb.append("    providerIds: ").append(toIndentedString(providerIds)).append("\n");
        sb.append("    year: ").append(toIndentedString(year)).append("\n");
        sb.append("    indexNumber: ").append(toIndentedString(indexNumber)).append("\n");
        sb.append("    parentIndexNumber: ").append(toIndentedString(parentIndexNumber)).append("\n");
        sb.append("    premiereDate: ").append(toIndentedString(premiereDate)).append("\n");
        sb.append("    isAutomated: ").append(toIndentedString(isAutomated)).append("\n");
        sb.append("    albumArtists: ").append(toIndentedString(albumArtists)).append("\n");
        sb.append("    artistProviderIds: ").append(toIndentedString(artistProviderIds)).append("\n");
        sb.append("    songInfos: ").append(toIndentedString(songInfos)).append("\n");
        sb.append("}");
        return sb.toString();
    }

    /**
     * Convert the given object to string with each line indented by 4 spaces
     * (except the first line).
     */
    private String toIndentedString(Object o) {
        return o == null ? "null" : o.toString().replace("\n", "\n    ");
    }

    /**
     * Convert the instance into URL query string.
     *
     * @return URL query string
     */
    public String toUrlQueryString() {
        return toUrlQueryString(null);
    }

    /**
     * Convert the instance into URL query string.
     *
     * @param prefix prefix of the query string
     * @return URL query string
     */
    public String toUrlQueryString(String prefix) {
        String suffix = "";
        String containerSuffix = "";
        String containerPrefix = "";
        if (prefix == null) {
            // style=form, explode=true, e.g. /pet?name=cat&type=manx
            prefix = "";
        } else {
            // deepObject style e.g. /pet?id[name]=cat&id[type]=manx
            prefix = prefix + "[";
            suffix = "]";
            containerSuffix = "]";
            containerPrefix = "[";
        }

        StringJoiner joiner = new StringJoiner("&");

        // add `Name` to the URL query string
        if (getName() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sName%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getName()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `OriginalTitle` to the URL query string
        if (getOriginalTitle() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sOriginalTitle%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getOriginalTitle()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `Path` to the URL query string
        if (getPath() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sPath%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getPath()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `MetadataLanguage` to the URL query string
        if (getMetadataLanguage() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sMetadataLanguage%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getMetadataLanguage()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `MetadataCountryCode` to the URL query string
        if (getMetadataCountryCode() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sMetadataCountryCode%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getMetadataCountryCode()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `ProviderIds` to the URL query string
        if (getProviderIds() != null) {
            for (String _key : getProviderIds().keySet()) {
                try {
                    joiner.add(String.format(java.util.Locale.ROOT, "%sProviderIds%s%s=%s", prefix, suffix,
                            "".equals(suffix) ? ""
                                    : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, _key,
                                            containerSuffix),
                            getProviderIds().get(_key),
                            URLEncoder.encode(String.valueOf(getProviderIds().get(_key)), "UTF-8").replaceAll("\\+",
                                    "%20")));
                } catch (UnsupportedEncodingException e) {
                    // Should never happen, UTF-8 is always supported
                    throw new RuntimeException(e);
                }
            }
        }

        // add `Year` to the URL query string
        if (getYear() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sYear%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getYear()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `IndexNumber` to the URL query string
        if (getIndexNumber() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sIndexNumber%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getIndexNumber()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `ParentIndexNumber` to the URL query string
        if (getParentIndexNumber() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sParentIndexNumber%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getParentIndexNumber()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `PremiereDate` to the URL query string
        if (getPremiereDate() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sPremiereDate%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getPremiereDate()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `IsAutomated` to the URL query string
        if (getIsAutomated() != null) {
            try {
                joiner.add(String.format(java.util.Locale.ROOT, "%sIsAutomated%s=%s", prefix, suffix,
                        URLEncoder.encode(String.valueOf(getIsAutomated()), "UTF-8").replaceAll("\\+", "%20")));
            } catch (UnsupportedEncodingException e) {
                // Should never happen, UTF-8 is always supported
                throw new RuntimeException(e);
            }
        }

        // add `AlbumArtists` to the URL query string
        if (getAlbumArtists() != null) {
            for (int i = 0; i < getAlbumArtists().size(); i++) {
                try {
                    joiner.add(String.format(java.util.Locale.ROOT, "%sAlbumArtists%s%s=%s", prefix, suffix,
                            "".equals(suffix) ? ""
                                    : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, i,
                                            containerSuffix),
                            URLEncoder.encode(String.valueOf(getAlbumArtists().get(i)), "UTF-8").replaceAll("\\+",
                                    "%20")));
                } catch (UnsupportedEncodingException e) {
                    // Should never happen, UTF-8 is always supported
                    throw new RuntimeException(e);
                }
            }
        }

        // add `ArtistProviderIds` to the URL query string
        if (getArtistProviderIds() != null) {
            for (String _key : getArtistProviderIds().keySet()) {
                try {
                    joiner.add(String.format(java.util.Locale.ROOT, "%sArtistProviderIds%s%s=%s", prefix, suffix,
                            "".equals(suffix) ? ""
                                    : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, _key,
                                            containerSuffix),
                            getArtistProviderIds().get(_key),
                            URLEncoder.encode(String.valueOf(getArtistProviderIds().get(_key)), "UTF-8")
                                    .replaceAll("\\+", "%20")));
                } catch (UnsupportedEncodingException e) {
                    // Should never happen, UTF-8 is always supported
                    throw new RuntimeException(e);
                }
            }
        }

        // add `SongInfos` to the URL query string
        if (getSongInfos() != null) {
            for (int i = 0; i < getSongInfos().size(); i++) {
                if (getSongInfos().get(i) != null) {
                    joiner.add(getSongInfos().get(i)
                            .toUrlQueryString(String.format(java.util.Locale.ROOT, "%sSongInfos%s%s", prefix, suffix,
                                    "".equals(suffix) ? ""
                                            : String.format(java.util.Locale.ROOT, "%s%d%s", containerPrefix, i,
                                                    containerSuffix))));
                }
            }
        }

        return joiner.toString();
    }

    public static class Builder {

        private AlbumInfo instance;

        public Builder() {
            this(new AlbumInfo());
        }

        protected Builder(AlbumInfo instance) {
            this.instance = instance;
        }

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

        public AlbumInfo.Builder originalTitle(String originalTitle) {
            this.instance.originalTitle = originalTitle;
            return this;
        }

        public AlbumInfo.Builder path(String path) {
            this.instance.path = path;
            return this;
        }

        public AlbumInfo.Builder metadataLanguage(String metadataLanguage) {
            this.instance.metadataLanguage = metadataLanguage;
            return this;
        }

        public AlbumInfo.Builder metadataCountryCode(String metadataCountryCode) {
            this.instance.metadataCountryCode = metadataCountryCode;
            return this;
        }

        public AlbumInfo.Builder providerIds(Map<String, String> providerIds) {
            this.instance.providerIds = providerIds;
            return this;
        }

        public AlbumInfo.Builder year(Integer year) {
            this.instance.year = year;
            return this;
        }

        public AlbumInfo.Builder indexNumber(Integer indexNumber) {
            this.instance.indexNumber = indexNumber;
            return this;
        }

        public AlbumInfo.Builder parentIndexNumber(Integer parentIndexNumber) {
            this.instance.parentIndexNumber = parentIndexNumber;
            return this;
        }

        public AlbumInfo.Builder premiereDate(OffsetDateTime premiereDate) {
            this.instance.premiereDate = premiereDate;
            return this;
        }

        public AlbumInfo.Builder isAutomated(Boolean isAutomated) {
            this.instance.isAutomated = isAutomated;
            return this;
        }

        public AlbumInfo.Builder albumArtists(List<String> albumArtists) {
            this.instance.albumArtists = albumArtists;
            return this;
        }

        public AlbumInfo.Builder artistProviderIds(Map<String, String> artistProviderIds) {
            this.instance.artistProviderIds = artistProviderIds;
            return this;
        }

        public AlbumInfo.Builder songInfos(List<SongInfo> songInfos) {
            this.instance.songInfos = songInfos;
            return this;
        }

        /**
         * returns a built AlbumInfo instance.
         *
         * The builder is not reusable.
         */
        public AlbumInfo build() {
            try {
                return this.instance;
            } finally {
                // ensure that this.instance is not reused
                this.instance = null;
            }
        }

        @Override
        public String toString() {
            return getClass() + "=(" + instance + ")";
        }
    }

    /**
     * Create a builder with no initialized field.
     */
    public static AlbumInfo.Builder builder() {
        return new AlbumInfo.Builder();
    }

    /**
     * Create a builder with a shallow copy of this instance.
     */
    public AlbumInfo.Builder toBuilder() {
        return new AlbumInfo.Builder().name(getName()).originalTitle(getOriginalTitle()).path(getPath())
                .metadataLanguage(getMetadataLanguage()).metadataCountryCode(getMetadataCountryCode())
                .providerIds(getProviderIds()).year(getYear()).indexNumber(getIndexNumber())
                .parentIndexNumber(getParentIndexNumber()).premiereDate(getPremiereDate()).isAutomated(getIsAutomated())
                .albumArtists(getAlbumArtists()).artistProviderIds(getArtistProviderIds()).songInfos(getSongInfos());
    }
}
