using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Cepis;
///
/// A CEP and everything the database knows about it.
///
///
///
/// The property names are the API's own, in Portuguese, with only the casing
/// adapted to C#. Everything else in this library is English; the data fields
/// are the one deliberate exception, so that what you read in the JSON at
/// https://cep.is/01001000 is what you access on the object. The
/// mapping from wire name to property is:
///
///
/// wireproperty
/// - cep
/// - logradouro
/// - complemento
/// - unidade
/// - bairro
/// - localidade
/// - uf
/// - estado
/// - regiao
/// - ibge
/// - gia
/// - ddd
/// - siafi
/// - geo
///
///
/// Fields the database does not have for that CEP come back as empty strings,
/// never — that is what the API returns.
///
///
/// is the exception: it is when there
/// is no coordinate. There the difference is real, because the API omits
/// the whole field in that case (about 43% of CEPs) rather than sending null.
/// It is also always for an address that came from
/// ,
/// which carries no coordinate at all.
///
///
/// holds any field the API has grown that this version of
/// the library does not model, so an outdated client loses nothing. It takes no
/// part in equality, hashing or : two addresses
/// describing the same place are equal even if one of them was built by hand.
///
///
public sealed record Address
{
/// The eight digits, always unmasked. Wire name cep.
[JsonPropertyName("cep")]
public string Cep { get; init; } = "";
/// The street. Wire name logradouro.
[JsonPropertyName("logradouro")]
public string Logradouro { get; init; } = "";
///
/// The qualifier on the street, such as a range of numbers. Wire name
/// complemento.
///
[JsonPropertyName("complemento")]
public string Complemento { get; init; } = "";
///
/// The named unit, for a CEP that belongs to one. Wire name unidade.
///
[JsonPropertyName("unidade")]
public string Unidade { get; init; } = "";
/// The neighbourhood. Wire name bairro.
[JsonPropertyName("bairro")]
public string Bairro { get; init; } = "";
/// The municipality. Wire name localidade.
[JsonPropertyName("localidade")]
public string Localidade { get; init; } = "";
/// The two-letter state code. Wire name uf.
[JsonPropertyName("uf")]
public string UF { get; init; } = "";
/// The state's name. Wire name estado.
[JsonPropertyName("estado")]
public string Estado { get; init; } = "";
/// The region of the country. Wire name regiao.
[JsonPropertyName("regiao")]
public string Regiao { get; init; } = "";
/// The IBGE municipality code. Wire name ibge.
[JsonPropertyName("ibge")]
public string Ibge { get; init; } = "";
/// The GIA code, São Paulo only. Wire name gia.
[JsonPropertyName("gia")]
public string Gia { get; init; } = "";
/// The telephone area code. Wire name ddd.
[JsonPropertyName("ddd")]
public string Ddd { get; init; } = "";
/// The SIAFI municipality code. Wire name siafi.
[JsonPropertyName("siafi")]
public string Siafi { get; init; } = "";
///
/// The coordinate, or when there is none. Wire name
/// geo.
///
///
/// A malformed geo block yields rather than
/// failing the whole response: the rest of the address is still useful.
///
[JsonPropertyName("geo")]
[JsonConverter(typeof(GeoConverter))]
public Geo? Geo { get; init; }
///
/// Fields the API returned that this version of the library does not model.
///
///
/// A new field in the API therefore cannot break this client, and cannot be
/// silently dropped either. Empty for an address built by hand.
///
[JsonExtensionData]
public Dictionary? Extra { get; init; }
/// The CEP with its mask, 01001-000.
///
/// The API always returns it unmasked; formatting is presentation, and it
/// lives here so it does not become a repeated interpolation in every
/// project that uses this library. A CEP that is not eight characters long
/// is returned unchanged.
///
[JsonIgnore]
public string FormattedCep => Cep.Length == 8 ? $"{Cep[..5]}-{Cep[5..]}" : Cep;
/// Compare every field but .
/// the address to compare with
/// when both describe the same place
public bool Equals(Address? other) =>
other is not null
&& Cep == other.Cep
&& Logradouro == other.Logradouro
&& Complemento == other.Complemento
&& Unidade == other.Unidade
&& Bairro == other.Bairro
&& Localidade == other.Localidade
&& UF == other.UF
&& Estado == other.Estado
&& Regiao == other.Regiao
&& Ibge == other.Ibge
&& Gia == other.Gia
&& Ddd == other.Ddd
&& Siafi == other.Siafi
&& Geo == other.Geo;
/// Hash every field but .
/// a hash consistent with
public override int GetHashCode()
{
var hash = default(HashCode);
hash.Add(Cep);
hash.Add(Logradouro);
hash.Add(Complemento);
hash.Add(Unidade);
hash.Add(Bairro);
hash.Add(Localidade);
hash.Add(UF);
hash.Add(Estado);
hash.Add(Regiao);
hash.Add(Ibge);
hash.Add(Gia);
hash.Add(Ddd);
hash.Add(Siafi);
hash.Add(Geo);
return hash.ToHashCode();
}
private bool PrintMembers(StringBuilder builder)
{
builder.Append("Cep = ").Append(Cep)
.Append(", Logradouro = ").Append(Logradouro)
.Append(", Complemento = ").Append(Complemento)
.Append(", Unidade = ").Append(Unidade)
.Append(", Bairro = ").Append(Bairro)
.Append(", Localidade = ").Append(Localidade)
.Append(", UF = ").Append(UF)
.Append(", Estado = ").Append(Estado)
.Append(", Regiao = ").Append(Regiao)
.Append(", Ibge = ").Append(Ibge)
.Append(", Gia = ").Append(Gia)
.Append(", Ddd = ").Append(Ddd)
.Append(", Siafi = ").Append(Siafi)
.Append(", Geo = ").Append(Geo?.ToString() ?? "null");
return true;
}
}