package model;
import java.util.Collection;
import main.error.VideothekException;
import model.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import model.data.exceptions.RecordNotFoundException;
import model.data.xml.writers.InvoiceWriter;
import model.events.*;
import model.exceptions.*;
import model.exceptions.FalseIDException;
/**
*
* InRent.java
* @author Andie Hoffmann (andhoffm@uos.de)
* 25.09.2008
*
* {@link InRent}-Objekte repräsentieren eine Ausleihe, die genau einem {@link Customer} zugeordnet sind,
* aber mehrere {@link VideoUnits} haben kann.
*/
public class InRent implements Comparable<InRent>
{
private int rID;
private int customerID;
private Customer customer = null;
private Collection<Integer> videoUnitIDs = null;
private Collection<VideoUnit> videoUnits = null;
private Date date;
private int duration;
private boolean deleted = false;
private boolean warned = false;
private static Map<Integer, InRent> inRentList;
private static int minrID;
/**
* Öffentlicher Konstruktor, der von der GUI genutzt wird
* @param customer {@link Customer}, der ausleiht
* @param videoUnits Liste der {@link VideoUnits}, die ausgeliehen werden sollen
* @param date ist das Ausleihdatum
* @param duration Ausleihdauer in Wochen
* @throws FalseIDException
* @throws FalseFieldException
* @throws CurrentDateException
* @throws VideoUnitRentedException
*/
public InRent(Customer customer, Collection<VideoUnit> videoUnits,
Date date, int duration) throws FalseIDException,
FalseFieldException, CurrentDateException, VideoUnitRentedException
{
// this(minrID, customer.getID(), , date, duration);
this.rID = minrID;
minrID++;
// checken, ob übergebene videoUnits auch keine leere liste ist
if(videoUnits.size() > 0)
{
for (VideoUnit unit : videoUnits)
{
if(!customer.canRent(unit))
throw new FalseFieldException("Kunde kann Film nicht ausleihen (FSK, oder es liegen Mahnungen vor)");
if (unit.isRented())
throw new VideoUnitRentedException(
"Videoexemplar " + unit.getID() + " bereits verliehen. "
+ "Erneute Ausleihe nicht möglich!");
}
}
else
{
// leere liste => exception
throw new FalseFieldException("Übergebene VideoExemplarListe leer!");
}
this.customerID = customer.getID();
this.customer = customer;
this.date = date;
this.duration = duration;
this.videoUnits = videoUnits;
// VideoUnitIDs aus übergebenen VideoUnits auslesen und in Liste
// speichern.
Collection<Integer> unitIDs = new LinkedList<Integer>();
for (VideoUnit unit : videoUnits)
{
unitIDs.add(unit.getID());
}
this.videoUnitIDs = unitIDs;
// Event feuern
EventManager.fireEvent(new InRentCreatedEvent(this));
checkRentDate();
inRentList.put(this.rID, this);
}
/**
* Privater Konstruktor, der vom öffentlichen Konstruktor und von der
* recreate-Methode genutzt wird
* @param rID Ausleihnummer
* @param customerID Kundennummer
* @param videoUnitIDs Liste der Filmexemplarnummern, die ausgeliehen werden sollen
* @param date Ausleihdatum
* @param duration Ausleihdauer in Wochen
* @param warned True, wenn für Ausleihe schon eine Mahnung vorliegt, False sonst
* @throws FalseIDException
* @throws FalseFieldException
* @throws CurrentDateException
*/
private InRent(int rID, int customerID, Collection<Integer> videoUnitIDs,
Date date, int duration, boolean warned) throws FalseIDException,
FalseFieldException, CurrentDateException
{
this.rID = rID;
this.customerID = customerID;
this.videoUnitIDs = videoUnitIDs;
this.date = date;
this.duration = duration;
this.warned = warned;
// leere liste => exception
if(videoUnitIDs.size() <= 0)
{
throw new FalseFieldException("Übergebene VideoExemplarListe leer!");
}
checkIDs();
checkDuration();
}
/**
* Soll gespeicherte Ausleihen aus der xml-Datei erzeugen
* @param rID Ausleihnummer
* @param customerID Kundennummer
* @param videoUnitIDs Filmexemplarnummern
* @param date Ausleihdatum
* @param duration Ausleihdauer
* @param warned True, wenn für Ausleihe schon eine Mahnung vorliegt, False sonst
* @return InRent die Ausleihe
* @throws FalseIDException
* @throws FalseFieldException
* @throws CurrentDateException
*/
public static InRent reCreate(int rID, int customerID,
Collection<Integer> videoUnitIDs, Date date, int duration,
boolean warned) throws FalseIDException, FalseFieldException,
CurrentDateException
{
return new InRent(rID, customerID, videoUnitIDs, date, duration, warned);
}
/**
* Setzt die MinID für InRents
* @param newMinrID neue MinID für InRrents
* @throws FalseIDException
*/
public static void setMinID(int newMinrID) throws FalseIDException
{
if (newMinrID > 0)
{
minrID = newMinrID;
}
else
{
throw new FalseIDException(
"Übergebene MinID für InRent ist kleiner 0!!!");
}
}
/**
* Liefert die MinID
* @return die MinID
*/
public static int getMinID()
{
return minrID;
}
/**
* Überprüf, ob das Ausleihdatum dem aktuellen Datum entspricht
* @throws FalseFieldException
* @throws CurrentDateException
*/
private void checkRentDate() throws FalseFieldException,
CurrentDateException
{
if (this.date.compareTo(CurrentDate.get()) != 0)
throw new FalseFieldException("Bitte Datum überprüfen");
}
/**
* Überprüft, ob die Ausleihdauer zwischen 1 und 5 Wochen beträgt
* @throws FalseFieldException
*/
private void checkDuration() throws FalseFieldException
{
if (this.duration < 1 || this.duration > 5)
throw new FalseFieldException();
}
/**
* Liefert die Ausleihnummer
* @return die Ausleihnummer
*/
public int getID()
{
return this.rID;
}
/**
* Überprüft die Ausleih- und die Kundennummer
* @throws FalseIDException
*/
private void checkIDs() throws FalseIDException
{
int rID = this.rID;
int customerID = this.customerID;
// videoUnitIDs checken
for (Integer videoUnitID : this.videoUnitIDs)
{
if (videoUnitID < 1)
throw new FalseIDException();
}
if (rID < 1 || customerID < 1)
throw new FalseIDException();
}
/**
* Liefert den {@link Customer} der Ausleihe
* @return den {@link Customer} der Ausleihe
*/
public Customer getCustomer()
{
if (this.customer == null)
{
try
{
this.customer = Customer.findByID(this.customerID);
}
catch (RecordNotFoundException e)
{
this.customer = null; // sollte hoffentlich nie eintreten!
}
}
return this.customer;
}
/**
* Liefert das Ausleihdatum
* @return das Ausleihdatum
*/
public Date getDate()
{
return this.date;
}
/**
* Liefert das Rückgabedatum der Ausleihe
* @return das Rückgabedatum der Ausleihe
*/
public Date getReturnDate()
{
return this.date.addWeeks(this.duration);
}
/**
* Methode überprüft, ob die Leihfrist + der angegebenen Frist abgelaufen ist
*
* @param deadline Anzahl der Tage, die auf das Rückgabedatum hinzugerechnet
* werden.
* @return true, wenn Leihfrist überschritten, False sonst
*/
public boolean isOverDuration(int deadline)
{
if (this.getReturnDate().addDays(deadline).compareTo(CurrentDate.get()) < 0)
{
return true;
}
else
return false;
}
/**
* Methode überprüft, ob die Leihfrist abgelaufen ist
*
* @return true, wenn Leihfrist überschritten, False sonst
*/
public boolean isOverDuration()
{
return isOverDuration(0);
}
/**
* Liefert eine Liste der ausgeliehenen Filmexemplarnummern
* @return eine Liste der Filmexemplarnummern
*/
public Collection<Integer> getVideoUnitIDs()
{
return this.videoUnitIDs;
}
/**
* Liefert die Ausleihdauer in Wochen
* @return
*/
public int getDuration()
{
return this.duration;
}
/**
* Liefert eine Liste der ausgeliehenen Filmexemplare
* @return eine Liste der Filmexemplare
*/
public Collection<VideoUnit> getVideoUnits()
{
if (this.videoUnits == null)
{
try
{
// this.videoUnits = VideoUnit.findByInRent(this);
// TODO: müssen evtl mal überlegen, welche variante sinniger
// ist...
Collection<VideoUnit> foundVideoUnits = new LinkedList<VideoUnit>();
for (Integer unitID : videoUnitIDs)
{
foundVideoUnits.add(VideoUnit.findByID(unitID));
}
this.videoUnits = foundVideoUnits;
}
catch (RecordNotFoundException e)
{
this.videoUnits = null;
}
}
return this.videoUnits;
}
/**
* Gibt den Preis dieser Ausleihe zurück, berechnet aus Ausleihdauer
* (duration) multipliziert mit dem Preis des Films.
*
* @return Der Preis der Ausleihe.
*/
public float getPrice()
{
float price = 0.0f;
try
{
for (VideoUnit unit : this.getVideoUnits())
{
price += unit.getVideo().getPriceCategory().getPrice()
* this.duration;
}
}
catch (RecordNotFoundException e)
{
// sollte hoffentlich nie passieren...
e.printStackTrace();
}
return price;
}
/**
* Entfernt InRent aus globaler InRent-Liste. Wird beim nächsten Speichern
* nicht mehr mitgespeichert und geht somit verloren.
*
* @throws VideothekException
*/
public void delete() throws VideothekException
{
if (!this.isWarned())
{
inRentList.remove(this.getID());
this.deleted = true;
// Event feuern
EventManager.fireEvent(new InRentDeletedEvent(this));
}
else
throw new VideothekException(
"Ausstehende Mahnung für diese Ausleihe. Löschen nicht möglich!");
}
/**
* Gibt an, ob das Objekt gelöscht wurde (via delete())
*
* @return True, falls gelöscht, False sonst.
*/
public boolean isDeleted()
{
return this.deleted;
}
/**
* Informiert alle anderen Teilsysteme, dass diese Ausleihe evtl. geändert
* wurde. Feuert ein InRentEditedStateEvent und sollte einmal nach einem
* Bearbeitungsvorgang aufgerufen werden.
*/
public void save()
{
// Event feuern
EventManager.fireEvent(new InRentEditedStateEvent(this));
}
/**
* Informiert, ob bereits eine Mahnung (Warning) für diese Ausleihe erstellt wurde
*
* @return true, wenn schon gemahnt wurde, false sonst
*/
public boolean isWarned()
{
return warned;
}
/**
* Markiert, dass bereits eine Mahnung erstellt wurde
*/
public void setWarned(boolean b)
{
this.warned = b;
}
/**
* Erstellt eine Quittung für diese Ausleihe im quittungen/ Ordner. Name der
* Quittings-Datei ist die ID dieses InRent Objektes + '.txt'
*/
public void createInvoice()
{
InvoiceWriter writer = new InvoiceWriter();
writer.writeInvoiceFor(this);
save();
}
/**
* Gibt das zugehörige Warning zurück, falls vorhanden, ansonsten null.
* @return Das zugehörige Warning bzw. null, falls nicht vorhanden.
*/
public Warning getWarning()
{
return Warning.findByInRent(this);
}
/**
* Liefert die zu der übergebenen Ausleihnummer passende Ausleihe
* @param inRentID Ausleihnummer
* @return Ausleihe, die zu der Ausleihnummer gehört
* @throws RecordNotFoundException
*/
public static InRent findByID(int inRentID) throws RecordNotFoundException
{
if (inRentList.containsKey(inRentID))
{
return inRentList.get(inRentID);
}
else
{
throw new RecordNotFoundException("Ausleihe", "AusleihNummer",
inRentID);
}
}
/**
* Liefert eine Liste aller Ausleihen
* @return eine Liste aller Ausleihen
*/
public static Collection<InRent> findAll()
{
return inRentList.values();
}
/**
* Liefert eine Liste aller Ausleihen, die zum übergebenen {@link Customer} gehören
* @param customer {@link Customer}, dessen Ausleihen gesucht werden
* @return Liste aller Ausleihen, die zum übergebenen {@link Customer} gehören
*/
public static Collection<InRent> findByCustomer(Customer customer)
{
List<InRent> foundInRents = new LinkedList<InRent>();
for (InRent ir : inRentList.values())
{
if (ir.getCustomer().getID() == customer.getID())
{
foundInRents.add(ir);
}
}
return foundInRents;
}
/**
* Liefert die Ausleihe, in der sich das Filmexemplar befindet
* @param videoUnit Filmexemplar
* @return die gesuchte Ausleihe zu dem Filmexemplar
* @throws RecordNotFoundException
*/
public static InRent findByVideoUnit(VideoUnit videoUnit)
throws RecordNotFoundException
{
// TODO: hier kann das evtl. auch anders gemacht werden...
for (InRent ir : inRentList.values())
{
if (ir.getVideoUnits().contains(videoUnit))
{
return ir;
}
}
return null;
// dieser code hier hat in der log-datei immer für die vielen
// fehlermeldungen gesorgt:
// throw new RecordNotFoundException("Ausleihe", "VideoExemplarNr.",
// videoUnit.getID());
}
/**
* Liefert eine Liste aller Ausleihen, deren Ausleihdatum mit dem übergebenen Datum übereinstimmt
* @param date Ausleihdatum
* @return eine Liste aller Ausleihen mit dem gesuchten Ausleihdatum
*/
public static Collection<InRent> findByDate(Date date)
{
List<InRent> foundInRents = new LinkedList<InRent>();
for (InRent ir : inRentList.values())
{
if (ir.date.equals(date))
{
foundInRents.add(ir);
}
}
return foundInRents;
}
/**
* Setzt die globale Liste aller Ausleihen
* @param newInRentList neue Liste aller Ausleihen
* @throws FalseFieldException
*/
public static void setInRentList(Map<Integer, InRent> newInRentList)
throws FalseFieldException
{
if (newInRentList != null)
{
inRentList = newInRentList;
}
else
{
throw new FalseFieldException("InRentList is null!");
}
}
/**
* Methode wird aus Warning aufgerufen und überprüft die Liste aller Ausleihen
* auf Ausleihen mit überzogener Leihfrist
*
* @return true, wenn InRents mit überzogener Leihfrist existieren, false
* sonst
*/
protected static boolean newWarnings()
{
for (InRent ir : inRentList.values())
{
if (ir.isOverDuration(3) && !ir.isWarned())
{
return true;
}
}
return false;
}
/**
* Methode wird aus Warning aufgerufen, überprüft die Liste der Ausleihen und
* liefert eine Liste mit allen neuen, fälligen Mahnungen
*
* @return Liste mit den neuen Mahnungen
*/
protected static Collection<Warning> getNewWarnings()
{
List<Warning> foundNewWarnings = new LinkedList<Warning>();
for (InRent ir : inRentList.values())
{
if (ir.isOverDuration(3) && !ir.isWarned())
{
foundNewWarnings.add(new Warning(ir));
}
}
return foundNewWarnings;
}
/**
* Löscht ein einzelnes Filmexemplar aus einer Ausleihe
* (falls nur dieses Exemplar zurückgegeben wird)
* @param videoUnit Filmexemplar, das gelöscht wird
*/
public void deleteSingleVideoUnit(VideoUnit videoUnit)
{
this.videoUnitIDs.remove(videoUnit.getID());
this.getVideoUnits().remove(videoUnit);
EventManager.fireEvent(new InRentDeletedUnitEvent(this, videoUnit));
}
public void deleteMultipleVideoUnits(Collection<VideoUnit> videoUnits)
{
for (VideoUnit unit : videoUnits)
{
deleteSingleVideoUnit(unit);
}
}
@Override
/**
*
*/
public int compareTo(InRent other)
{
if (this.customerID == other.customerID && this.warned == other.warned
&& this.date.equals(other.date)
&& this.duration == other.duration
&& this.deleted == other.deleted && this.rID == other.rID
&& this.isOverDuration() == other.isOverDuration()
&& this.videoUnitIDs.equals(other.videoUnitIDs)
&& this.getPrice() == other.getPrice())
{
return 0; // sind gleich
}
else
{
return 1; // sind ungleich
}
}
/**
* Überprüft eine Ausleihe mit einer anderen auf Gleichheit
* @param other andere Ausleihe
* @return True, wenn Ausleihen gleich, False sonst
*/
public boolean equals(InRent other)
{
return this.compareTo(other) == 0;
}
}