diff --git a/src/es/markse/Contenedor.java b/src/es/markse/Contenedor.java index 44673c845d8a3fbdaf0356681a1f0a0c147f13a6..e8119a7dda3927ff5594165443721f23f19c7533 100644 --- a/src/es/markse/Contenedor.java +++ b/src/es/markse/Contenedor.java @@ -12,163 +12,60 @@ import java.util.List; * @author victorm */ public class Contenedor { - private String codigo; + private final List<Trayecto> trayectos = new ArrayList<>(); + + private ISO6346 codigo; private float pesoTara; private float maximaCargaUtil; private float volumen; private boolean techo; - private List<Trayecto> trayectos = new ArrayList<>(); - private boolean recogida; - private boolean transito; - private boolean apilado = false; + + //Seleccion del estado y de las medidas + private enum estados{ REGOGIDA, TRANSITO } + private enum pesos{ KILOS, LIBRAS} + private enum volumenes{ METROS, PIES } + private estados estadoActual; + private final pesos pesoSeleccionado; + private final volumenes volumenSeleccionado; + + //Parametros para el paso de unas medidas a otras + private final float KILOS_A_LIBRAS = 2.20462f; + private final float LIBRAS_A_KILOS = 0.453592f; + private final float METROS_A_PIES = 35.3147f; + private final float PIES_A_METROS= 0.0283168f; /** * Constructor del Objeto Contenedor - * @param codigoDueno codigo de 3 letras mayusculas del dueño - * @param equipamiento Una letra U, J o Z que indica el equipamiento - * @param numeroSerie El Numero de serie de 6 digitos * @param pesoContenedor El peso del contenedor en kilogramos * @param maximaCargaUtil La carga util del contenedor dada en kilogramos * @param volumen El volumen dado en metros cúbicos * @param transito Indica si esta en transito (true) o en recogida (false) * @param techo indica si tiene techo (true) o no (false) */ - public Contenedor(String codigoDueno, char equipamiento, String numeroSerie, float pesoTara, float maximaCargaUtil, float volumen, boolean transito, boolean techo) { - validarCodigoDueno(codigoDueno); - validarEquipamiento(equipamiento); - comprobarPesos(pesoTara, maximaCargaUtil, volumen); - validarNumeroSerie(numeroSerie); + public Contenedor(ISO6346 codigo, float pesoTara, float maximaCargaUtil, float volumen, estados estadoActual, pesos pesoSeleccionado, volumenes volumenSeleccionado, boolean techo) { + if (pesoTara<0 || maximaCargaUtil <0 || volumen<0) + throw new IllegalArgumentException("Los pesos no puedne ser menores a 0"); + this.codigo = codigo; this.pesoTara = pesoTara; this.maximaCargaUtil = maximaCargaUtil; - this.volumen = volumen; - this.transito = transito; - this.recogida = !transito; + this.estadoActual = estadoActual; + this.pesoSeleccionado = pesoSeleccionado; + this.volumenSeleccionado = volumenSeleccionado; this.techo = techo; - String digitoControl = String.valueOf(calcularDigitoControl(codigoDueno, equipamiento, numeroSerie)); - this.codigo = codigoDueno.toUpperCase() + equipamiento + numeroSerie + digitoControl; - } - - /** - * Metodo que compara e codigo del dueño para ver si es correcto - * @param codigoDueno Cadena de 3 letras mayusculas - * @throws IllegalArgumentException Si el codigoDueno no coincide con el patron correcto - */ - private void validarCodigoDueno(String codigoDueno) { - if (codigoDueno == null) throw new IllegalArgumentException("El código del dueño debe tener 3 letras mayúsculas."); - if (codigoDueno.length() != 3 || !codigoDueno.matches("[A-Za-z]{3}")) - throw new IllegalArgumentException("El código del dueño debe tener 3 letras mayúsculas."); - } - - /** - * Metodo que sirve para comparar si el equipamiento es uno de los correctos - * @param equipamiento Es un caracter que indica el equipamiento - * @throws IllegalArgumentException si el equipamiento no es correcto (no es ni U ni J ni Z) - */ - private void validarEquipamiento(char equipamiento) { - if (equipamiento != 'U' && equipamiento != 'J' && equipamiento != 'Z') { - throw new IllegalArgumentException("Equipamiento debe ser 'U', 'J' o 'Z'."); - } - } - - /** - * metodo para comparar si el numero de serie es correcto - * @param numeroSerie el numero de serie del contenedor - * @throws Si el numeroSerie no es correcto (no son 6 numeros) o si es nulo - * - */ - private void validarNumeroSerie(String numeroSerie) { - if (numeroSerie == null) throw new IllegalArgumentException("El numero de serie no puede ser nulo"); - if (numeroSerie.length() != 6 || !numeroSerie.matches("\\d{6}")) { - throw new IllegalArgumentException("El número de serie debe tener 6 dÃgitos."); - } - } - - /** - * Metodo qe comprueba los pesos de los contenedores - * @param pesoTara Peso del contenedor - * @param maximaCargaUtil Maxima carga util del contenedor - * @param volumen Volumen del contenedor - * @throws IllegalArgumentException si alguno de los pesos es menor que 1 - */ - private void comprobarPesos(float pesoTara, float maximaCargaUtil, float volumen) { - if (pesoTara < 1 || maximaCargaUtil <1 || volumen < 1) { - throw new IllegalArgumentException("Los pesos deben ser igual o mayores a 1"); - } - } - - /** - * Metodo que sirve para calcular el diito de control mediante el codigo del dueño, el equipamiento y el - * numero de serie - * @return devuelve el digito de control - */ - private int calcularDigitoControl(String codigoDueno, char equipamiento, String numeroSerie) { - String codigoCompleto = codigoDueno + equipamiento + numeroSerie; - int[] valores = {10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38}; - int suma = 0; - for (int i = 0; i < codigoCompleto.length(); i++) { - char c = codigoCompleto.charAt(i); - int valor; - if (Character.isLetter(c))valor = valores[c - 'A']; - else valor = Character.getNumericValue(c); - suma += valor*(int) Math.pow(2, i); - } - int resto = suma % 11; - return (resto == 10) ? 0 : resto; - } - - /** - * Metodo que sirve para devolver el codigo del contenedor - * @return el codigo del contenedor (compelto) - */ - public String getCodigo() { - return this.codigo; - } - - /** - * Metodo que devuelve si un contenedor tiene techo - * @return si tiene techo (true) o si no lo tiene (false) - */ - public boolean tieneTecho() { - return this.techo; } /** * 1.1.13 Metodo que sirve para cambiar el estado a recogida de un contenedor - * Si esta apilado no puede estar en recogida - * @throws IllegalArgumentException si el contenedor esta apilado */ public void cambiarEstadoARecogida() { - if(this.estadoApilado()) throw new IllegalArgumentException("No puedes cambiar el estado a un contenedor apilado"); - this.recogida = true; - this.transito = false; + this.estadoActual = estados.REGOGIDA; } /** - * 1.1.14 metodo que sirve para cambiar un contenedor a estado de transito - * Si esta apilado no puede estar en transito - * @throws IllegalArgumentException si el contenedor esta apilado + * 1.1.14 Metodo que sirve para cambiar un contenedor a estado de transito */ public void cambiarEstadoATransito() { - if(this.estadoApilado()) throw new IllegalArgumentException("No puedes cambiar el estado a un contenedor apilado"); - this.recogida = false; - this.transito = true; - } - - /** - * Metodo para cambiar estado a apilado - */ - public void cambiarEstadoApilado() { - this.apilado = true; - this.transito = false; - this.recogida = false; - } - - /** - * Metodo para cmabiar el estado de apilado --> recogida - */ - public void cambiarEstadoDesapilado() { - this.apilado = false; - this.recogida = true; + this.estadoActual = estados.TRANSITO; } /** @@ -182,77 +79,66 @@ public class Contenedor { * 1.1.16 Metodo que devuelve el volumen del contenedor en metros cubicos * @return volumen en metros cubicos */ - public float volumenEnMetrosCubicos() { - return this.volumen; + public double volumenEnMetrosCubicos() { + return (volumenSeleccionado == volumenes.METROS) ? this.volumen : this.volumen*this.PIES_A_METROS; } /** * 1.1.17 metodo que devuelve el volumen del contenedor en pies cubicos * @return volumen en pies cubicos */ - public float volumenEnPiesCubicos() { - return this.volumen*35.3147f; - + public double volumenEnPiesCubicos() { + return (volumenSeleccionado == volumenes.PIES) ? this.volumen : this.volumen*this.METROS_A_PIES; } /** * 1.1.18 Metodo que devuelve el peso del contenedor en Kilogramos * @return peso del contenedor en kilogramos */ - public float obtenerPesoKilos() { - return this.pesoTara; + public double obtenerPesoKilos() { + return (this.pesoSeleccionado == pesos.KILOS ) ? this.pesoTara : this.pesoTara *this.LIBRAS_A_KILOS; } /** * 1.1.19 Metodo que devuelve el peso del contenedor en Libras * @return peso del contenedor en Libras */ - public float obtenerPesoLibras() { - return this.pesoTara*2.20462f; + public double obtenerPesoLibras() { + return (this.pesoSeleccionado == pesos.LIBRAS ) ? this.pesoTara : this.pesoTara *this.KILOS_A_LIBRAS; } /** - * Metodo que devuelve la maxima carga util de un contenedor - * @return La maxima carga util de un contenedor - */ - public float cargaUtilContenedor() { - return this.maximaCargaUtil; - } - - /** - * Metodo que devuelve el estado de recogida de un contenedor - * @return estado de recogida de un contenedor + * Metodo que calcula el costo total de los trayectos de un contenedor + * @param costeDiarioTrayecto El coste diario de un dia de trayecto + * @param costePorMilla El coste por milla recorrida en un trayecto + * @return el precio total del transporte del contenedor */ - public boolean estadoRecogida() { - return this.recogida; + public double precioTransporteTotalContenedor(double costeDiarioTrayecto, double costePorMilla) { + if (this.trayectos.isEmpty()) + return 0.0; + double precioTotal = 0.0; + for (Trayecto t : this.trayectos) { + precioTotal += t.precioTrayectoEnEuros(costeDiarioTrayecto, costePorMilla); + } + return precioTotal; } - /** - * Metodo que devuelve el estado de transito de un contenedor - * @return estado de transito de un contenedor - */ - public boolean estadoTransito() { - return this.transito; - } + /****************************** + * EMPLEACION DE OTROS METODOS* + ******************************/ - /** - * Metodo que devuelve el estado de apilamiento de un contenedor - * @return estado de apilamiento de un contenedor - */ - public boolean estadoApilado() { - return this.apilado; - } - /** * Metodo que sirve para anyadir un trayecto al contenedor * @param t El trayecto que se añade al contenedor - * @throws IllegalArgumentException si es trayecto es nulo, si la fecha fin del ultimo trayecto es superior - * a la de inicio del nuevo trayecto, o si el puerto/muelle destinos del ultimo trayecto no son los de origen - * del nuevo. + * @throws IllegalArgumentException si es trayecto es nulo, + * @throws IllegalArgumentException si la fecha fin del ultimo trayecto es superior a la de inicio del nuevo trayecto + * @throws IllegalArgumentException si el puerto/muelle destinos del ultimo trayecto no son los de origen del nuevo. */ public void anyadirTrayecto(Trayecto t) { - if (t == null) throw new IllegalArgumentException("El trayecto no puede ser nulo"); - if (this.trayectos.size() == 0) this.trayectos.add(t); + if (t == null) + throw new IllegalArgumentException("El trayecto no puede ser nulo"); + if (this.trayectos.size() == 0) + this.trayectos.add(t); else { Trayecto ultimoT = this.trayectos.get(this.trayectos.size() -1); //Si la fecha fin es mayor a la de inicio del nuevo @@ -267,4 +153,43 @@ public class Contenedor { this.trayectos.add(t); } } + + /** + * Metodo que devuelve si un contenedor tiene techo + * @return si tiene techo (true) o si no lo tiene (false) + */ + public boolean tieneTecho() { + return this.techo; + } + + /** + * Metodo que devuelve la maxima carga util de un contenedor + * @return La maxima carga util de un contenedor + */ + public float cargaUtilContenedor() { + return this.maximaCargaUtil; + } + /** + * Metodo que sirve para devolver el codigo del contenedor + * @return el codigo del contenedor (compelto) + */ + public String getCodigo() { + return this.codigo.codigoContenedor(); + } + + /** + * Metodo que sirve para devolver si el contenedor esta en transito + * @return true si esta en transito o false si no lo esta + */ + public boolean contenedorEnTransito() { + return (estadoActual == estados.TRANSITO) ? true : false; + } + + /** + * Metodo que sirve para devolver si el contenedor esta en recogida + * @return true si esta en recogida o false si no lo esta + */ + public boolean contenedorEnRecogida() { + return (estadoActual == estados.REGOGIDA) ? true : false; + } } \ No newline at end of file diff --git a/src/es/markse/ISO6346.java b/src/es/markse/ISO6346.java new file mode 100644 index 0000000000000000000000000000000000000000..1cc22caa230cf4e69250546960021b32493c5f5c --- /dev/null +++ b/src/es/markse/ISO6346.java @@ -0,0 +1,127 @@ +/** + * Copyright UVa 2024/2025 + */ +package es.markse; +import java.util.regex.Pattern; +/** + * Implementacion de la clase ISO6346 para el codigo del contenedor + * @author javcalv + * @authro victorm + */ +public class ISO6346 { + + private final String codigoDuenyo; + private char equipamiento; + private final int numeroSerie; + private int digitoControl; + private final Pattern CODIGO_DUENO = Pattern.compile("[A-Za-z]{3}"); + + /** + * Implementacion de la clase ISO6346 + * @param codigoDuenyo Codigo del dueño de 3 letras (Mayusculas) + * @param equipamiento Equipamiento del contenedor --> U, J o Z + * @param numeroSerie Numero de serie del contenedor. De 0-999999 + * @throws IllegalArgumentException si el codigo del dueño es nulo + * @throws IllegalArgumentException si el codigo del dueño no tiene el patron correcto + * @throws IllegalArgumentException si el equipamiento no es correcto + * @throws IllegalArgumentException si el numero de serie es incorrecto + */ + public ISO6346(String codigoDuenyo, char equipamiento, int numeroSerie) { + if(codigoDuenyo == null) + throw new IllegalArgumentException("El codigo del dueño no puede ser nulo"); + if (!validarCodigoDueño(codigoDuenyo)) + throw new IllegalArgumentException("El codigo del dueño no tiene el patron correcto (3 letras)"); + if (!comprobarEquipamiento(equipamiento)) + throw new IllegalArgumentException("Equipamiento debe ser 'U', 'J' o 'Z'"); + if (numeroSerie<0 || numeroSerie>999999) + throw new IllegalArgumentException("El numero de serie debe ser entre 0-999999"); + + this.codigoDuenyo = codigoDuenyo.toUpperCase(); + this.equipamiento = equipamiento; + this.numeroSerie = numeroSerie; + this.digitoControl = calcularDigitoControl(codigoDuenyo, equipamiento, numeroSerie); + } + + + /** + * Metodo que sirve para validar si el codigo del dueño tiene el patron correcto + * @param codigoDuenyo Codigo del dueño que se debe validar + * @return true si es correcto o falso si no lo es + */ + private boolean validarCodigoDueño(String codigoDuenyo) { + return (this.CODIGO_DUENO.matcher(codigoDuenyo).matches()) ? true : false; + } + + /** + * Metodo que comprueba el equipamiento es correcto + * @param equipamiento Equipamiento que se comprobara + * @return true si es correcto o false si no lo es + */ + private boolean comprobarEquipamiento(char equipamiento) { + return (equipamiento == 'U' || equipamiento == 'J' || equipamiento == 'Z')? true: false; + } + + /** + * Metodo que sirve para calcular el diito de control mediante el codigo del dueño, el equipamiento y el + * numero de serie + * @param codigoDuenyo Codigo del dueño + * @param equipamiento = equipamiento del contenedor + * @param numeroSerie numero de serie del contenedor + * @return devuelve el digito de control + */ + private int calcularDigitoControl(String codigoDueno, char equipamiento, int numeroSerie) { + String codigoCompleto = codigoDueno + equipamiento + numeroSerieString(numeroSerie); + int[] valores = {10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 37, 38}; + int suma = 0; + for (int i = 0; i < codigoCompleto.length(); i++) { + char c = codigoCompleto.charAt(i); + int valor; + if (Character.isLetter(c))valor = valores[c - 'A']; + else valor = Character.getNumericValue(c); + suma += valor*(int) Math.pow(2, i); + } + int resto = suma % 11; + return (resto == 10) ? 0 : resto; + } + + /** + * Metodo que pasa el numero de Serie a un String (con los 6 caracteres) + * @param numeroSerie Numero de serie a transformar + * @return numero de Serie transformado en String + */ + private String numeroSerieString(int numeroSerie) { + return String.format("%06d", numeroSerie); + } + + /** + * Metodo que devuelve el codigo del dueño + * @return codigo del dueño + */ + public String codigoDuenyo() { + return this.codigoDuenyo; + } + + /** + * Metodo que devuelve el equipamiento del codigo + * @return equipamiento + */ + public char equipamiento() { + return this.equipamiento; + } + + /** + * Metodo que devuelve el numero de Serie del contenedor + * @return numero de Serie del contenedor + */ + public int numeroSerie() { + return this.numeroSerie; + } + + /** + * Metodo que devuelve el codigo del Contenedor completo + * @return codigo del contenedor + */ + public String codigoContenedor() { + return (this.codigoDuenyo + this.equipamiento + numeroSerieString(numeroSerie) + this.digitoControl); + } +} \ No newline at end of file diff --git a/src/es/markse/Muelle.java b/src/es/markse/Muelle.java index c8e01da4c83b72ebae257c8ef8ca477bb952fa72..949e4e4b532cbeeeef1f061a1afdba30cc7a3b0d 100644 --- a/src/es/markse/Muelle.java +++ b/src/es/markse/Muelle.java @@ -1,4 +1,3 @@ - /** * Copyright UVa 2024/2025 */ @@ -23,6 +22,7 @@ public class Muelle { private estado estadoActual; private final GPSCoordinate cord; private final Pattern IDENTIFICADOR_REGUEX = Pattern.compile("^\\d{2}$"); + private final Pattern CODIGO_CONTENEDOR = Pattern.compile("[A-Z]{4}\\d{7}"); private static class Plaza { private int altura; @@ -37,20 +37,30 @@ public class Muelle { } /** - * Metodo que indica si un contenedor se encuentra en la plaza o no - * @param codigo Codigo del contenedor que queremos buscar - * @return true si contiene ese contenedor en la Plaza o false si no lo tiene + * 1.1.8 Metodo que devuelve si una plaza esta vacia o no + * @return true si esta vacia o false si no lo esta */ - public boolean contieneContenedor(String codigo) { - return (this.nivelContenedor(codigo)!=-1) ? true : false; - } + public boolean plazaVacia() { + return (this.contenedores.size() == 0) ? true : false; + } + + /** + * 1.1.8 Metodo que devuelve si una plaza esta llena o no + * @return true si la plaza esta llena o si no lo esta + */ + public boolean plazaLlena() { + return (this.contenedores.size() == this.altura || this.ultimoContenedor().tieneTecho()) ? true : false; + } /** - * Metodo que indica el nivel que tiene un contenedor, dado un codigo. + * 1.1.10 Metodo que indica el nivel que tiene un contenedor, dado un codigo. * @param codigo Codigo del contenedo que queremos ver su plaza * @return la altura en la que se encuentra (del 1 que es la baja ahasta n, que es el máximo de contenedores apilabres) + * @throws IllegalArgumentException si el codigo es nulo */ public int nivelContenedor(String codigo) { + if (codigo == null) + throw new IllegalArgumentException("El codigo no puede ser nulo"); for (int i = 0; i < this.contenedores.size(); i++) { if (this.contenedores.get(i).getCodigo().equals(codigo)) { return i + 1; @@ -60,48 +70,41 @@ public class Muelle { } /** - *Metodo que sirve para colar el contenedor en una plaza (apilarlo si esppsible) + * 1.1.11 Metodo que sirve para colar el contenedor en una plaza (apilarlo si es posible) * @param codigo: Codigo del contenedor - * @return true si se ha colodado, o false si no, ya que la plaza esta llena o el ultimo contenedor de esa plaza - * no tiene techo + * @return true si se ha colodado, o false si no + * @throws IllegalArgumentException si el contenedor es nulo */ - public boolean colocarContenedor(Contenedor contenedor) { - if (this.contenedores.size() >= this.altura) { - return false; - } - if (this.contenedores.isEmpty() || this.ultimoContenedor().tieneTecho()) { - return this.contenedores.add(contenedor); - } - return false; + public void colocarContenedor(Contenedor contenedor) { + //Encapsulamos errores aunque para evitarlos en un futuro (si hay cambios) + if (contenedor == null) + throw new IllegalArgumentException("El contenedor no puede ser nulo"); + + if (contenedor.contenedorEnTransito()) + throw new IllegalStateException("El Contenedor esta en transito, no se puede colocar"); + + if(this.contenedores.size() == this.altura) + throw new IllegalStateException("La plaza está llena"); + + if(!this.contenedores.get(this.contenedores.size()-1).tieneTecho()) + throw new IllegalStateException("El ultimo contenedor no tiene techo"); + + if (this.contenedores.isEmpty() || (this.ultimoContenedor().tieneTecho() && this.contenedores.size() < this.altura)) { + this.contenedores.add(contenedor); + } } /** - * Metodo que devuelve true o false si el contenedor que introducimos se encuentra en el nivel mas alto actual de la plaza, es decir, que - * es el ultimo contenedor apilado en esa plaza (sin necesidad que sea el maximo) - * @param codigoContenedor Codigo del contenedor que se comprueba si es el ultimo - * @return true si es el ultimo o false si no lo es. - */ - public boolean estaEnUltimoNivel(String codigoContenedor) { - return this.ultimoContenedor().getCodigo().equals(codigoContenedor); - } - - /** - * Metodo que desapila el contendor + * 1.1.12 Metodo que desapila el ultimo contendor */ public void desapilarContenedor() { - this.contenedores.remove(contenedores.size() - 1); + if(!this.contenedores.isEmpty()) + this.contenedores.remove(contenedores.size() - 1); } - /** - * Metod que devuelve el ultimo contenedor de la Plaza - * @return ultimo contenedor de la plaza o null si esta vacio - */ - public Contenedor ultimoContenedor() { - if (contenedores.isEmpty()) { - return null; - } - return contenedores.get(contenedores.size() -1); - } + /********************************************* + * OTROS METODOS DE LA PLAZA PARA SU GESTION * + *********************************************/ /** * Metodo que devuelve el numero decontenedores @@ -120,19 +123,34 @@ public class Muelle { } /** - * Metodo que devuelve si una plaza esta vacia o no - * @return true si esta vacia o false si no lo esta + * Metodo que devuelve true o false si el contenedor que introducimos se encuentra en el nivel mas alto actual de la plaza, es decir, que + * es el ultimo contenedor apilado en esa plaza (sin necesidad que sea el maximo) + * @param codigoContenedor Codigo del contenedor que se comprueba si es el ultimo + * @return true si es el ultimo o false si no lo es. */ - public boolean plazaVacia() { - return (this.contenedores.size() == 0) ? true : false; + public boolean estaEnUltimoNivel(String codigoContenedor) { + Contenedor c = this.ultimoContenedor(); + return (c == null) ? false : c.getCodigo().equals(codigoContenedor); } /** - * Metodo que devuelve si una plaza esta llena o no - * @return true si la plaza esta llena o si no lo esta + * Metodo que indica si un contenedor se encuentra en la plaza o no + * @param codigo Codigo del contenedor que queremos buscar + * @return true si contiene ese contenedor en la Plaza o false si no lo tiene */ - public boolean plazaLlena() { - return (this.contenedores.size() == this.altura || this.ultimoContenedor().tieneTecho()) ? true : false; + public boolean contieneContenedor(String codigo) { + return (this.nivelContenedor(codigo)!=-1) ? true : false; + } + + /** + * Metod que devuelve el ultimo contenedor de la Plaza + * @return ultimo contenedor de la plaza o null si esta vacio + */ + public Contenedor ultimoContenedor() { + if (contenedores.isEmpty()) { + return null; + } + return contenedores.get(contenedores.size() -1); } } @@ -140,12 +158,11 @@ public class Muelle { * Constructor del objeto Muelle * @param identificador Identificador de 2 digitos (numeros) * @param cord Punto GPS que lo localiza. Clase GPSCoordinate. - * @param operativo Estado del muelle. + * @param estadoActual Estado del muelle. * @param plazas Numero de plazas totales que tiene el Muelle * @param altura numero maximo de contenedores que se pueden apilar encima de otro */ - //CHANGE BOOLEAN OPERATIVO FOR AN STATE OF ESTADO - public Muelle (String identificador, GPSCoordinate cord, boolean operativo, int plazas, int altura) { + public Muelle (String identificador, GPSCoordinate cord, estado estadoActual, int plazas, int altura) { if(!comprobarValoresNulos(identificador, cord)) throw new IllegalArgumentException("Los valores del identificador y coordenada no pueden ser nulos"); if(!comprobarTamanyoAlturaPlazas(plazas, altura)) @@ -156,13 +173,11 @@ public class Muelle { this.identificador = identificador; this.cord = cord; this.plazas = new Plaza[plazas]; - this.estadoActual = operativo ? estado.OPERATIVO : estado.FUERA_DE_SERVICIO; - + this.estadoActual = estadoActual; //Inicializamos el array de las plazas for (int i = 0; i < plazas; i++) { this.plazas[i] = new Plaza(altura); } - } /** @@ -251,7 +266,11 @@ public class Muelle { * @return la plaza del contenedor o -1 si no se encuentra en ninguna plaza */ public int plazaActual(String codigo) { - this.comprobarCodigoContenedor(codigo); + if(codigo == null) + throw new IllegalArgumentException("El codigo no puede ser nulo"); + if(!comprobarCodigoContenedor(codigo)) + throw new IllegalArgumentException("El codigo de contenedor es incorrecto"); + for (int i = 0; i < this.plazas.length; i++) { if (this.plazas[i].numeroContenedores() != 0 && this.plazas[i].contieneContenedor(codigo)) { return i; @@ -267,7 +286,10 @@ public class Muelle { * @return el nivel en el que se encuentra el contenedor o -1 si no se encuentra */ public int nivelEnPlaza(String codigo) { - this.comprobarCodigoContenedor(codigo); + if(codigo == null) + throw new IllegalArgumentException("Codigo del contenedor no puede ser nulo"); + if(!this.comprobarCodigoContenedor(codigo)) + throw new IllegalArgumentException("El codigo de contenedor no tiene el formato correcto"); for (Plaza plaza : this.plazas) { if (plaza.numeroContenedores() != 0 && plaza.contieneContenedor(codigo)) { return plaza.nivelContenedor(codigo); @@ -280,52 +302,70 @@ public class Muelle { * 1.1.11 Metodo para colocar un contenedor en una plaza y apilarlo si es posible * @param codigo Codigo del contenedor que queremos colocar * @param plaza La plaza del contenedor - * @throws IllegalArgumentException si el contenedor es nulo, si la plaza esta fuera de rango, si ese contenedor ya esta apilado - * Si ese contenedor essta en transito, si el contenedor donde se coloca encima no tiene techo o si la plaza - * esta llena + * @throws IllegalArgumentException si el contenedor es nulo + * @throws IllegalArgumentException si la plaza esta fuera de rango, + * @throws IllegalStateException si ese contenedor ya esta apilado + * @throws IllegalStateException si ese contenedor esta en transito, + * @throws IllegalStateException si el contenedor donde se coloca encima no tiene techo + * @throws IllegalStateException si la plaza esta llena */ public void colocarContenedorEnPlaza(Contenedor contenedor, int plaza) { - if (contenedor == null) throw new IllegalArgumentException("El Ccontenedor no puede ser nulo"); - if (plaza < 0 || plaza > this.numeroDePlazasTotales()) throw new - IllegalArgumentException("La plaza debe de estar entre 0-"+ (this.plazas.length -1)); - //Si ya esta apilado - if (contenedor.estadoApilado()) { - throw new IllegalArgumentException("El Contenedor ya esta apilado"); - } + //Comprobamos si el contenedor es nulo o la plaza no pertenece al rango + if (contenedor == null) + throw new IllegalArgumentException("El Contenedor no puede ser nulo"); + if (plaza < 0 || plaza > this.numeroDePlazasTotales()) + throw new IllegalArgumentException("La plaza debe de estar entre 0-"+ (this.plazas.length -1)); + //Si esta entransito - if (contenedor.estadoTransito()) { - throw new IllegalArgumentException("El Contenedor esta en transito, no se puede colocar"); + if (contenedor.contenedorEnTransito()){ + throw new IllegalStateException("El Contenedor esta en transito, no se puede colocar"); } - // Verificar si hay un último contenedor y si tiene techo - if (this.plazas[plaza].colocarContenedor(contenedor)) { - contenedor.cambiarEstadoApilado(); - } - else { - if (!this.plazas[plaza].ultimoContenedor().tieneTecho()) - throw new IllegalArgumentException("El contenedor no tiene techo"); - throw new IllegalArgumentException("La plaza está llena"); - } + //Si ya se encuentra apilado el contenedor en el muelle + if (nivelEnPlaza(contenedor.getCodigo()) != -1) { + throw new IllegalStateException("El Contenedor ya esta apilado"); + } + + //Verificar si la plaza esta llena + Plaza p = this.plazas[plaza]; + if(p.contenedores.size() == p.altura()) + throw new IllegalStateException("La plaza está llena"); + + //Verificamos si el ultimo contenedor tiene techo + if(!p.ultimoContenedor().tieneTecho()) + throw new IllegalStateException("El contenedor no tiene techo"); + else{ + this.plazas[plaza].colocarContenedor(contenedor); + } } /** * 1.1.12 Metodo que sirve para sacar un contenedor de una Plaza y desapilarlo si es posible - * @param contenedor: Contenedor a desapilar de la plaza - * @throws IllegalArgumentException si el contenedor es nulo, si no se encuentra apilado en ningun sitio o - * si el contenedor no se encuentra en la ultima posicion (no se podria desapilar) + * @param contenedor Contenedor a desapilar de la plaza + * @throws IllegalArgumentException si el contenedor es nulo + * @throws IllegalStateException si el contenedor se encuentra en transito + * @throws IllegalStateException si el contenedor no se encuentra apilado en el muelle + * @throws IllegalStateException si el contenedor no se encuentra en la ultima plaza */ public void sacarContenedorDePlaza(Contenedor contenedor) { - if (contenedor == null) throw new IllegalArgumentException("El Ccontenedor no puede ser nulo"); - if (!contenedor.estadoApilado()) throw new IllegalArgumentException("El Contenedor no esta en ninguna plaza. Se encuentra en transito o en recogida"); - + //Comprobamos que el contenedor no sea nulo o que esté en transito + if (contenedor == null) + throw new IllegalArgumentException("El Contenedor no puede ser nulo"); + if (contenedor.contenedorEnTransito()) + throw new IllegalStateException("El Contenedor se encuentra en transito"); + + String c = contenedor.getCodigo(); + //Buscamos que el contenedor este en el muelle + if (plazaActual(c) == -1) + throw new IllegalStateException("El contenedor no se encuentra apilado en este muelle"); + //Buscamos el contenedor y desapilamos el contenedor si se encuentra en el ultimo nivel for (Plaza plaza : this.plazas) { - if (plaza.contieneContenedor(contenedor.getCodigo())) { - if (plaza.estaEnUltimoNivel(contenedor.getCodigo())) { + if (plaza.contieneContenedor(c)) { + if (plaza.estaEnUltimoNivel(c)) { plaza.desapilarContenedor(); - contenedor.cambiarEstadoDesapilado(); } else { - throw new IllegalArgumentException("El Contenedor No esta en el ultimo nivel"); + throw new IllegalStateException("El Contenedor no esta en el ultimo nivel, no se puede desapilar"); } } } @@ -341,11 +381,10 @@ public class Muelle { /** * Metodo que sirve para si un codigo de contenedor es correcto * @param codigo Codigo del contenedor que se comprueba - * @throws IllegalArgumentException si el codigo es nulo o no corresponde a un codigo correcto + * @return true si el codigo es correcto o false si no lo es */ - private void comprobarCodigoContenedor(String codigo) { - if (codigo == null) throw new IllegalArgumentException("Codigo no puede ser nulo"); - if (!codigo.matches("[A-Z]{4}\\d{7}")) throw new IllegalArgumentException("El codigo no pertenece a un codigo de contenedor"); + private boolean comprobarCodigoContenedor(String codigo) { + return (this.CODIGO_CONTENEDOR.matcher(codigo).matches()) ? true : false; } /** @@ -372,5 +411,4 @@ public class Muelle { public GPSCoordinate getGPSCoordinate() { return this.cord; } -} - +} \ No newline at end of file diff --git a/src/es/markse/Puerto.java b/src/es/markse/Puerto.java index f90506a6be70a2044c1832150d66970460743f62..d847c0c250593b4e78edc5ed7ca6f40599c6d83c 100644 --- a/src/es/markse/Puerto.java +++ b/src/es/markse/Puerto.java @@ -21,7 +21,7 @@ public class Puerto { private final String ciudad; private final List<Muelle> muelles = new ArrayList<>(); private final Pattern PAIS_REGUEX = Pattern.compile("[A-Za-z]{2}"); - private final Pattern CIUDAD_REGUEX = Pattern.compile("[A-Za-z]{2}"); + private final Pattern CIUDAD_REGUEX = Pattern.compile("[A-Za-z]{3}"); /** @@ -82,24 +82,6 @@ public class Puerto { return this.muelles.removeIf(muelle -> muelle.getIdentificador().equals(id)); } - /** - * Metodo para comprobar si un muelle esta en ese puerto o no, para agregarle, - * ya que solo puede haber un muelle con el mismo identificador para cada puerto. - * @param m obtejo Muelle - * @return true si esta, y false si no se encuentra en el puerto - */ - public boolean comprobarMuelleEnPuerto(Muelle m) { - String id = m.getIdentificador(); - GPSCoordinate cord = m.getGPSCoordinate(); - //Para daca muelle comprobamos si hay alguno con el mismo id o las mismas coordenadas - for (Muelle muelle : this.muelles) { - if (id.equals(muelle.getIdentificador())|| (cord.getDistanceTo(muelle.getGPSCoordinate())==0)) { - return true; - } - } - return false; - } - /** * 1.1.3 Metodo que comprueba si un puerto esta Lleno o no * @return true (si esta lleno) o false (si no lo esta) @@ -169,6 +151,24 @@ public class Puerto { return cercanos.toArray(new Muelle[0]); } + /** + * Metodo para comprobar si un muelle esta en ese puerto o no, para agregarle, + * ya que solo puede haber un muelle con el mismo identificador para cada puerto. + * @param m obtejo Muelle + * @return true si esta, y false si no se encuentra en el puerto + */ + public boolean comprobarMuelleEnPuerto(Muelle m) { + String id = m.getIdentificador(); + GPSCoordinate cord = m.getGPSCoordinate(); + //Para daca muelle comprobamos si hay alguno con el mismo id o las mismas coordenadas + for (Muelle muelle : this.muelles) { + if (id.equals(muelle.getIdentificador())|| (cord.getDistanceTo(muelle.getGPSCoordinate())==0)) { + return true; + } + } + return false; + } + /** * Metodo que devuelve el pais del puerto * @return pais del perto diff --git a/src/es/markse/Trayecto.java b/src/es/markse/Trayecto.java index 76a8764db3871ad3ea0a83d3c7c4989a26739c42..e196f768664fa1ebd88060c4a190ce24f772b278 100644 --- a/src/es/markse/Trayecto.java +++ b/src/es/markse/Trayecto.java @@ -3,6 +3,8 @@ */ package es.markse; +import java.io.Serializable; + /** * Implementacion de la clase Trayecto * @author vicmtorm @@ -25,14 +27,31 @@ public class Trayecto { * @param fechaFinTrayecto Fecha en la que finaliza un Trayecto */ public Trayecto (Muelle muelleOrigen, Puerto puertoOrigen, Fecha fechaInicioTrayecto, Muelle muelleDestino, Puerto puertoDestino, Fecha fechaFinTrayecto) { - disponibilidadMuelle(muelleOrigen); - disponibilidadMuelle(muelleDestino); - muellePerteneceAlPuerto(muelleOrigen,puertoOrigen); - muellePerteneceAlPuerto(muelleDestino,puertoDestino); - comprobacionMuellesDistintos(muelleOrigen, muelleDestino, puertoOrigen, puertoDestino); - comprobacionFecha(fechaInicioTrayecto); - comprobacionFecha(fechaFinTrayecto); - comprobacionOrdenFechas(fechaInicioTrayecto,fechaFinTrayecto); + //Comprobamos si los valores no son nulos + if(muelleOrigen == null || muelleDestino == null) + throw new IllegalArgumentException("Los muelles no pueden ser nulos"); + if(puertoOrigen == null || puertoDestino == null) + throw new IllegalArgumentException("Los puertos no pueden ser nulos"); + if(fechaInicioTrayecto == null || fechaFinTrayecto == null) + throw new IllegalArgumentException("Las fechas no pueden ser nulas"); + + //Comprobamos si los muelles estan operativos + if (!muelleOrigen.estaOperativo() || !muelleDestino.estaOperativo()) + throw new IllegalStateException("El muelle de origen esta fuera de servicio"); + if (!muelleDestino.estaOperativo()) + throw new IllegalStateException("El muelle de destino esta fuera de servicio"); + + //Comprobamos si los muelles pertenecen al puerto + if (!puertoOrigen.comprobarMuelleEnPuerto(muelleOrigen)) + throw new MuelleNoPerteneceAlPuertoException("El muelle no pertenece al puerto"); + if (!puertoDestino.comprobarMuelleEnPuerto(muelleDestino)) + throw new MuelleNoPerteneceAlPuertoException("El muelle no pertenece al puerto"); + + if (!comprobacionMuellesDistintos(muelleOrigen, muelleDestino, puertoOrigen, puertoDestino)) + throw new IllegalStateException("El muelle de origen no puede ser igual al de destino"); + if(comprobacionOrdenFechas(fechaInicioTrayecto,fechaFinTrayecto)) + throw new IllegalArgumentException ("La Fecha del Inicio del Trayecto no puede ser posterior a la fecha del Fin del Trayecto"); + this.muelleOrigen=muelleOrigen; this.puertoOrigen=puertoOrigen; this.fechaInicioTrayecto=fechaInicioTrayecto; @@ -41,123 +60,39 @@ public class Trayecto { this.fechaFinTrayecto = fechaFinTrayecto; } - /** - * Método que Devuelve el Muelle de Origen - * @return muelleOrigen - */ - - public Muelle getMuelleOrigen() { - return this.muelleOrigen; - } - - /** - * Método que Devuelve el Muelle de Destino - * @return muelleDestino - */ - - public Muelle getMuelleDestino() { - return this.muelleDestino; - } - - /** - * Método que Devuelve el Puerto de Origen - * @return puertoOrigen - */ - - public Puerto getPuertoOrigen() { - return this.puertoOrigen; - } - - /** - * Método que Devuelve el Puerto de Destino - * @return puertoDestino - */ - - public Puerto getPuertoDestino() { - return this.puertoDestino; - } - - /** - * Método que Devuelve la Fecha del Inicio del Trayecto - * @return fechaInicioTrayecto - */ - - public Fecha getFechaInicioTrayecto() { - return this.fechaInicioTrayecto; - } - - /** - * Método que Devuelve la Fecha del Fin del Trayecto - * @return fechaFinTrayecto - */ - - public Fecha getFechaFinTrayecto() { - return this.fechaFinTrayecto; - } - - /** - * Método que comprueba si un Muelle está Operativo o está Fuera de Servicio - * @param muelle Muelle para el que queremos conocer su disponibilidad - * @throws Illegal Argument Exception En el caso de que el Muelle se encuentre Fuera de Servicio - */ - - private void disponibilidadMuelle(Muelle muelle) { - if (!muelle.estaOperativo()) throw new IllegalArgumentException ("¡El Muelle Introducido está Fuera de Servicio!"); - } - - /** - * Método que comprueba si un Muelle Introducido pertenece al Puerto Introducido - * @param muelle Tipo Muelle - * @param puerto Tipo Puerto - * @throws Illegal Argument Exception En el caso de que el Muelle no se encuentre en ese Puerto - */ - - private void muellePerteneceAlPuerto(Muelle muelle, Puerto puerto) { - if (!puerto.comprobarMuelleEnPuerto(muelle))throw new IllegalArgumentException ("¡El Muelle Introducido no Pertenece al Puerto Introducido!"); - } - /** * Método que Comprueba si los Muelles Introducidos son Distintos o no * @param muelleOrigen Muelle desde el que comienza el Trayecto * @param muelleDestino Muelle en el que finaliza el Trayecto - * @throws IllegalArgumentException Si el Muelle de Origen y el Muelle de Destino son el Mismo + * @return true si los muelles son distintos o false si son los mismos */ - - private void comprobacionMuellesDistintos(Muelle muelleOrigen, Muelle muelleDestino, Puerto puertoOrigen, Puerto puertoDestino) { - if (muelleOrigen.getIdentificador()== muelleDestino.getIdentificador()&& puertoOrigen.identificadorPuerto().equals(puertoDestino.identificadorPuerto())) { - throw new IllegalArgumentException ("¡El Muelle de Origen no puede ser igual al Muelle de Destino!"); - } - } - - /** - * Método que Comprueba si la Fecha Introducida al Declarar un nuevo Trayecto es válida o no - * @param fechaDada Fecha Introducida por el Usuario - * @throws IllegalArgumentException Si la Fecha a Comprobar es Nula - */ - - private void comprobacionFecha(Fecha fechaDada) { - if (fechaDada == null) { - throw new IllegalArgumentException ("La Fecha introducida no puede ser nula"); + private boolean comprobacionMuellesDistintos(Muelle muelleOrigen, Muelle muelleDestino, Puerto puertoOrigen, Puerto puertoDestino) { + if (muelleOrigen.getIdentificador() == muelleDestino.getIdentificador() && puertoOrigen.identificadorPuerto().equals(puertoDestino.identificadorPuerto())) { + return false; } + return true; } - + /** * Método que Comprueba si el Orden de las Fechas de Inicio y del Final del Trayecto es el adecuado. * @throws IllegalArgumentException Si la Fecha del Inicio del Trayecto es Posterior a la Fecha del Fin del Trayecto, lo cual es Imposible. */ - - private void comprobacionOrdenFechas(Fecha fechaInicioTrayecto, Fecha fechaFinTrayecto) { + private boolean comprobacionOrdenFechas(Fecha fechaInicioTrayecto, Fecha fechaFinTrayecto) { if (fechaInicioTrayecto.getDiasDesdeEpoch()>fechaFinTrayecto.getDiasDesdeEpoch()){ - throw new IllegalArgumentException ("La Fecha del Inicio del Trayecto no puede ser posterior a la fecha del Fin del Trayecto"); + return false; } + return true; } + /********************************************* + * IMPLEMENTACION DE FUNCIONALIDADES BASICAS * + *********************************************/ + /** - * Método que indica si la Fecha de Fin de Trayecto es superior a una Fecha Dada + * 1.1.21 Método que indica si la Fecha de Fin de Trayecto es superior a una Fecha Dada * @param fechaDada Fecha de Introducida por el usuario * @return True si la Fecha de Fin de Trayecto es Superior, y False si la Fecha de Fin de Trayecto no es Superior */ - public boolean FechaFinTrayectoSuperior(Fecha fechaDada) { if (fechaDada == null) throw new IllegalArgumentException("Fecha no puede ser nula"); if (fechaFinTrayecto.getDiasDesdeEpoch()>fechaDada.getDiasDesdeEpoch()) { @@ -166,16 +101,14 @@ public class Trayecto { else { return true; } - } /** - * Método que, introduciendo el coste diario y el coste por milla, devuelve el precio calculado en Euros de un Trayecto + * 1.1.22. Metodo que, introduciendo el coste diario y el coste por milla, devuelve el precio calculado en Euros de un Trayecto * @param costeDiarioTrayecto Valor en Euros del Coste Diario de un Trayecto * @param costePorMilla Valor en Euros del Coste por Milla de un Trayecto * @return Precio del Trayecto Calculado en Euros */ - public double precioTrayectoEnEuros(double costeDiarioTrayecto, double costePorMilla) { if (costeDiarioTrayecto <= 0) { throw new IllegalArgumentException ("El Coste Diario del Trayecto no es válido"); @@ -183,26 +116,23 @@ public class Trayecto { else if(costePorMilla <= 0) { throw new IllegalArgumentException ("El Coste por Milla del Trayecto no es válido"); } - int dias = (fechaFinTrayecto.getDiasDesdeEpoch()-fechaInicioTrayecto.getDiasDesdeEpoch())+1; + int dias = numeroDeDiasDeTrayceto(); double dist = distanciaMillasMarinas(); return ((dias*costeDiarioTrayecto)+(dist*costePorMilla)); } /** - * Método que devuelve la Distancia calculada en Millas Marinas entre 2 Muelles Distintos + * 1.1.23 Método que devuelve la Distancia calculada en Millas Marinas entre 2 Muelles Distintos * @return Distancia entre 2 Muelles Distintos calculada en Millas Marinas - * */ - public double distanciaMillasMarinas() { return muelleOrigen.getGPSCoordinate().getDistanceTo(muelleDestino.getGPSCoordinate()); } - + /** - * Método que Proporciona Información acerca del Trayecto: Localidad y PaÃs de los Puertos de Origen y Destino, y Fechas de Inicio y Fin del Trayecto + * 1.1.24 Método que Proporciona Información acerca del Trayecto: Localidad y PaÃs de los Puertos de Origen y Destino, y Fechas de Inicio y Fin del Trayecto * @return Información Sobre el Origen (Ciudad, Pais, Fecha Inicio) y el Destino (Ciudad, Pais, Fecha Fin) */ - public String inforTrayecto() { String ciudadOrig = this.puertoOrigen.ciudadDelPuerto(); String paisOrig = this.puertoOrigen.paisDelPuerto(); @@ -210,8 +140,77 @@ public class Trayecto { String ciudadDest = this.puertoDestino.ciudadDelPuerto(); String paisDest = this.puertoDestino.paisDelPuerto(); String FechaFin = this.fechaFinTrayecto.aCadena(); - return"INFORMACION SOBRE EL ORIGEN: \nCiudad Origen: "+ciudadOrig+"\nPais Origen: "+paisOrig+"\nInicio del Trayecto: "+FechaInicio+ "\n\nINFORMACION SOBRE EL DESTINO: \nCiudad Destino: "+ciudadDest+"\nPais Destino: "+paisDest+"\nFin del Trayecto: "+FechaFin+"\n"; } + + /************************* + * OTRAS FUNCIONALIDADES * + *************************/ + + /** + * Metodo que devuelve el numero de dias de un trayecto + */ + public int numeroDeDiasDeTrayceto(){ + return (this.fechaFinTrayecto.getDiasDesdeEpoch()- this.fechaInicioTrayecto.getDiasDesdeEpoch()) +1; + } + + /** + * Método que Devuelve el Muelle de Origen + * @return muelleOrigen + */ + public Muelle getMuelleOrigen() { + return this.muelleOrigen; + } + + /** + * Método que Devuelve el Muelle de Destino + * @return muelleDestino + */ + public Muelle getMuelleDestino() { + return this.muelleDestino; + } + /** + * Método que Devuelve el Puerto de Origen + * @return puertoOrigen + */ + + public Puerto getPuertoOrigen() { + return this.puertoOrigen; + } + /** + * Método que Devuelve el Puerto de Destino + * @return puertoDestino + */ + public Puerto getPuertoDestino() { + return this.puertoDestino; + } + + /** + * Método que Devuelve la Fecha del Inicio del Trayecto + * @return fechaInicioTrayecto + */ + public Fecha getFechaInicioTrayecto() { + return this.fechaInicioTrayecto; + } + + /** + * Método que Devuelve la Fecha del Fin del Trayecto + * @return fechaFinTrayecto + */ + public Fecha getFechaFinTrayecto() { + return this.fechaFinTrayecto; + } + + /** + * Excpcion lanzada para indicar que un muelle no pertenece al puerto + * @author javcalv + * @author victorm + */ + public class MuelleNoPerteneceAlPuertoException extends RuntimeException implements Serializable{ + private static final long serialVersionUID = 1L; + public MuelleNoPerteneceAlPuertoException(String m) { + super(m); + } + } } \ No newline at end of file