/*
 * Daytona
 * Daytona AI platform API Docs
 *
 * The version of the OpenAPI document: 1.0
 * Contact: support@daytona.com
 *
 * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
 * https://openapi-generator.tech
 * Do not edit the class manually.
 */


package io.daytona.api.client.model;

import java.util.Objects;
import com.google.gson.TypeAdapter;
import com.google.gson.annotations.JsonAdapter;
import com.google.gson.annotations.SerializedName;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import io.daytona.api.client.model.Announcement;
import io.daytona.api.client.model.OidcConfig;
import io.daytona.api.client.model.PosthogConfig;
import io.daytona.api.client.model.RateLimitConfig;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import io.daytona.api.client.JSON;

/**
 * DaytonaConfiguration
 */
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.21.0")
public class DaytonaConfiguration {
  public static final String SERIALIZED_NAME_VERSION = "version";
  @SerializedName(SERIALIZED_NAME_VERSION)
  @javax.annotation.Nonnull
  private String version;

  public static final String SERIALIZED_NAME_POSTHOG = "posthog";
  @SerializedName(SERIALIZED_NAME_POSTHOG)
  @javax.annotation.Nullable
  private PosthogConfig posthog;

  public static final String SERIALIZED_NAME_OIDC = "oidc";
  @SerializedName(SERIALIZED_NAME_OIDC)
  @javax.annotation.Nonnull
  private OidcConfig oidc;

  public static final String SERIALIZED_NAME_LINKED_ACCOUNTS_ENABLED = "linkedAccountsEnabled";
  @SerializedName(SERIALIZED_NAME_LINKED_ACCOUNTS_ENABLED)
  @javax.annotation.Nonnull
  private Boolean linkedAccountsEnabled;

  public static final String SERIALIZED_NAME_ANNOUNCEMENTS = "announcements";
  @SerializedName(SERIALIZED_NAME_ANNOUNCEMENTS)
  @javax.annotation.Nonnull
  private Map<String, Announcement> announcements = new HashMap<>();

  public static final String SERIALIZED_NAME_PYLON_APP_ID = "pylonAppId";
  @SerializedName(SERIALIZED_NAME_PYLON_APP_ID)
  @javax.annotation.Nullable
  private String pylonAppId;

  public static final String SERIALIZED_NAME_PROXY_TEMPLATE_URL = "proxyTemplateUrl";
  @SerializedName(SERIALIZED_NAME_PROXY_TEMPLATE_URL)
  @javax.annotation.Nonnull
  private String proxyTemplateUrl;

  public static final String SERIALIZED_NAME_PROXY_TOOLBOX_URL = "proxyToolboxUrl";
  @SerializedName(SERIALIZED_NAME_PROXY_TOOLBOX_URL)
  @javax.annotation.Nonnull
  private String proxyToolboxUrl;

  public static final String SERIALIZED_NAME_DEFAULT_SNAPSHOT = "defaultSnapshot";
  @SerializedName(SERIALIZED_NAME_DEFAULT_SNAPSHOT)
  @javax.annotation.Nonnull
  private String defaultSnapshot;

  public static final String SERIALIZED_NAME_DASHBOARD_URL = "dashboardUrl";
  @SerializedName(SERIALIZED_NAME_DASHBOARD_URL)
  @javax.annotation.Nonnull
  private String dashboardUrl;

  public static final String SERIALIZED_NAME_MAX_AUTO_ARCHIVE_INTERVAL = "maxAutoArchiveInterval";
  @SerializedName(SERIALIZED_NAME_MAX_AUTO_ARCHIVE_INTERVAL)
  @javax.annotation.Nonnull
  private BigDecimal maxAutoArchiveInterval;

  public static final String SERIALIZED_NAME_MAINTANANCE_MODE = "maintananceMode";
  @SerializedName(SERIALIZED_NAME_MAINTANANCE_MODE)
  @javax.annotation.Nonnull
  private Boolean maintananceMode;

  public static final String SERIALIZED_NAME_ENVIRONMENT = "environment";
  @SerializedName(SERIALIZED_NAME_ENVIRONMENT)
  @javax.annotation.Nonnull
  private String environment;

  public static final String SERIALIZED_NAME_BILLING_API_URL = "billingApiUrl";
  @SerializedName(SERIALIZED_NAME_BILLING_API_URL)
  @javax.annotation.Nullable
  private String billingApiUrl;

  public static final String SERIALIZED_NAME_ANALYTICS_API_URL = "analyticsApiUrl";
  @SerializedName(SERIALIZED_NAME_ANALYTICS_API_URL)
  @javax.annotation.Nullable
  private String analyticsApiUrl;

  public static final String SERIALIZED_NAME_SSH_GATEWAY_COMMAND = "sshGatewayCommand";
  @SerializedName(SERIALIZED_NAME_SSH_GATEWAY_COMMAND)
  @javax.annotation.Nullable
  private String sshGatewayCommand;

  public static final String SERIALIZED_NAME_SSH_GATEWAY_PUBLIC_KEY = "sshGatewayPublicKey";
  @SerializedName(SERIALIZED_NAME_SSH_GATEWAY_PUBLIC_KEY)
  @javax.annotation.Nullable
  private String sshGatewayPublicKey;

  public static final String SERIALIZED_NAME_RATE_LIMIT = "rateLimit";
  @SerializedName(SERIALIZED_NAME_RATE_LIMIT)
  @javax.annotation.Nullable
  private RateLimitConfig rateLimit;

  public DaytonaConfiguration() {
  }

  public DaytonaConfiguration version(@javax.annotation.Nonnull String version) {
    this.version = version;
    return this;
  }

  /**
   * Daytona version
   * @return version
   */
  @javax.annotation.Nonnull
  public String getVersion() {
    return version;
  }

  public void setVersion(@javax.annotation.Nonnull String version) {
    this.version = version;
  }


  public DaytonaConfiguration posthog(@javax.annotation.Nullable PosthogConfig posthog) {
    this.posthog = posthog;
    return this;
  }

  /**
   * PostHog configuration
   * @return posthog
   */
  @javax.annotation.Nullable
  public PosthogConfig getPosthog() {
    return posthog;
  }

  public void setPosthog(@javax.annotation.Nullable PosthogConfig posthog) {
    this.posthog = posthog;
  }


  public DaytonaConfiguration oidc(@javax.annotation.Nonnull OidcConfig oidc) {
    this.oidc = oidc;
    return this;
  }

  /**
   * OIDC configuration
   * @return oidc
   */
  @javax.annotation.Nonnull
  public OidcConfig getOidc() {
    return oidc;
  }

  public void setOidc(@javax.annotation.Nonnull OidcConfig oidc) {
    this.oidc = oidc;
  }


  public DaytonaConfiguration linkedAccountsEnabled(@javax.annotation.Nonnull Boolean linkedAccountsEnabled) {
    this.linkedAccountsEnabled = linkedAccountsEnabled;
    return this;
  }

  /**
   * Whether linked accounts are enabled
   * @return linkedAccountsEnabled
   */
  @javax.annotation.Nonnull
  public Boolean getLinkedAccountsEnabled() {
    return linkedAccountsEnabled;
  }

  public void setLinkedAccountsEnabled(@javax.annotation.Nonnull Boolean linkedAccountsEnabled) {
    this.linkedAccountsEnabled = linkedAccountsEnabled;
  }


  public DaytonaConfiguration announcements(@javax.annotation.Nonnull Map<String, Announcement> announcements) {
    this.announcements = announcements;
    return this;
  }

  public DaytonaConfiguration putAnnouncementsItem(String key, Announcement announcementsItem) {
    if (this.announcements == null) {
      this.announcements = new HashMap<>();
    }
    this.announcements.put(key, announcementsItem);
    return this;
  }

  /**
   * System announcements
   * @return announcements
   */
  @javax.annotation.Nonnull
  public Map<String, Announcement> getAnnouncements() {
    return announcements;
  }

  public void setAnnouncements(@javax.annotation.Nonnull Map<String, Announcement> announcements) {
    this.announcements = announcements;
  }


  public DaytonaConfiguration pylonAppId(@javax.annotation.Nullable String pylonAppId) {
    this.pylonAppId = pylonAppId;
    return this;
  }

  /**
   * Pylon application ID
   * @return pylonAppId
   */
  @javax.annotation.Nullable
  public String getPylonAppId() {
    return pylonAppId;
  }

  public void setPylonAppId(@javax.annotation.Nullable String pylonAppId) {
    this.pylonAppId = pylonAppId;
  }


  public DaytonaConfiguration proxyTemplateUrl(@javax.annotation.Nonnull String proxyTemplateUrl) {
    this.proxyTemplateUrl = proxyTemplateUrl;
    return this;
  }

  /**
   * Proxy template URL
   * @return proxyTemplateUrl
   */
  @javax.annotation.Nonnull
  public String getProxyTemplateUrl() {
    return proxyTemplateUrl;
  }

  public void setProxyTemplateUrl(@javax.annotation.Nonnull String proxyTemplateUrl) {
    this.proxyTemplateUrl = proxyTemplateUrl;
  }


  public DaytonaConfiguration proxyToolboxUrl(@javax.annotation.Nonnull String proxyToolboxUrl) {
    this.proxyToolboxUrl = proxyToolboxUrl;
    return this;
  }

  /**
   * Toolbox template URL
   * @return proxyToolboxUrl
   */
  @javax.annotation.Nonnull
  public String getProxyToolboxUrl() {
    return proxyToolboxUrl;
  }

  public void setProxyToolboxUrl(@javax.annotation.Nonnull String proxyToolboxUrl) {
    this.proxyToolboxUrl = proxyToolboxUrl;
  }


  public DaytonaConfiguration defaultSnapshot(@javax.annotation.Nonnull String defaultSnapshot) {
    this.defaultSnapshot = defaultSnapshot;
    return this;
  }

  /**
   * Default snapshot for sandboxes
   * @return defaultSnapshot
   */
  @javax.annotation.Nonnull
  public String getDefaultSnapshot() {
    return defaultSnapshot;
  }

  public void setDefaultSnapshot(@javax.annotation.Nonnull String defaultSnapshot) {
    this.defaultSnapshot = defaultSnapshot;
  }


  public DaytonaConfiguration dashboardUrl(@javax.annotation.Nonnull String dashboardUrl) {
    this.dashboardUrl = dashboardUrl;
    return this;
  }

  /**
   * Dashboard URL
   * @return dashboardUrl
   */
  @javax.annotation.Nonnull
  public String getDashboardUrl() {
    return dashboardUrl;
  }

  public void setDashboardUrl(@javax.annotation.Nonnull String dashboardUrl) {
    this.dashboardUrl = dashboardUrl;
  }


  public DaytonaConfiguration maxAutoArchiveInterval(@javax.annotation.Nonnull BigDecimal maxAutoArchiveInterval) {
    this.maxAutoArchiveInterval = maxAutoArchiveInterval;
    return this;
  }

  /**
   * Maximum auto-archive interval in minutes
   * @return maxAutoArchiveInterval
   */
  @javax.annotation.Nonnull
  public BigDecimal getMaxAutoArchiveInterval() {
    return maxAutoArchiveInterval;
  }

  public void setMaxAutoArchiveInterval(@javax.annotation.Nonnull BigDecimal maxAutoArchiveInterval) {
    this.maxAutoArchiveInterval = maxAutoArchiveInterval;
  }


  public DaytonaConfiguration maintananceMode(@javax.annotation.Nonnull Boolean maintananceMode) {
    this.maintananceMode = maintananceMode;
    return this;
  }

  /**
   * Whether maintenance mode is enabled
   * @return maintananceMode
   */
  @javax.annotation.Nonnull
  public Boolean getMaintananceMode() {
    return maintananceMode;
  }

  public void setMaintananceMode(@javax.annotation.Nonnull Boolean maintananceMode) {
    this.maintananceMode = maintananceMode;
  }


  public DaytonaConfiguration environment(@javax.annotation.Nonnull String environment) {
    this.environment = environment;
    return this;
  }

  /**
   * Current environment
   * @return environment
   */
  @javax.annotation.Nonnull
  public String getEnvironment() {
    return environment;
  }

  public void setEnvironment(@javax.annotation.Nonnull String environment) {
    this.environment = environment;
  }


  public DaytonaConfiguration billingApiUrl(@javax.annotation.Nullable String billingApiUrl) {
    this.billingApiUrl = billingApiUrl;
    return this;
  }

  /**
   * Billing API URL
   * @return billingApiUrl
   */
  @javax.annotation.Nullable
  public String getBillingApiUrl() {
    return billingApiUrl;
  }

  public void setBillingApiUrl(@javax.annotation.Nullable String billingApiUrl) {
    this.billingApiUrl = billingApiUrl;
  }


  public DaytonaConfiguration analyticsApiUrl(@javax.annotation.Nullable String analyticsApiUrl) {
    this.analyticsApiUrl = analyticsApiUrl;
    return this;
  }

  /**
   * Analytics API URL
   * @return analyticsApiUrl
   */
  @javax.annotation.Nullable
  public String getAnalyticsApiUrl() {
    return analyticsApiUrl;
  }

  public void setAnalyticsApiUrl(@javax.annotation.Nullable String analyticsApiUrl) {
    this.analyticsApiUrl = analyticsApiUrl;
  }


  public DaytonaConfiguration sshGatewayCommand(@javax.annotation.Nullable String sshGatewayCommand) {
    this.sshGatewayCommand = sshGatewayCommand;
    return this;
  }

  /**
   * SSH Gateway command
   * @return sshGatewayCommand
   */
  @javax.annotation.Nullable
  public String getSshGatewayCommand() {
    return sshGatewayCommand;
  }

  public void setSshGatewayCommand(@javax.annotation.Nullable String sshGatewayCommand) {
    this.sshGatewayCommand = sshGatewayCommand;
  }


  public DaytonaConfiguration sshGatewayPublicKey(@javax.annotation.Nullable String sshGatewayPublicKey) {
    this.sshGatewayPublicKey = sshGatewayPublicKey;
    return this;
  }

  /**
   * Base64 encoded SSH Gateway public key
   * @return sshGatewayPublicKey
   */
  @javax.annotation.Nullable
  public String getSshGatewayPublicKey() {
    return sshGatewayPublicKey;
  }

  public void setSshGatewayPublicKey(@javax.annotation.Nullable String sshGatewayPublicKey) {
    this.sshGatewayPublicKey = sshGatewayPublicKey;
  }


  public DaytonaConfiguration rateLimit(@javax.annotation.Nullable RateLimitConfig rateLimit) {
    this.rateLimit = rateLimit;
    return this;
  }

  /**
   * Rate limit configuration
   * @return rateLimit
   */
  @javax.annotation.Nullable
  public RateLimitConfig getRateLimit() {
    return rateLimit;
  }

  public void setRateLimit(@javax.annotation.Nullable RateLimitConfig rateLimit) {
    this.rateLimit = rateLimit;
  }

  /**
   * A container for additional, undeclared properties.
   * This is a holder for any undeclared properties as specified with
   * the 'additionalProperties' keyword in the OAS document.
   */
  private Map<String, Object> additionalProperties;

  /**
   * Set the additional (undeclared) property with the specified name and value.
   * If the property does not already exist, create it otherwise replace it.
   *
   * @param key name of the property
   * @param value value of the property
   * @return the DaytonaConfiguration instance itself
   */
  public DaytonaConfiguration putAdditionalProperty(String key, Object value) {
    if (this.additionalProperties == null) {
        this.additionalProperties = new HashMap<String, Object>();
    }
    this.additionalProperties.put(key, value);
    return this;
  }

  /**
   * Return the additional (undeclared) property.
   *
   * @return a map of objects
   */
  public Map<String, Object> getAdditionalProperties() {
    return additionalProperties;
  }

  /**
   * Return the additional (undeclared) property with the specified name.
   *
   * @param key name of the property
   * @return an object
   */
  public Object getAdditionalProperty(String key) {
    if (this.additionalProperties == null) {
        return null;
    }
    return this.additionalProperties.get(key);
  }


  @Override
  public boolean equals(Object o) {
    if (this == o) {
      return true;
    }
    if (o == null || getClass() != o.getClass()) {
      return false;
    }
    DaytonaConfiguration daytonaConfiguration = (DaytonaConfiguration) o;
    return Objects.equals(this.version, daytonaConfiguration.version) &&
        Objects.equals(this.posthog, daytonaConfiguration.posthog) &&
        Objects.equals(this.oidc, daytonaConfiguration.oidc) &&
        Objects.equals(this.linkedAccountsEnabled, daytonaConfiguration.linkedAccountsEnabled) &&
        Objects.equals(this.announcements, daytonaConfiguration.announcements) &&
        Objects.equals(this.pylonAppId, daytonaConfiguration.pylonAppId) &&
        Objects.equals(this.proxyTemplateUrl, daytonaConfiguration.proxyTemplateUrl) &&
        Objects.equals(this.proxyToolboxUrl, daytonaConfiguration.proxyToolboxUrl) &&
        Objects.equals(this.defaultSnapshot, daytonaConfiguration.defaultSnapshot) &&
        Objects.equals(this.dashboardUrl, daytonaConfiguration.dashboardUrl) &&
        Objects.equals(this.maxAutoArchiveInterval, daytonaConfiguration.maxAutoArchiveInterval) &&
        Objects.equals(this.maintananceMode, daytonaConfiguration.maintananceMode) &&
        Objects.equals(this.environment, daytonaConfiguration.environment) &&
        Objects.equals(this.billingApiUrl, daytonaConfiguration.billingApiUrl) &&
        Objects.equals(this.analyticsApiUrl, daytonaConfiguration.analyticsApiUrl) &&
        Objects.equals(this.sshGatewayCommand, daytonaConfiguration.sshGatewayCommand) &&
        Objects.equals(this.sshGatewayPublicKey, daytonaConfiguration.sshGatewayPublicKey) &&
        Objects.equals(this.rateLimit, daytonaConfiguration.rateLimit)&&
        Objects.equals(this.additionalProperties, daytonaConfiguration.additionalProperties);
  }

  @Override
  public int hashCode() {
    return Objects.hash(version, posthog, oidc, linkedAccountsEnabled, announcements, pylonAppId, proxyTemplateUrl, proxyToolboxUrl, defaultSnapshot, dashboardUrl, maxAutoArchiveInterval, maintananceMode, environment, billingApiUrl, analyticsApiUrl, sshGatewayCommand, sshGatewayPublicKey, rateLimit, additionalProperties);
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder();
    sb.append("class DaytonaConfiguration {\n");
    sb.append("    version: ").append(toIndentedString(version)).append("\n");
    sb.append("    posthog: ").append(toIndentedString(posthog)).append("\n");
    sb.append("    oidc: ").append(toIndentedString(oidc)).append("\n");
    sb.append("    linkedAccountsEnabled: ").append(toIndentedString(linkedAccountsEnabled)).append("\n");
    sb.append("    announcements: ").append(toIndentedString(announcements)).append("\n");
    sb.append("    pylonAppId: ").append(toIndentedString(pylonAppId)).append("\n");
    sb.append("    proxyTemplateUrl: ").append(toIndentedString(proxyTemplateUrl)).append("\n");
    sb.append("    proxyToolboxUrl: ").append(toIndentedString(proxyToolboxUrl)).append("\n");
    sb.append("    defaultSnapshot: ").append(toIndentedString(defaultSnapshot)).append("\n");
    sb.append("    dashboardUrl: ").append(toIndentedString(dashboardUrl)).append("\n");
    sb.append("    maxAutoArchiveInterval: ").append(toIndentedString(maxAutoArchiveInterval)).append("\n");
    sb.append("    maintananceMode: ").append(toIndentedString(maintananceMode)).append("\n");
    sb.append("    environment: ").append(toIndentedString(environment)).append("\n");
    sb.append("    billingApiUrl: ").append(toIndentedString(billingApiUrl)).append("\n");
    sb.append("    analyticsApiUrl: ").append(toIndentedString(analyticsApiUrl)).append("\n");
    sb.append("    sshGatewayCommand: ").append(toIndentedString(sshGatewayCommand)).append("\n");
    sb.append("    sshGatewayPublicKey: ").append(toIndentedString(sshGatewayPublicKey)).append("\n");
    sb.append("    rateLimit: ").append(toIndentedString(rateLimit)).append("\n");
    sb.append("    additionalProperties: ").append(toIndentedString(additionalProperties)).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    ");
  }


  public static HashSet<String> openapiFields;
  public static HashSet<String> openapiRequiredFields;

  static {
    // a set of all properties/fields (JSON key names)
    openapiFields = new HashSet<String>(Arrays.asList("version", "posthog", "oidc", "linkedAccountsEnabled", "announcements", "pylonAppId", "proxyTemplateUrl", "proxyToolboxUrl", "defaultSnapshot", "dashboardUrl", "maxAutoArchiveInterval", "maintananceMode", "environment", "billingApiUrl", "analyticsApiUrl", "sshGatewayCommand", "sshGatewayPublicKey", "rateLimit"));

    // a set of required properties/fields (JSON key names)
    openapiRequiredFields = new HashSet<String>(Arrays.asList("version", "oidc", "linkedAccountsEnabled", "announcements", "proxyTemplateUrl", "proxyToolboxUrl", "defaultSnapshot", "dashboardUrl", "maxAutoArchiveInterval", "maintananceMode", "environment"));
  }

  /**
   * Validates the JSON Element and throws an exception if issues found
   *
   * @param jsonElement JSON Element
   * @throws IOException if the JSON Element is invalid with respect to DaytonaConfiguration
   */
  public static void validateJsonElement(JsonElement jsonElement) throws IOException {
      if (jsonElement == null) {
        if (!DaytonaConfiguration.openapiRequiredFields.isEmpty()) { // has required fields but JSON element is null
          throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "The required field(s) %s in DaytonaConfiguration is not found in the empty JSON string", DaytonaConfiguration.openapiRequiredFields.toString()));
        }
      }

      // check to make sure all required properties/fields are present in the JSON string
      for (String requiredField : DaytonaConfiguration.openapiRequiredFields) {
        if (jsonElement.getAsJsonObject().get(requiredField) == null) {
          throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "The required field `%s` is not found in the JSON string: %s", requiredField, jsonElement.toString()));
        }
      }
        JsonObject jsonObj = jsonElement.getAsJsonObject();
      if (!jsonObj.get("version").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `version` to be a primitive type in the JSON string but got `%s`", jsonObj.get("version").toString()));
      }
      // validate the optional field `posthog`
      if (jsonObj.get("posthog") != null && !jsonObj.get("posthog").isJsonNull()) {
        PosthogConfig.validateJsonElement(jsonObj.get("posthog"));
      }
      // validate the required field `oidc`
      OidcConfig.validateJsonElement(jsonObj.get("oidc"));
      if ((jsonObj.get("pylonAppId") != null && !jsonObj.get("pylonAppId").isJsonNull()) && !jsonObj.get("pylonAppId").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `pylonAppId` to be a primitive type in the JSON string but got `%s`", jsonObj.get("pylonAppId").toString()));
      }
      if (!jsonObj.get("proxyTemplateUrl").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `proxyTemplateUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("proxyTemplateUrl").toString()));
      }
      if (!jsonObj.get("proxyToolboxUrl").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `proxyToolboxUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("proxyToolboxUrl").toString()));
      }
      if (!jsonObj.get("defaultSnapshot").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `defaultSnapshot` to be a primitive type in the JSON string but got `%s`", jsonObj.get("defaultSnapshot").toString()));
      }
      if (!jsonObj.get("dashboardUrl").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `dashboardUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("dashboardUrl").toString()));
      }
      if (!jsonObj.get("environment").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `environment` to be a primitive type in the JSON string but got `%s`", jsonObj.get("environment").toString()));
      }
      if ((jsonObj.get("billingApiUrl") != null && !jsonObj.get("billingApiUrl").isJsonNull()) && !jsonObj.get("billingApiUrl").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `billingApiUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("billingApiUrl").toString()));
      }
      if ((jsonObj.get("analyticsApiUrl") != null && !jsonObj.get("analyticsApiUrl").isJsonNull()) && !jsonObj.get("analyticsApiUrl").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `analyticsApiUrl` to be a primitive type in the JSON string but got `%s`", jsonObj.get("analyticsApiUrl").toString()));
      }
      if ((jsonObj.get("sshGatewayCommand") != null && !jsonObj.get("sshGatewayCommand").isJsonNull()) && !jsonObj.get("sshGatewayCommand").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `sshGatewayCommand` to be a primitive type in the JSON string but got `%s`", jsonObj.get("sshGatewayCommand").toString()));
      }
      if ((jsonObj.get("sshGatewayPublicKey") != null && !jsonObj.get("sshGatewayPublicKey").isJsonNull()) && !jsonObj.get("sshGatewayPublicKey").isJsonPrimitive()) {
        throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "Expected the field `sshGatewayPublicKey` to be a primitive type in the JSON string but got `%s`", jsonObj.get("sshGatewayPublicKey").toString()));
      }
      // validate the optional field `rateLimit`
      if (jsonObj.get("rateLimit") != null && !jsonObj.get("rateLimit").isJsonNull()) {
        RateLimitConfig.validateJsonElement(jsonObj.get("rateLimit"));
      }
  }

  public static class CustomTypeAdapterFactory implements TypeAdapterFactory {
    @SuppressWarnings("unchecked")
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
       if (!DaytonaConfiguration.class.isAssignableFrom(type.getRawType())) {
         return null; // this class only serializes 'DaytonaConfiguration' and its subtypes
       }
       final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);
       final TypeAdapter<DaytonaConfiguration> thisAdapter
                        = gson.getDelegateAdapter(this, TypeToken.get(DaytonaConfiguration.class));

       return (TypeAdapter<T>) new TypeAdapter<DaytonaConfiguration>() {
           @Override
           public void write(JsonWriter out, DaytonaConfiguration value) throws IOException {
             JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject();
             obj.remove("additionalProperties");
             // serialize additional properties
             if (value.getAdditionalProperties() != null) {
               for (Map.Entry<String, Object> entry : value.getAdditionalProperties().entrySet()) {
                 if (entry.getValue() instanceof String)
                   obj.addProperty(entry.getKey(), (String) entry.getValue());
                 else if (entry.getValue() instanceof Number)
                   obj.addProperty(entry.getKey(), (Number) entry.getValue());
                 else if (entry.getValue() instanceof Boolean)
                   obj.addProperty(entry.getKey(), (Boolean) entry.getValue());
                 else if (entry.getValue() instanceof Character)
                   obj.addProperty(entry.getKey(), (Character) entry.getValue());
                 else {
                   JsonElement jsonElement = gson.toJsonTree(entry.getValue());
                   if (jsonElement.isJsonArray()) {
                     obj.add(entry.getKey(), jsonElement.getAsJsonArray());
                   } else {
                     obj.add(entry.getKey(), jsonElement.getAsJsonObject());
                   }
                 }
               }
             }
             elementAdapter.write(out, obj);
           }

           @Override
           public DaytonaConfiguration read(JsonReader in) throws IOException {
             JsonElement jsonElement = elementAdapter.read(in);
             validateJsonElement(jsonElement);
             JsonObject jsonObj = jsonElement.getAsJsonObject();
             // store additional fields in the deserialized instance
             DaytonaConfiguration instance = thisAdapter.fromJsonTree(jsonObj);
             for (Map.Entry<String, JsonElement> entry : jsonObj.entrySet()) {
               if (!openapiFields.contains(entry.getKey())) {
                 if (entry.getValue().isJsonPrimitive()) { // primitive type
                   if (entry.getValue().getAsJsonPrimitive().isString())
                     instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsString());
                   else if (entry.getValue().getAsJsonPrimitive().isNumber())
                     instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsNumber());
                   else if (entry.getValue().getAsJsonPrimitive().isBoolean())
                     instance.putAdditionalProperty(entry.getKey(), entry.getValue().getAsBoolean());
                   else
                     throw new IllegalArgumentException(String.format(java.util.Locale.ROOT, "The field `%s` has unknown primitive type. Value: %s", entry.getKey(), entry.getValue().toString()));
                 } else if (entry.getValue().isJsonArray()) {
                     instance.putAdditionalProperty(entry.getKey(), gson.fromJson(entry.getValue(), List.class));
                 } else { // JSON object
                     instance.putAdditionalProperty(entry.getKey(), gson.fromJson(entry.getValue(), HashMap.class));
                 }
               }
             }
             return instance;
           }

       }.nullSafe();
    }
  }

  /**
   * Create an instance of DaytonaConfiguration given an JSON string
   *
   * @param jsonString JSON string
   * @return An instance of DaytonaConfiguration
   * @throws IOException if the JSON string is invalid with respect to DaytonaConfiguration
   */
  public static DaytonaConfiguration fromJson(String jsonString) throws IOException {
    return JSON.getGson().fromJson(jsonString, DaytonaConfiguration.class);
  }

  /**
   * Convert an instance of DaytonaConfiguration to an JSON string
   *
   * @return JSON string
   */
  public String toJson() {
    return JSON.getGson().toJson(this);
  }
}

