/*
* Copyright 2009-2012 by KNURT Systeme (http://www.knurt.de)
*
* Licensed under the Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://creativecommons.org/licenses/by-nc-sa/3.0/
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.knurt.fam.core.model.persist.booking;
import java.util.Date;
import org.springframework.dao.DataIntegrityViolationException;
import de.knurt.fam.core.model.config.BookingRule;
import de.knurt.fam.core.model.config.BookingStrategy;
import de.knurt.fam.core.model.config.FacilityBookable;
import de.knurt.fam.core.model.persist.StoreableAbstract;
import de.knurt.fam.core.model.persist.User;
import de.knurt.fam.core.model.persist.document.Job;
import de.knurt.fam.core.persistence.dao.FamDaoProxy;
import de.knurt.fam.core.persistence.dao.config.FacilityConfigDao;
import de.knurt.fam.core.persistence.dao.couchdb.CouchDBDao4Jobs;
import de.knurt.fam.core.persistence.dao.couchdb.FamCouchDBDao;
import de.knurt.fam.core.util.mail.OutgoingUserMailBox;
import de.knurt.heinzelmann.util.time.TimeFrame;
/**
* a booking resolving things that are the same in all bookings of the access system.<br />
* be sure, never have an User or Facility object directly as attribute here! it results in saving inconsistent data.
*
* @author Daniel Oltmanns
* @since 0.20090827
*/
public abstract class AbstractBooking extends StoreableAbstract implements Booking {
private Date lastInvoiced = null;
@Override
public void cancel() {
if (this.isBooked()) this.cancel(new Cancelation(this.getUser(), Cancelation.REASON_NO_REASON));
}
@Override
public boolean transferTo(User receiver) {
boolean result = false;
if (this.isTransferable() && receiver.isAllowedToAccess(this.getFacility())) {
String oldUsername = this.getUsername();
this.setUsername(receiver.getUsername());
if (FamDaoProxy.bookingDao().update(this)) {
Job job = CouchDBDao4Jobs.me().getJob(this.getId(), Job.STEP_USER_REQUEST);
job.setUsername(receiver.getUsername());
result = FamCouchDBDao.getInstance().updateDocument(job, job);
if (!result) {
// rollback
this.setUsername(oldUsername);
}
}
}
return result;
}
/** {@inheritDoc} */
@Override
public Date getLastInvoiced() {
return this.lastInvoiced;
}
/** {@inheritDoc} */
@Override
public void invoice() {
this.setLastInvoiced(new Date());
this.update();
}
/** {@inheritDoc} */
@Override
public void setLastInvoiced(Date lastInvoiced) {
this.lastInvoiced = lastInvoiced;
}
/**
* construct a booking for a user, a facility, with a status and capacity units and booked by rules.
*
* @param facilityKey representing the facility this booking is for
* @param username of user booked this
* @param bookingStatus the status of booking ({@link BookingStatus})
* @param capacityUnits units booked
* @param bookingRule rules used for this booking
*/
public AbstractBooking(String facilityKey, String username, BookingStatus bookingStatus, int capacityUnits, BookingRule bookingRule) {
this.username = username;
this.bookingStatus = bookingStatus;
this.facilityKey = facilityKey;
if (capacityUnits < 1 || capacityUnits > this.getFacility().getCapacityUnits()) {
throw new DataIntegrityViolationException("invalid capacity units [200909300830]");
}
this.capacityUnits = capacityUnits;
this.bookingRule = bookingRule;
}
/** {@inheritDoc} */
@Override
public boolean isQueueBased() {
return this.getIdBookedInBookingStrategy() == BookingStrategy.QUEUE_BASED;
}
/** {@inheritDoc} */
@Override
public boolean isTimeBased() {
return this.getIdBookedInBookingStrategy() == BookingStrategy.TIME_BASED;
}
/**
* send the applicant, that requested this booking, a confirmation and give him the bonus for it.
*
* @param mailMessage additional message to this confirmation
*/
@Override
public void confirmApplication(String mailMessage) {
this.setBooked();
this.update();
OutgoingUserMailBox.insert_ApplicationConfirmation(this.getUser(), this, mailMessage);
}
/** {@inheritDoc} */
@Override
public int getIdBookedInBookingStrategy() {
if (this.idBookedInBookingStrategy == null) {
this.idBookedInBookingStrategy = this.getBookingRule().getBookingStrategy();
}
return this.idBookedInBookingStrategy.intValue();
}
private Integer idBookedInBookingStrategy = null;
/** {@inheritDoc} */
@Override
public void setIdBookedInBookingStrategy(int idBookedInBookingStrategy) {
this.idBookedInBookingStrategy = idBookedInBookingStrategy;
}
/**
* empty constructor
*/
protected AbstractBooking() {
}
/** {@inheritDoc} */
@Override
public boolean overlaps(Booking otherBooking) {
return this.overlaps(otherBooking.getSessionTimeFrame());
}
/** {@inheritDoc} */
@Override
public boolean overlaps(TimeFrame timeFrame) {
return this.getSessionTimeFrame().overlaps(timeFrame);
}
/** {@inheritDoc} */
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
throw new Error("implements Cloneable!");
}
}
private String username, notice;
private String facilityKey;
private BookingStatus bookingStatus;
private BookingRule bookingRule;
private Integer capacityUnits;
private Integer id;
private Date seton;
private Cancelation cancelation;
private FacilityBookable tmpFacility;
private boolean processed = false;
/**
* set this booking as processed.
*
* @see #setProcessed(boolean)
*/
public void setProcessed() {
this.setProcessed(true);
}
/**
* return the facility, this booking is for.
*
* @return the facility, this booking is for.
*/
@Override
public FacilityBookable getFacility() {
if (this.tmpFacility == null) {
this.tmpFacility = FacilityConfigDao.bookableFacility(this.getFacilityKey());
}
return this.tmpFacility;
}
/**
* return -1, if this booking starts before the other booking. otherwise return 1.
*
* @param otherBooking other booking
* @return -1, if this booking starts before the other booking. otherwise return 1.
*/
public int compareTo(Booking otherBooking) {
return this.getSessionTimeFrame().getStart() < otherBooking.getSessionTimeFrame().getStart() ? -1 : 1;
}
/**
* return the user made in this booking.
*
* @return the user made in this booking.
*/
@Override
public User getUser() {
return FamDaoProxy.userDao().getUserFromUsername(this.getUsername());
}
/** {@inheritDoc} */
@Override
public Integer getCapacityUnits() {
return capacityUnits;
}
/**
* return true, if this booking is an application. same as <code>this.getBookingStatus().isApplied()</code>.
*
* @see BookingStatus#isApplied()
* @return true, if this booking is an application.
*/
@Override
public boolean isApplication() {
return this.getBookingStatus().isApplied();
}
/**
* return true, if this booking is available
*
* @return true, if this booking is available
*/
@Override
public abstract boolean isAvailableForInsertion();
/** {@inheritDoc} */
@Override
public boolean isCanceled() {
return this.cancelation != null;
}
/** {@inheritDoc} */
@Override
public void setBooked() {
this.bookingStatus = new BookingStatus(BookingStatus.STATUS_BOOKED);
}
/** {@inheritDoc} */
@Override
public void setUnset() {
this.bookingStatus = new BookingStatus(BookingStatus.STATUS_UNSET);
}
/** {@inheritDoc} */
@Override
public void setApplied() {
this.bookingStatus = new BookingStatus(BookingStatus.STATUS_APPLIED);
}
/** {@inheritDoc} */
@Override
public String getUsername() {
return username;
}
/** {@inheritDoc} */
@Override
public void setUsername(String username) {
this.username = username;
}
/** {@inheritDoc} */
@Override
public String getFacilityKey() {
return facilityKey;
}
/** {@inheritDoc} */
@Override
public void setFacilityKey(String facilityKey) {
this.facilityKey = facilityKey;
}
/** {@inheritDoc} */
@Override
public BookingStatus getBookingStatus() {
return bookingStatus;
}
/** {@inheritDoc} */
@Override
public void setBookingStatus(BookingStatus bookingStatus) {
this.bookingStatus = bookingStatus;
}
/** {@inheritDoc} */
@Override
public BookingRule getBookingRule() {
return bookingRule;
}
/** {@inheritDoc} */
@Override
public void setBookingRule(BookingRule bookingRule) {
this.bookingRule = bookingRule;
}
/** {@inheritDoc} */
@Override
public void setCapacityUnits(Integer capacityUnits) {
this.capacityUnits = capacityUnits;
}
/**
* return true, if the booking is complete available. do the same as {@link #isAvailableForInsertion()}
*
* @return true, if the booking is complete available.
*/
@Override
public boolean isCompletelyAvailable() {
return this.isAvailableForInsertion();
}
/** {@inheritDoc} */
@Override
public Integer getId() {
return this.id;
}
/** {@inheritDoc} */
@Override
public void setId(Integer id) {
this.id = id;
}
/** {@inheritDoc} */
@Override
public Date getSeton() {
return seton;
}
/** {@inheritDoc} */
@Override
public void setSeton(Date seton) {
this.seton = seton;
}
/** {@inheritDoc} */
@Override
public Cancelation getCancelation() {
return cancelation;
}
/** {@inheritDoc} */
@Override
public void setCancelation(Cancelation cancelation) {
this.cancelation = cancelation;
}
/** {@inheritDoc} */
@Override
public boolean isBooked() {
return this.getBookingStatus().isBooked();
}
/** {@inheritDoc} */
@Override
public String getNotice() {
return notice;
}
/** {@inheritDoc} */
@Override
public void setNotice(String notice) {
this.notice = notice == null ? null : notice.replaceAll("<", "<").replaceAll(">", ">");
}
/** {@inheritDoc} */
@Override
public boolean isProcessed() {
return processed;
}
/** {@inheritDoc} */
@Override
public void setProcessed(boolean processed) {
this.processed = processed;
}
/** {@inheritDoc} */
@Override
public boolean delete() {
return FamDaoProxy.bookingDao().delete(this);
}
/** {@inheritDoc} */
@Override
public boolean isTransferable() {
return this.isBooked() && this.isCanceled() == false && this.getUser() != null && (this.getUser().isAdmin() || this.getUser().hasResponsibility4Facility(this.getFacility()));
}
}