417 lines
9.5 KiB
C#
417 lines
9.5 KiB
C#
using OperationControl.Mapas.Models;
|
|
|
|
namespace OperationControl.Mapas.Services
|
|
{
|
|
public class MapaSelectionService
|
|
{
|
|
/// <summary>
|
|
/// Alterna o estado de seleção de uma rua.
|
|
///
|
|
/// Retorna true se a rua ficou selecionada.
|
|
/// Retorna false se a rua ficou desmarcada.
|
|
/// </summary>
|
|
public bool AlternarRua(
|
|
MapaDocumento documento,
|
|
MapaSelecaoOperacao selecao,
|
|
string ruaId)
|
|
{
|
|
ValidarArgumentos(
|
|
documento,
|
|
selecao
|
|
);
|
|
|
|
|
|
string id =
|
|
NormalizarId(
|
|
ruaId
|
|
);
|
|
|
|
|
|
GarantirRuaExistente(
|
|
documento,
|
|
id
|
|
);
|
|
|
|
|
|
if (selecao.RuasMutaveis.Contains(
|
|
id,
|
|
StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
RemoverRua(
|
|
documento,
|
|
selecao,
|
|
id
|
|
);
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
SelecionarRua(
|
|
documento,
|
|
selecao,
|
|
id
|
|
);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Seleciona uma rua e a coloca no final da ordem atual.
|
|
///
|
|
/// Se já estiver selecionada, nada é alterado.
|
|
/// </summary>
|
|
public bool SelecionarRua(
|
|
MapaDocumento documento,
|
|
MapaSelecaoOperacao selecao,
|
|
string ruaId)
|
|
{
|
|
ValidarArgumentos(
|
|
documento,
|
|
selecao
|
|
);
|
|
|
|
|
|
string id =
|
|
NormalizarId(
|
|
ruaId
|
|
);
|
|
|
|
|
|
GarantirRuaExistente(
|
|
documento,
|
|
id
|
|
);
|
|
|
|
|
|
if (selecao.RuasMutaveis.Contains(
|
|
id,
|
|
StringComparer.OrdinalIgnoreCase))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
selecao.RuasMutaveis.Add(
|
|
id
|
|
);
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Remove uma rua da seleção.
|
|
///
|
|
/// Como a ordem é representada pela própria posição
|
|
/// na lista, nenhuma renumeração manual é necessária.
|
|
/// </summary>
|
|
public bool RemoverRua(
|
|
MapaDocumento documento,
|
|
MapaSelecaoOperacao selecao,
|
|
string ruaId)
|
|
{
|
|
ValidarArgumentos(
|
|
documento,
|
|
selecao
|
|
);
|
|
|
|
|
|
string id =
|
|
NormalizarId(
|
|
ruaId
|
|
);
|
|
|
|
|
|
int indice =
|
|
selecao.RuasMutaveis.FindIndex(
|
|
x => string.Equals(
|
|
x,
|
|
id,
|
|
StringComparison.OrdinalIgnoreCase
|
|
)
|
|
);
|
|
|
|
|
|
if (indice < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
selecao.RuasMutaveis.RemoveAt(
|
|
indice
|
|
);
|
|
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Substitui a seleção atual por uma lista já ordenada.
|
|
///
|
|
/// Útil para restaurar uma operação previamente
|
|
/// parametrizada ou recebida de outro componente.
|
|
///
|
|
/// IDs inválidos, vazios ou duplicados não são aceitos.
|
|
/// </summary>
|
|
public void DefinirSelecao(
|
|
MapaDocumento documento,
|
|
MapaSelecaoOperacao selecao,
|
|
IEnumerable<string>? ruasOrdenadas)
|
|
{
|
|
ValidarArgumentos(
|
|
documento,
|
|
selecao
|
|
);
|
|
|
|
|
|
var novaSelecao =
|
|
new List<string>();
|
|
|
|
|
|
var idsUsados =
|
|
new HashSet<string>(
|
|
StringComparer.OrdinalIgnoreCase
|
|
);
|
|
|
|
|
|
foreach (
|
|
string? ruaId
|
|
in ruasOrdenadas ?? Enumerable.Empty<string>())
|
|
{
|
|
string id =
|
|
NormalizarId(
|
|
ruaId
|
|
);
|
|
|
|
|
|
GarantirRuaExistente(
|
|
documento,
|
|
id
|
|
);
|
|
|
|
|
|
if (!idsUsados.Add(id))
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"A seleção contém o ID de rua '{id}' repetido."
|
|
);
|
|
}
|
|
|
|
|
|
novaSelecao.Add(
|
|
id
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Só altera o objeto oficial depois que a nova
|
|
* seleção inteira foi validada.
|
|
*
|
|
* Assim a operação é transacional:
|
|
* se houver um ID inválido no meio da lista,
|
|
* a seleção anterior permanece intacta.
|
|
*/
|
|
selecao.RuasMutaveis.Clear();
|
|
|
|
selecao.RuasMutaveis.AddRange(
|
|
novaSelecao
|
|
);
|
|
}
|
|
|
|
|
|
public void Limpar(
|
|
MapaSelecaoOperacao selecao)
|
|
{
|
|
if (selecao == null)
|
|
{
|
|
throw new ArgumentNullException(
|
|
nameof(selecao)
|
|
);
|
|
}
|
|
|
|
|
|
selecao.RuasMutaveis.Clear();
|
|
}
|
|
|
|
|
|
public bool EstaSelecionada(
|
|
MapaSelecaoOperacao selecao,
|
|
string ruaId)
|
|
{
|
|
if (selecao == null)
|
|
{
|
|
throw new ArgumentNullException(
|
|
nameof(selecao)
|
|
);
|
|
}
|
|
|
|
|
|
string id =
|
|
NormalizarId(
|
|
ruaId
|
|
);
|
|
|
|
|
|
return selecao.RuasMutaveis.Contains(
|
|
id,
|
|
StringComparer.OrdinalIgnoreCase
|
|
);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Retorna a ordem 1-based da rua.
|
|
///
|
|
/// Exemplo:
|
|
/// primeira selecionada = 1.
|
|
///
|
|
/// Retorna null caso a rua não esteja selecionada.
|
|
/// </summary>
|
|
public int? ObterOrdem(
|
|
MapaSelecaoOperacao selecao,
|
|
string ruaId)
|
|
{
|
|
if (selecao == null)
|
|
{
|
|
throw new ArgumentNullException(
|
|
nameof(selecao)
|
|
);
|
|
}
|
|
|
|
|
|
string id =
|
|
NormalizarId(
|
|
ruaId
|
|
);
|
|
|
|
|
|
int indice =
|
|
selecao.RuasMutaveis.FindIndex(
|
|
x => string.Equals(
|
|
x,
|
|
id,
|
|
StringComparison.OrdinalIgnoreCase
|
|
)
|
|
);
|
|
|
|
|
|
return indice < 0
|
|
? null
|
|
: indice + 1;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Retorna uma cópia independente da seleção.
|
|
///
|
|
/// Este é o método que futuramente alimentará
|
|
/// OperacaoParametrosModel.RuasPercorrer.
|
|
/// </summary>
|
|
public List<string> ObterRuasOrdenadas(
|
|
MapaSelecaoOperacao selecao)
|
|
{
|
|
if (selecao == null)
|
|
{
|
|
throw new ArgumentNullException(
|
|
nameof(selecao)
|
|
);
|
|
}
|
|
|
|
|
|
return selecao.RuasOrdenadas
|
|
.ToList();
|
|
}
|
|
|
|
|
|
private static void GarantirRuaExistente(
|
|
MapaDocumento documento,
|
|
string ruaId)
|
|
{
|
|
int quantidade =
|
|
documento.Ruas.Count(
|
|
x =>
|
|
x != null &&
|
|
string.Equals(
|
|
x.Id,
|
|
ruaId,
|
|
StringComparison.OrdinalIgnoreCase
|
|
)
|
|
);
|
|
|
|
|
|
if (quantidade == 0)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"A rua '{ruaId}' não existe no mapa."
|
|
);
|
|
}
|
|
|
|
|
|
/*
|
|
* Isso jamais deveria acontecer depois que o
|
|
* MapaValidationService aprovou o documento.
|
|
*
|
|
* Mesmo assim protegemos esta fronteira.
|
|
*/
|
|
if (quantidade > 1)
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"O mapa possui {quantidade} ruas com o ID '{ruaId}'."
|
|
);
|
|
}
|
|
}
|
|
|
|
|
|
private static string NormalizarId(
|
|
string? ruaId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(
|
|
ruaId))
|
|
{
|
|
throw new ArgumentException(
|
|
"O ID da rua não foi informado.",
|
|
nameof(ruaId)
|
|
);
|
|
}
|
|
|
|
|
|
return ruaId.Trim();
|
|
}
|
|
|
|
|
|
private static void ValidarArgumentos(
|
|
MapaDocumento documento,
|
|
MapaSelecaoOperacao selecao)
|
|
{
|
|
if (documento == null)
|
|
{
|
|
throw new ArgumentNullException(
|
|
nameof(documento)
|
|
);
|
|
}
|
|
|
|
|
|
if (selecao == null)
|
|
{
|
|
throw new ArgumentNullException(
|
|
nameof(selecao)
|
|
);
|
|
}
|
|
|
|
|
|
if (documento.Ruas == null ||
|
|
documento.Ruas.Count == 0)
|
|
{
|
|
throw new InvalidOperationException(
|
|
"O mapa não possui ruas para seleção."
|
|
);
|
|
}
|
|
}
|
|
}
|
|
} |