import java.util.ArrayList;
// Exception [unchecked] : peut être utilisée n'importe où.
class HoraireInvalide extends IllegalArgumentException{}
// Exceptions [checked] : doit être déclarée avec [throws] quand elle
// peut être levée directement ou indirectement.
class CreneauInvalide extends Exception {}
class CreneauVide extends CreneauInvalide {}
class Depassement extends CreneauInvalide {
public Horaire hor;
public Depassement(Horaire hor) { this.hor = hor; }
}
class NonOuvrable extends CreneauInvalide {
public Creneau c;
public NonOuvrable(Creneau c) { this.c = c; }
}
class Conflit extends Exception {
public Creneau c;
public int i;
public Conflit(Creneau c, int i) { this.c = c; this.i = i; }
}
// Horaires (parties 1 et 2)
class Horaire implements Comparable<Horaire> {
private int jour, heure;
public int getJour() { return jour; }
public int getHeure() { return heure; }
public Horaire(int j, int h)
{
if (0 <= j && j < 7 && 0 <= h && h < 24) {
this.jour = j; this.heure = h;
} else {
// Simplement faire
// throw new IllegalArgumentException();
// fonctionne aussi, mais on peut faire remarquer
// au passage qu'une exception qui étent celle-ci
// n'a pas besoin d'être déclarée non plus.
throw new HoraireInvalide();
}
}
public int compareTo(Horaire other)
{
if (this.jour == other.jour) {
return other.heure - this.heure;
} else {
return other.jour - this.jour;
}
}
public Horaire ajoute(int duree) throws Depassement
{
if (this.heure + duree < 24) {
return new Horaire(this.jour, this.heure + duree);
} else {
try {
int d = duree - (24 - this.heure);
return new Horaire(this.jour + d/24, d%24);
}
// Avantage d'avoir utilisé une exception "maison" :
// on ne rattrape pas tout et n'importe quoi dans ce [catch].
catch (HoraireInvalide e) { throw new Depassement(this); }
}
}
// public Horaire ajouteUnsafe(int duree)
// {
// if (this.heure + duree < 24) {
// return new Horaire(this.jour, this.heure + duree);
// } else {
// int d = duree - (24 - this.heure);
// return new Horaire(this.jour + d/24, d%24);
// }
// }
}
// Créneaux (parties 2 et 3)
class Creneau {
private Horaire hord, horf;
public Horaire getDebut() { return hord; }
public Horaire getFin() { return horf; }
// Constructeurs normaux
public Creneau(Horaire hd, Horaire hf) throws CreneauVide
{
if (hd.compareTo(hf) > 1) { throw new CreneauVide(); }
else { this.hord = hd; this.horf = hf; }
}
private Creneau(Horaire hd, int duree) throws CreneauVide, Depassement
{
this(hd, hd.ajoute(duree));
}
// Constructeur ne déclarant pas d'exception [CreneauVide].
// Précondition : hd < hf
// Le booléen ne sert qu'à assurer la gestion de la surcharge (gore)
private Creneau(Horaire hd, Horaire hf, boolean t)
{
this.hord = hd;
this.horf = hf;
}
public boolean verifOuvrable()
{
return (hord.getJour() == horf.getJour() &&
hord.getJour() < 6 &&
hord.getHeure() > 7 &&
horf.getHeure() < 19);
}
// Comme lors du rattrapage on réutilise le constructeur, les
// déclarations d'exceptions doivent rester même si elles ne peuvent
// pas être levées dans les faits.
public static Creneau creneauNonVide(Horaire hd, Horaire hf)
throws CreneauVide, Depassement
{
try { return new Creneau(hd, hf); }
catch (CreneauVide e) { return new Creneau(hd, 1); }
}
// Cette version utilise le constructeur qui ne déclare pas d'exceptions,
// mais il y a toujours la possibilité d'un dépassement.
// Pour ne pas déclarer [Depassement] il faudrait utiliser [ajouteUnsafe]
// mais ce n'est pas une bonne idée car notre méthode ne vérifie pas
// qu'il n'y a pas de dépassement.
public static Creneau creneauNonVideBis(Horaire hd, Horaire hf)
throws Depassement
{
try { return new Creneau(hd, hf); }
catch (CreneauVide e) { return new Creneau(hd, hd.ajoute(1), true); }
}
public CreneauCours creneauCours(Horaire hd, Horaire hf)
throws CreneauVide, NonOuvrable
{
try {
return new CreneauCours(hd, hf);
}
catch (NonOuvrable e) {
int j = e.c.getDebut().getJour();
int hhd = Math.max(8, e.c.getDebut().getHeure());
int hhf =
(e.c.getDebut().getJour() == e.c.getFin().getJour())?
Math.min(18, e.c.getFin().getHeure()):
18;
return new CreneauCours(new Horaire(j, hhd), new Horaire(j, hhf));
}
}
public boolean precede(Creneau c)
{
return this.horf.compareTo(c.getDebut()) < 0;
}
public boolean suit(Creneau c)
{
return this.hord.compareTo(c.getFin()) > 0;
}
// public boolean contientHoraire(Horaire h) {
// return this.hd.compareTo(h) < 0 && this.hf.compareTo(h) > 0;
// }
// public boolean precede(Horaire h) {
// return this.hf.compareTo(h) < 0;
// }
// public boolean suit(Horaire h) {
// return this.hd.compareTo(h) > 0;
// }
// public boolean conflit(Creneau c) {
// return this.contientHoraire(c.getDebut()) || c.contientHoraire(hd);
// }
public boolean estPrioritaire() { return false; }
}
class CreneauCours extends Creneau {
public CreneauCours(Horaire hd, Horaire hf)
throws CreneauVide, NonOuvrable
{
super(hd, hf);
if (!this.verifOuvrable()) { throw new NonOuvrable(this); }
}
public CreneauCours(Horaire hd, int duree)
throws CreneauVide, NonOuvrable, Depassement
{
this(hd, hd.ajoute(duree));
}
public boolean verifOuvrable()
{
return (getDebut().getJour() == getFin().getJour() &&
getDebut().getJour() < 6 &&
getDebut().getHeure() > 7 &&
getFin().getHeure() < 19);
}
public boolean estPrioritaire() { return true; }
}
class AjouteCreneauOK extends Exception {}
// EdT (partie 3)
public class EdT {
private ArrayList<Creneau> liste;
public EdT() { liste = new ArrayList<Creneau>(); }
public void ajouteCreneau(Creneau c) throws Conflit
{
int i=0;
try {
while (this.liste.get(i).precede(c)) {
i++;
}
if (this.liste.get(i).suit(c)) {
this.liste.add(i, c);
} else {
throw new Conflit(c, i);
}
}
// Remarque : dans la boucle précédente, je ne regarde jamais si [i]
// reste dans le tableau. Ce rattrapage d'exception intercepte
// l'éventuelle sortie, qui correspond au cas où le créneau qu'on veut
// ajouter est postérieur à tous les créneaux déjà présents.
catch (IndexOutOfBoundsException e) {
this.liste.add(i, c);
}
}
public void ajouteCreneauAvecPriorite(Creneau c) throws Conflit
{
try { this.ajouteCreneau(c); }
catch (Conflit e) {
if (!c.estPrioritaire()) { throw e; }
boolean conflit = false;
int j = e.i;
while (!this.liste.get(j).suit(c)) {
conflit = conflit || this.liste.get(j).estPrioritaire();
j++;
}
if (conflit) { throw e; }
else {
for (int i=e.i; i<j; i++) { this.liste.remove(i); }
this.liste.add(e.i, c);
}
}
}
}