package entity.reports;
import entity.Ownable;
import entity.files.SYSNR2FILE;
import entity.info.Resident;
import entity.process.QProcess;
import entity.process.QProcessElement;
import entity.process.SYSNR2PROCESS;
import entity.system.Commontags;
import entity.system.Users;
import op.OPDE;
import op.tools.SYSTools;
import org.apache.commons.collections.Closure;
import org.apache.commons.collections.CollectionUtils;
import org.joda.time.DateTime;
import org.joda.time.Seconds;
import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* This is the entity class responsible for the storage of nursing reports. As this is a documentation, there are some features
* with this database table that guarantees the correct handling, even when reports are deleted or changed.
* <p>
* The reports are <b>never</b> really deleted or altered. They are <b>marked</b> as deleted or altered.
* <p>
* <ul>
* <li><b>DELETE</b> - see remarks for delPit</li>
* <li><b>CHANGE</b> - when a report is changed:
* <ol>
* <li>a new report is cloned from the old one.</li>
* <li>the new one is marked as replacement for the old one</li>
* <li>the old report is marked as replaced by the new report</li>
* <li>the old report looses all attached files and qprocess connections (which the new one inherited of course)</li>
* <li>the old report is marked with the editor and the PIT (editedBy, editedPIT)</li>
* </ol>
* </li>
* </ul>
*
* @author tloehr
*/
@Entity
@Table(name = "nreports")
public class NReport extends Ownable implements Serializable, QProcessElement, Comparable<NReport>, Cloneable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "PBID")
private Long pbid;
@Version
@Column(name = "version")
private Long version;
/**
* When did the event depicted in this report really happen ?
*/
@Basic(optional = false)
@Column(name = "PIT")
@Temporal(TemporalType.TIMESTAMP)
private Date pit;
/**
* This is the time, when the new report was entered. A replacement report has also the PIT of the replacement time.
* It does NOT carry over the newPIT from the old report.
*/
@Basic(optional = false)
@Column(name = "NewPIT")
@Temporal(TemporalType.TIMESTAMP)
private Date newPIT;
/**
* The time when this report was edited. null if it wasn't.
*/
@Basic(optional = true)
@Column(name = "EditedPIT")
@Temporal(TemporalType.TIMESTAMP)
private Date editedPIT;
/**
* The time when this report was deleted. null if it wasn't.
*/
@Basic(optional = true)
@Column(name = "DelPIT")
@Temporal(TemporalType.TIMESTAMP)
private Date delPIT;
/**
* the text of the report
*/
@Lob
@Column(name = "Text")
private String text;
/**
* the amount of time the events in this text took to happen. (how much work was it ?)
*/
@Basic(optional = false)
@Column(name = "Dauer")
private int minutes;
/**
* the user who entered this report.
*/
@JoinColumn(name = "NewBy", referencedColumnName = "UKennung")
@ManyToOne
private Users newBy;
/**
* The user who deleted this report. null if its not deleted.
*/
@JoinColumn(name = "DeletedBy", referencedColumnName = "UKennung")
@ManyToOne
private Users deletedBy;
/**
* the resident who <i>owns</i> this report
*/
@JoinColumn(name = "BWKennung", referencedColumnName = "BWKennung")
@ManyToOne
private Resident resident;
/**
* the user who edited this report. null, if it is still unchanged.
*/
@JoinColumn(name = "EditedBy", referencedColumnName = "UKennung")
@ManyToOne
private Users editedBy;
/**
* if this report has been replaced by another one, it is stored here. null, if its not replaced.
*/
@JoinColumn(name = "ReplacedBy", referencedColumnName = "PBID")
@OneToOne
private NReport replacedBy;
/**
* if this report is a replacement for another report, then this report is stored here. null, if its no replacement.
*/
@JoinColumn(name = "ReplacementFor", referencedColumnName = "PBID")
@OneToOne
private NReport replacementFor;
/**
* the list of attached files.
*/
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "nReport")
private Collection<SYSNR2FILE> attachedFilesConnections;
/**
* for handovers only. the list of users who acknowledged this report.
*/
@OneToMany(cascade = CascadeType.ALL, mappedBy = "bericht", fetch = FetchType.EAGER)
private List<NR2User> usersAcknowledged;
/**
* the list of processes which this report was attached to
*/
@OneToMany(orphanRemoval = true, cascade = CascadeType.ALL, mappedBy = "nreport")
private Collection<SYSNR2PROCESS> attachedProcessConnections;
/**
* the list of tags which were sticked to this report.
*/
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
@JoinTable(name = "nreports2tags", joinColumns =
@JoinColumn(name = "pbid"), inverseJoinColumns =
@JoinColumn(name = "ctagid"))
private Collection<Commontags> commontags;
public NReport() {
}
public NReport(Resident resident) {
this.pit = new Date();
this.newPIT = new Date();
this.text = "";
this.minutes = 3;
this.resident = resident;
this.newBy = OPDE.getLogin().getUser();
this.attachedFilesConnections = new ArrayList<SYSNR2FILE>();
this.commontags = new ArrayList<Commontags>();
this.attachedProcessConnections = new ArrayList<SYSNR2PROCESS>();
this.usersAcknowledged = new ArrayList<NR2User>();
this.version = 0l;
}
/**
* private constructor for the cloning only
*
* @param pit
* @param newPIT
* @param editedPIT
* @param text
* @param minutes
* @param newBy
* @param resident
* @param editedBy
* @param replacedBy
* @param replacementFor
*/
private NReport(Date pit, Date newPIT, Date editedPIT, String text, int minutes, Users newBy, Resident resident, Users editedBy, NReport replacedBy, NReport replacementFor) {
this.pit = pit;
this.newPIT = newPIT;
this.editedPIT = editedPIT;
this.text = SYSTools.tidy(text);
this.minutes = minutes;
this.newBy = newBy;
this.resident = resident;
this.editedBy = editedBy;
this.replacedBy = replacedBy;
this.replacementFor = replacementFor;
this.attachedFilesConnections = new ArrayList<SYSNR2FILE>();
this.commontags = new ArrayList<Commontags>();
this.attachedProcessConnections = new ArrayList<SYSNR2PROCESS>();
this.usersAcknowledged = new ArrayList<NR2User>();
this.version = 0l;
}
public Long getPbid() {
return pbid;
}
public void setPbid(Long pbid) {
this.pbid = pbid;
}
public List<NR2User> getUsersAcknowledged() {
return usersAcknowledged;
}
public Date getPit() {
return pit;
}
public void setPit(Date pit) {
this.pit = pit;
}
public Date getEditedPIT() {
return editedPIT;
}
public String getText() {
SYSTools.anonymizeText(resident.getNameNeverAnonymous(), text);
return text;
}
public void setText(String text) {
this.text = SYSTools.tidy(text);
}
public int getMinutes() {
return minutes;
}
public void setMinutes(int dauer) {
this.minutes = dauer;
}
public Resident getResident() {
return resident;
}
public Collection<SYSNR2FILE> getAttachedFilesConnections() {
return attachedFilesConnections;
}
public Date getNewPIT() {
return newPIT;
}
public void setNewPIT(Date newPIT) {
this.newPIT = newPIT;
}
public void setEditedPIT(Date editedPIT) {
this.editedPIT = editedPIT;
}
public Date getDelPIT() {
return delPIT;
}
public void setDelPIT(Date delPIT) {
this.delPIT = delPIT;
}
public Users getDeletedBy() {
return deletedBy;
}
public void setDeletedBy(Users deletedBy) {
this.deletedBy = deletedBy;
}
public void setResident(Resident resident) {
this.resident = resident;
}
public Users getEditedBy() {
return editedBy;
}
public void setEditedBy(Users editedBy) {
this.editedBy = editedBy;
}
public NReport getReplacedBy() {
return replacedBy;
}
public void setReplacedBy(NReport replacedBy) {
this.replacedBy = replacedBy;
}
public boolean isReplaced() {
return replacedBy != null;
}
public boolean isReplacement() {
return replacementFor != null;
}
public boolean isAddedLater() {
return Seconds.secondsBetween(new DateTime(pit), new DateTime(newPIT)).isGreaterThan(Seconds.seconds(NReportTools.IGNORED_AMOUNT_SECONDS_TILL_THE_CLOCK_TURNS_UP));
}
public boolean isDeleted() {
return delPIT != null;
}
/**
* @return true if and only if the report is deleted or replaced
*/
public boolean isObsolete() {
return isDeleted() || isReplaced();
}
/**
* Ein "Ersatzbericht", "weiss" wer er mal war, indem er in <code>replacementFor</code> auf den alten,
* ersetzten Bericht zeigt. Normale Berichte geben hier <code>null</code> zurück.
*
* @return
*/
public NReport getReplacementFor() {
return replacementFor;
}
public void setReplacementFor(NReport replacementFor) {
this.replacementFor = replacementFor;
}
public Collection<Commontags> getCommontags() {
return commontags;
}
public Users getNewBy() {
return newBy;
}
@Override
public Users getUser() {
return newBy;
}
public void setNewBy(Users user) {
this.newBy = user;
}
@Override
public Users getOwner() {
return newBy;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NReport nReport = (NReport) o;
if (minutes != nReport.minutes) return false;
// if (editedBy != null ? !editedBy.equals(nReport.editedBy) : nReport.editedBy != null) return false;
if (editedPIT != null ? !editedPIT.equals(nReport.editedPIT) : nReport.editedPIT != null) return false;
if (newPIT != null ? !newPIT.equals(nReport.newPIT) : nReport.newPIT != null) return false;
if (delPIT != null ? !delPIT.equals(nReport.delPIT) : nReport.delPIT != null) return false;
if (pbid != null ? !pbid.equals(nReport.pbid) : nReport.pbid != null) return false;
if (pit != null ? !pit.equals(nReport.pit) : nReport.pit != null) return false;
// if (replacedBy != null ? !replacedBy.equals(nReport.replacedBy) : nReport.replacedBy != null) return false;
// if (replacementFor != null ? !replacementFor.equals(nReport.replacementFor) : nReport.replacementFor != null)
// return false;
if (resident != null ? !resident.equals(nReport.resident) : nReport.resident != null) return false;
if (commontags != null ? !commontags.equals(nReport.commontags) : nReport.commontags != null) return false;
if (text != null ? !text.equals(nReport.text) : nReport.text != null) return false;
if (newBy != null ? !newBy.equals(nReport.newBy) : nReport.newBy != null) return false;
if (version != null ? !version.equals(nReport.version) : nReport.version != null) return false;
return true;
}
@Override
public int hashCode() {
int result = pbid != null ? pbid.hashCode() : 0;
result = 31 * result + (version != null ? version.hashCode() : 0);
result = 31 * result + (pit != null ? pit.hashCode() : 0);
result = 31 * result + (editedPIT != null ? editedPIT.hashCode() : 0);
result = 31 * result + (text != null ? text.hashCode() : 0);
result = 31 * result + minutes;
result = 31 * result + (newBy != null ? newBy.hashCode() : 0);
result = 31 * result + (resident != null ? resident.hashCode() : 0);
// result = 31 * result + (editedBy != null ? editedBy.hashCode() : 0);
// result = 31 * result + (replacedBy != null ? replacedBy.hashCode() : 0);
// result = 31 * result + (replacementFor != null ? replacementFor.hashCode() : 0);
result = 31 * result + (commontags != null ? commontags.hashCode() : 0);
return result;
}
@Override
public String getContentAsHTML() {
return NReportTools.getNReportAsHTML(this, false);
}
@Override
public String getPITAsHTML() {
return NReportTools.getPITAsHTML(this);
}
@Override
public long getID() {
return pbid;
}
@Override
public String toString() {
return "entity.reports.NReport[pbid=" + pbid + "]";
}
@Override
public ArrayList<QProcess> getAttachedProcesses() {
ArrayList<QProcess> list = new ArrayList<QProcess>();
for (SYSNR2PROCESS att : attachedProcessConnections) {
list.add(att.getQProcess());
}
return list;
}
public Collection<SYSNR2PROCESS> getAttachedQProcessConnections() {
return attachedProcessConnections;
}
@Override
public String getTitle() {
return SYSTools.xx("misc.msg.report") + ": " + text;
}
@Override
public NReport clone() {
final NReport clonedReport = new NReport(pit, newPIT, editedPIT, text, minutes, newBy, resident, editedBy, null, null);
CollectionUtils.forAllDo(commontags, new Closure() {
public void execute(Object o) {
clonedReport.commontags.add((Commontags) o);
}
});
CollectionUtils.forAllDo(attachedProcessConnections, new Closure() {
public void execute(Object o) {
SYSNR2PROCESS oldAssignment = (SYSNR2PROCESS) o;
clonedReport.attachedProcessConnections.add(new SYSNR2PROCESS(oldAssignment.getQProcess(), clonedReport));
}
});
CollectionUtils.forAllDo(attachedFilesConnections, new Closure() {
public void execute(Object o) {
SYSNR2FILE oldAssignment = (SYSNR2FILE) o;
clonedReport.attachedFilesConnections.add(new SYSNR2FILE(oldAssignment.getSysfile(), clonedReport, clonedReport.getNewBy(), clonedReport.getPit()));
}
});
return clonedReport;
}
@Override
public long getPITInMillis() {
return pit.getTime();
}
@Override
public int compareTo(NReport other) {
return pit.compareTo(other.getPit()) * -1;
}
}