@startuml
skinparam linetype ortho


Provincia --> "1..*" Municipio
Municipio --> "1..*" Localidad
Localidad --> Municipio
Municipio --> Provincia

class Provincia{
    -id: String
    -nombre: String
    -municipios: List<Municipio>
}

class Municipio{
    -id: String
    -nombre: String
    -provincia: Provincia
    -localidades: List<Localidad>
}

class Localidad{
    -id: String
    -nombre: String
    -municipio: Municipio
}

class Usuario{
    -id: int
    -username: String
    -password: String
    -rolPlataforma: Rol
}



class Interes{
    -entidades: List<Entidad>
    -servicios: List<Servicio> 

    +serviciosDeInteres(ubi: Ubicacion): List<Servicio>
    -entidadesDeUbicacion(ubi: Ubicacion): List<Entidad>
}

Interes ..> Ubicacion
Persona --> Interes
Persona ..> Notificable

class Persona{
    -usuario: Usuario
    -nombre: String
    -apellido: String
    -email: String
    -whatsapp: int
    -interes: Interes
    -ubicacion: Ubicacion
    -membresias: List<Membresia>   
    -metodoNotificacion: String
    -tiempoNotificacion: TiempoNotificacion

    +setUbicacion(Ubicacion ubicacion)
    +enviarNotificacion(Notificable notificable)
    +setTiempoNotificacion(TiempoNotificacion tiempo)
    +getMetodoNotificacion(): String
    +setMetodoNotificacion(metodo: String)
    +agregarServicio(servicio: Servicio)
    +eliminarServicio(servicio: Servicio)
    +agregarEntidad(entidad: Entidad)
}
Persona-->"1..*" Notificable
Persona --> TiempoNotificacion
Persona ..> AdapterCalculadoraDistancia

interface AdapterCalculadoraDistancia {
    +distanciaEntre(Ubicacion ubicacionA, Ubicacion ubicacionB): double
}

interface TiempoNotificacion{
    +notificar(notificable Notificable, persona: Persona)
}

NotificacionSinApuro --> "1..*" Horario

enum Horario{
}

class NotificacionSinApuro{
    -notificablesSinNotificar: ListadoNotificables
    -fechas: Map<DayOfWeek, List<Horario>>

    +notificar(notificable Notificable, persona: Persona)
}

class NotificacionAlMomento{
    +notificar(notificable Notificable, persona: Persona)
}

class ListadoNotificables{
    -notificables: List<Notificable>

    +agregarNotificables(Notificable notificable)
    +vaciarNotificables()
    +getInfo(): String
}

ListadoNotificables --> "1..*" Notificable
ListadoNotificables ..|> Notificable

NotificacionSinApuro ..|> TiempoNotificacion
NotificacionSinApuro --> ListadoNotificables
NotificacionAlMomento ..|> TiempoNotificacion
NotificacionAlMomento ..> Notificador

class Comunidad{
    - id: int
    - detalle: String
    - servicios: List<Servicio>
    - membresias: List<Membresia>
    - incidentes: List<IncidentePorComunidad>
    
    + getIncidentes(): List<IncidentePorComunidad>
    + cerrarIncidente(Incidente incidente)
    + agregarIncidente(Incidente incidente)
}
Comunidad --> "1..*" IncidentePorComunidad
Comunidad ..> Incidente

class Membresia{
    -usuario: Persona
    -comunidad: Comunidad
    -rolComunidad: Rol
    -afectado: boolean

    +setRol(Rol rol)
    +setAfectado(boolean valor)
    +isAfectado(): boolean
}
Membresia --> Persona
Membresia --> Comunidad
Comunidad --> "1..*" Membresia
Persona --> "1..*" Membresia

Usuario-->Rol


class Rol{
    -id: int
    -permisos: List<Permiso>

    +tienePermiso(permiso: Permiso)
}
class Permiso{
    -id: int
    -detalles: String
}
Membresia --> Rol
Rol --> "1..*" Permiso


interface LocalizacionAdapter{
    + provincia(lat: float, long: float): Provincia
    + localidad(lat: float, long: float): Localidad
    + municipio(lat: float, long: float): Municipio
    + provincias(): List<Provincia>
    + municipiosDeProvincia(provincia Provincia): List<Municipio>
    + localidadDeProvincia(provincia Provincia): List<Localidad>
}
LocalizacionAdapter ..> Provincia
LocalizacionAdapter ..> Localidad
LocalizacionAdapter ..> Municipio

Ubicacion ..> LocalizacionAdapter

class EntidadPrestadora{
    - entidades: List<Entidad>
    - nombre : String
    - informado: Persona
    - generadorInformacion: InformacionAdapter
    - rankings: List<Ranking>

    +generarRankings()
    +getEntidades(): List<Entidad>
    +enviarInformacion()
}

class OrganismoControl{
    - entidades: List<EntidadPrestadora>
    - nombre : String
    - informado: Persona
    - generadorInformacion: InformacionAdapter
    - rankings: List<Ranking>

    +getRankings(): List<Ranking>
    +generarRankings()
    +getEntidades(): List<Entidad>
    +enviarInformacion()
}

class Entidad{    
    - establecimientos: List<Establecimiento>
    - nombre : String
    - denominacion : Denominacion
   
    +ubicaciones(): List<Ubicacion>
    +establecimientosEnUbiConDispo(ubi: Ubicacion, disp: boolean): List<Establecimiento>
    +agregarEstablecimiento(establecimiento: Establecimiento, posicion: int)
    +eliminarEstablecimiento(establecimiento: Establecimiento)
    -eliminarEstablecimientoPorID(idBuscada: int)
    -getEstablecimientosEnUbicacion(ubi: Ubicacion): List<Establecimiento>
}

Entidad ..> Ubicacion

OrganismoControl -->"1..*" EntidadPrestadora
EntidadPrestadora -->"1..*" Entidad
OrganismoControl --> Persona
EntidadPrestadora --> Persona
OrganismoControl-->InformacionAdapter
EntidadPrestadora-->InformacionAdapter
InformacionAdapter..>Entidad
InformacionAdapter..>EntidadPrestadora
Establecimiento --> Denominacion
Entidad --> Denominacion

class Denominacion{
    - id: int
    - descripcion: String

    + getDescripcion(): String
}

class Establecimiento{
    - denominacion : Denominacion
    - serviciosPrestados : List<ServicioPrestado>
    - ubicacion : Ubicacion

    + agregarServicio(nuevo: ServicioPrestado)
    + eliminarServicio(servicio: ServicioPrestado)
    - eliminarServicioPorID(idBuscada: int)
}

class ServicioPrestado{
    -id: int
    -servicio: Servicio
}

interface InformacionAdapter{
    + obtenerInformacion(entidad: Entidad) : String
    + obtenerInformacion(entidadPrestadora: EntidadPrestadora) : String
}

class Servicio{
    - id: int
    - etiquetas: List<Etiqueta>

    + agregarEtiqueta(nuevaEtiqueta: Etiqueta)
    + eliminarEtiqueta(EtiquetaServicio: Etiqueta)
    - eliminarEtiquetaPorID(idBuscada: int)

}

class Ubicacion{
    -lat: float
    -long: float
    -provincia: Provincia
    -localidad: Localidad
    -municipio: Municipio
}

Ubicacion --> Provincia
Ubicacion --> Localidad
Ubicacion --> Municipio

class Etiqueta{
    -id: int
    -tipo: String
    -valor: String
}

class RevisionIncidente{
    -incidente: Incidente

    +getInfo(): String
}

RevisionIncidente --> Incidente
RevisionIncidente ..|> Notificable

interface Notificable{
    +getInfo(): String
}

class Ranking{
    -ponderador: Ponderador
    -entidades: List<Entidad>

    +getInfo(): String
}

interface Ponderador{
    +ordenar(List<Entidad> entidades): List<Entidad>
}

class PromedioTiempoCierre{
    +ordenar(List<Entidad> entidades): List<Entidad>
}

class MasIncidentesEnSemana{
    +ordenar(List<Entidad> entidades): List<Entidad>
}

class GradoDeImpacto{
    +ordenar(List<Entidad> entidades): List<Entidad>
}

GradoDeImpacto ..> MedidorImpacto

interface MedidorImpacto{
    +comunidadConMasImpacto(Comunidad comunidadA, Comunidad comunidadB): Comunidad
}

PromedioTiempoCierre ..|> Ponderador
MasIncidentesEnSemana ..|> Ponderador
GradoDeImpacto ..|> Ponderador

Ranking --> Ponderador
Ranking --> "1..*" Entidad

class IncidentePorComunidad {
    - incidente: Incidente
    - estaCerrado: boolean
    - fechaCierre: DateTime
    - autorCierre: Persona
}
IncidentePorComunidad ---> Incidente

class Incidente{
    - serviciosAfectados: List<ServicioPrestado>
    - observaciones: String
    - fechaApertura: DateTime
    - autorApertura: Persona
    +getInfo(): String
}
Incidente ..|> Notificable
Incidente "1" --> "*" ServicioPrestado

Ranking ..|> Notificable


Notificador ..> Persona
Notificador ..> Notificable

class Notificador{
    {static}-estrategias: Map<String, StrategyNotificacion>
    {static}+notificar(notificable: Notificable, persona: Persona)
}

/'  RELACIONES  '/


Establecimiento --> "1..*" ServicioPrestado

ServicioPrestado --> Servicio
Servicio --> "1..*" Etiqueta

Entidad --> "1..*" Establecimiento

Establecimiento --> Ubicacion

Persona --> Usuario
Persona --> Ubicacion
Interes --> "1..*" Servicio
Interes --> "1..*" Entidad

ImportarEntidadAdapter ..> OrganismoControl
ImportarEntidadAdapter ..> EntidadPrestadora

interface ImportarEntidadAdapter{
    + crearOrganismosControl(path: String): List<OrganismoControl>
    + crearEntidadesPrestadoras(path: String): List<EntidadPrestadora>
}
ImportarEntidadCSV ..|> ImportarEntidadAdapter
class ImportarEntidadCSV{
    + crearOrganismosControl(path: String): List<OrganismoControl>
    + crearEntidadesPrestadoras(path: String): List<EntidadPrestadora>
}

interface ValidadorUsuario{
    + validar(usuario: Usuario, password: String) : boolean
}
ValidadorUsuario ..> Usuario


@enduml