package pl.com.bottega.documentmanagement.domain; import pl.com.bottega.documentmanagement.domain.events.DocumentListener; import javax.persistence.*; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkState; /** * Created by maciuch on 12.06.16. */ @Entity public class Document { private static final int CHARS_PER_PAGE = 1000; @Id @GeneratedValue private Long id; private DocumentNumber documentNumber; private String content; private String title; private boolean deleted; @Temporal(value = TemporalType.TIMESTAMP) private Date createdAt, verifiedAt, updatedAt; @Enumerated(EnumType.STRING) private DocumentStatus status; @ManyToOne(fetch = FetchType.LAZY) private Employee creator; @ManyToOne(fetch = FetchType.LAZY) private Employee verificator; @ManyToOne(fetch = FetchType.LAZY) private Employee deletor; @ManyToMany(cascade = CascadeType.ALL) private Set<Tag> tags; @OneToMany(mappedBy = "document", cascade = CascadeType.ALL, orphanRemoval = true) private Set<Reader> readers; @ManyToOne(fetch = FetchType.LAZY) private Employee publisher; private Date publishedAt; private BigDecimal printingCost; @Transient private Collection<DocumentListener> documentListeners = new HashSet<>(); private Document() { } public Document(DocumentNumber documentNumber, String content, String title, Employee creator, PrintCostCalculator printCostCalculator ) { this.documentNumber = documentNumber; this.content = content; this.title = title; this.creator = creator; this.status = DocumentStatus.DRAFT; this.createdAt = new Date(); this.deleted = false; this.printingCost = printCostCalculator.cost(pagesCount()); } private int pagesCount() { return content.length() / CHARS_PER_PAGE + (content.length() % CHARS_PER_PAGE == 0 ? 0 : 1); //return Math.ceil((double) content.length()) / CHARS_PER_PAGE); } public void change(String title, String content) { this.title = title; this.content = content; this.status = DocumentStatus.DRAFT; this.updatedAt = new Date(); } public void verify(Employee employee) { checkArgument(employee != null); this.verificator = employee; this.status = DocumentStatus.VERIFIED; this.verifiedAt = new Date(); } public void confirm(Employee confirmator) { Reader reader = reader(confirmator); reader.confirm(); } public void confirm(Employee confirmator, Employee forEmployee) { Reader reader = reader(forEmployee); reader.confirm(confirmator); } public void delete(Employee deletor) { this.deletor = deletor; this.deleted = true; } public void export(DocumentBuilder builder) { builder.start(); builder.addTitle(title); builder.addContent(content); builder.addCreatedAt(createdAt); builder.addStatus(status.name()); builder.end(); } public void tag(Set<Tag> tags) { this.tags = tags; } public Set<Tag> tags() { return tags; } public Employee verificator() { return verificator; } public String content() { return content; } public Employee creator() { return creator; } public String title() { return title; } public boolean deleted() { return deleted; } public DocumentNumber number() { return documentNumber; } public DocumentStatus status() { return status; } public Date verifiedAt() { return verifiedAt; } public Date updatedAt() { return updatedAt; } public Employee deletor() { return deletor; } public void publish(Employee publisher, Set<Employee> employees) { checkArgument(employees != null && employees.size() > 0); checkState(status.equals(DocumentStatus.VERIFIED)); Set<Reader> newReaders = employees.stream().map((employee) -> new Reader(this, employee)).collect(Collectors.toSet()); setReaders(newReaders); this.publishedAt = new Date(); this.publisher = publisher; this.status = DocumentStatus.PUBLISHED; notifyDocumentPublished(); } private void notifyDocumentPublished() { for (DocumentListener listener : documentListeners) listener.published(this); //eventPublisher.publish(new DocumentPublishedEvent(number)) } private void setReaders(Set<Reader> newReaders) { if (readers == null) readers = new HashSet<>(); else readers.clear(); this.readers.addAll(newReaders); } public Set<Reader> readers() { return Collections.unmodifiableSet(readers); } public Employee publisher() { return publisher; } public Date publishedAt() { return publishedAt; } public Reader reader(Employee employee) { return readers().stream(). filter((reader) -> reader.concernsEmployee(employee)). findFirst().orElseThrow(() -> new IllegalArgumentException()); } public void subscribeDocumentListener(DocumentListener documentListener) { documentListeners.add(documentListener); } }