/**
* Copyright © 2002 Instituto Superior Técnico
*
* This file is part of FenixEdu Academic.
*
* FenixEdu Academic is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* FenixEdu Academic is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FenixEdu Academic. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.academic.domain.contacts;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.fenixedu.academic.domain.DomainObjectUtil;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.PersonInformationLog;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.organizationalStructure.Party;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import org.fenixedu.bennu.core.security.Authenticate;
import org.joda.time.DateTime;
import pt.ist.fenixframework.Atomic;
public abstract class PartyContact extends PartyContact_Base {
public interface ContactResolver<T extends PartyContact> {
public String getPresentationValue(T partyContact);
}
private static final Map<Class<? extends PartyContact>, ContactResolver<? extends PartyContact>> DEFAULT_RESOLVERS =
new HashMap<>();
private static ContactResolver<? extends PartyContact> getResolver(Class<?> class1) {
synchronized (DEFAULT_RESOLVERS) {
return DEFAULT_RESOLVERS.get(class1);
}
}
public static void setResolver(Class<? extends PartyContact> class1, ContactResolver<?> contactResolver) {
synchronized (DEFAULT_RESOLVERS) {
DEFAULT_RESOLVERS.put(class1, contactResolver);
}
}
public static Comparator<PartyContact> COMPARATOR_BY_TYPE = new Comparator<PartyContact>() {
@Override
public int compare(PartyContact contact, PartyContact otherContact) {
int result = contact.getType().compareTo(otherContact.getType());
return (result == 0) ? DomainObjectUtil.COMPARATOR_BY_ID.compare(contact, otherContact) : result;
}
};
protected PartyContact() {
super();
setContactRoot(ContactRoot.getInstance());
setVisibleToPublic(Boolean.FALSE);
setVisibleToStudents(Boolean.FALSE);
setVisibleToStaff(Boolean.FALSE);
setLastModifiedDate(new DateTime());
setActive(true);
setDefaultContact(false);
}
protected void init(final Party party, final PartyContactType type, final boolean defaultContact) {
checkParameters(party, type);
super.setParty(party);
super.setType(type);
if (type.equals(PartyContactType.INSTITUTIONAL)) {
setVisibleToPublic();
} else {
setVisibleToStudents(type == PartyContactType.WORK);
setVisibleToStaff(type == PartyContactType.WORK);
}
setDefaultContactInformation(defaultContact);
setLastModifiedDate(new DateTime());
}
protected void init(final Party party, final PartyContactType type, final boolean visibleToPublic,
final boolean visibleToStudents, final boolean visibleToStaff, final boolean defaultContact) {
checkParameters(party, type);
super.setParty(party);
super.setType(type);
setVisibleToPublic(new Boolean(visibleToPublic));
setVisibleToStudents(new Boolean(visibleToStudents));
setVisibleToStaff(new Boolean(visibleToStaff));
setDefaultContactInformation(defaultContact);
setLastModifiedDate(new DateTime());
}
private void setVisibleToPublic() {
super.setVisibleToPublic(Boolean.TRUE);
super.setVisibleToStudents(Boolean.TRUE);
super.setVisibleToStaff(Boolean.TRUE);
}
@Override
public void setVisibleToPublic(Boolean visibleToPublic) {
super.setVisibleToPublic(visibleToPublic);
if (visibleToPublic.booleanValue()) {
super.setVisibleToStudents(Boolean.TRUE);
super.setVisibleToStaff(Boolean.TRUE);
}
}
@Override
public void setVisibleToStudents(Boolean visibleToStudents) {
super.setVisibleToStudents(visibleToStudents);
if (!visibleToStudents.booleanValue()) {
super.setVisibleToPublic(Boolean.FALSE);
}
}
@Override
public void setVisibleToStaff(Boolean visibleToStaff) {
super.setVisibleToStaff(visibleToStaff);
if (!visibleToStaff.booleanValue()) {
super.setVisibleToPublic(Boolean.FALSE);
}
}
public boolean isVisible() {
if (getVisibleToPublic()) {
return true;
}
if (getVisibleToStudents() && ContactRoot.getInstance().getStudentVisibility().isMember(Authenticate.getUser())) {
return true;
}
if (getVisibleToStaff() && ContactRoot.getInstance().getStaffVisibility().isMember(Authenticate.getUser())) {
return true;
}
if (ContactRoot.getInstance().getManagementVisibility().isMember(Authenticate.getUser())) {
return true;
}
return false;
}
public void setDefaultContactInformation(final boolean defaultContact) {
if (!isActiveAndValid()) {
if (getPartyContactValidation() != null) {
getPartyContactValidation().setToBeDefault(defaultContact);
}
} else {
if (defaultContact) {
changeToDefault();
} else {
final List<PartyContact> partyContacts = (List<PartyContact>) getParty().getPartyContacts(getClass());
if (partyContacts.isEmpty() || partyContacts.size() == 1) {
super.setDefaultContact(Boolean.TRUE);
} else {
setAnotherContactAsDefault();
super.setDefaultContact(Boolean.FALSE);
}
}
}
}
public void changeToDefault() {
final PartyContact defaultPartyContact = getParty().getDefaultPartyContact(getClass());
if (defaultPartyContact != null && defaultPartyContact != this) {
defaultPartyContact.setDefaultContact(Boolean.FALSE);
}
super.setDefaultContact(Boolean.TRUE);
}
private void checkParameters(final Party party, final PartyContactType type) {
if (party == null) {
throw new DomainException("error.contacts.PartyContact.party.cannot.be.null");
}
if (type == null) {
throw new DomainException("error.contacts.PartyContact.contactType.cannot.be.null");
}
}
public void edit(final PartyContactType type, final boolean defaultContact) {
checkParameters(getParty(), type);
setType(type);
setDefaultContactInformation(defaultContact);
}
public String getPresentationValue() {
final ContactResolver resolver = getResolver(getClass());
return resolver == null ? null : resolver.getPresentationValue(this);
}
public boolean isDefault() {
return hasDefaultContactValue() && getDefaultContact().booleanValue();
}
private boolean hasDefaultContactValue() {
return getDefaultContact() != null;
}
public boolean isInstitutionalType() {
return getType() == PartyContactType.INSTITUTIONAL;
}
public boolean isWorkType() {
return getType() == PartyContactType.WORK;
}
public boolean isPersonalType() {
return getType() == PartyContactType.PERSONAL;
}
public boolean isWebAddress() {
return false;
}
public boolean isPhysicalAddress() {
return false;
}
public boolean isEmailAddress() {
return false;
}
public boolean isPhone() {
return false;
}
public boolean isMobile() {
return false;
}
@Atomic
public void deleteWithoutCheckRules() {
processDelete();
}
@Atomic
public void delete() {
if (isActiveAndValid()) {
checkRulesToDelete();
}
processDelete();
}
protected void processDelete() {
if (isActiveAndValid()) {
setAnotherContactAsDefault();
}
if (getActive()) {
setActive(false);
setLastModifiedDate(new DateTime());
setCurrentPartyContact(null);
setPrevPartyContact(null);
if (getPartyContactValidation() != null) {
final PartyContactValidation validation = getPartyContactValidation();
if (validation.getContactRoot() != null) {
validation.setContactRoot(null);
}
}
}
// setResearcher(null);
// setParty(null);
// setRootDomainObject(null);
// super.deleteDomainObject();
}
protected void checkRulesToDelete() {
// nothing to check
}
public void setAnotherContactAsDefault() {
if (isDefault()) {
final List<PartyContact> contacts = (List<PartyContact>) getParty().getPartyContacts(getClass());
if (!contacts.isEmpty() && contacts.size() > 1) {
contacts.remove(this);
contacts.iterator().next().setDefaultContact(Boolean.TRUE);
}
}
}
public String getPartyContactTypeString() {
return getType().name();
}
public static Set<PartyContact> readPartyContactsOfType(Class<? extends PartyContact>... contactClasses) {
Set<PartyContact> contacts = new HashSet<PartyContact>();
for (Class<? extends PartyContact> clazz : contactClasses) {
contacts.addAll(getAllInstancesOf(clazz));
}
return contacts;
}
// getActive() isValid() Result
// 0 0 Refused
// 0 1 Deleted when validation was needed
// 1 0 Requires validation
// 1 1 Valid
public boolean isValid() {
return getPartyContactValidation() == null || getPartyContactValidation().isValid();
}
public boolean isActiveAndValid() {
return getActive() && isValid();
}
public boolean waitsValidation() {
return getActive() && !isValid();
}
public void triggerValidationProcess() {
if (getPartyContactValidation() != null) {
getPartyContactValidation().triggerValidationProcess();
}
}
public void triggerValidationProcessIfNeeded() {
if (getPartyContactValidation() != null) {
getPartyContactValidation().triggerValidationProcessIfNeeded();
}
}
public abstract boolean hasValue(String value);
public void setValid() {
if (getPartyContactValidation() != null) {
getPartyContactValidation().setValid();
}
}
public boolean isValidationCodeGenerated() {
if (getPartyContactValidation() != null) {
return getPartyContactValidation().getToken() != null;
}
return false;
}
/***************************************************************************
* DomainOperationLog: logic is all common code placed on parent class
* (PartyContact) while child class executes parent code with specific child
* class info (args)
**************************************************************************/
public void logCreate(Person person) {
}
protected void logCreateAux(Person person, String typeKey) {
final String infoLabel = BundleUtil.getString(Bundle.APPLICATION, typeKey);
final String personViewed = PersonInformationLog.getPersonNameForLogDescription(person);
final String descriptionKey;
if (waitsValidation()) {
descriptionKey = "log.personInformation.contact.generic.create.need.valid";
} else {
descriptionKey = "log.personInformation.contact.generic.create";
}
PersonInformationLog.createLog(person, Bundle.MESSAGING, descriptionKey, infoLabel, this.getPresentationValue(),
personViewed);
}
public void logEdit(Person person, boolean propertiesChanged, boolean valueChanged, boolean createdNewContact, String newValue) {
}
protected void logEditAux(Person person, boolean propertiesChanged, boolean valueChanged, boolean createdNewContact,
String newValue, String typeKey) {
final String infoLabel = BundleUtil.getString(Bundle.APPLICATION, typeKey);
final String personViewed = PersonInformationLog.getPersonNameForLogDescription(person);
boolean oldValueDiffersFromNew = false;
if (valueChanged) {
if (getPrevPartyContact() != null) {
oldValueDiffersFromNew = getPrevPartyContact().getPresentationValue().compareTo(getPresentationValue()) != 0;
}
}
if (propertiesChanged && !valueChanged) {
// only properties were changed
if (getPrevPartyContact() != null) {
// editing a contact with pending changes (replacing changes)
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.newEdit", infoLabel, this.getPresentationValue(),
personViewed);
} else {
// editing an existing contact with no pending changes
if (isValid()) {
PersonInformationLog.createLog(person, Bundle.MESSAGING, "log.personInformation.contact.generic.edit",
infoLabel, this.getPresentationValue(), personViewed);
} else {
// editing an existing pending contact (creation)
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.create.need.valid.edited", infoLabel,
this.getPresentationValue(), personViewed);
}
}
} else if (valueChanged) {
// value or physical address was changed
if (getPrevPartyContact() != null) {
if (getPrevPartyContact().isValid()) {
// editing a valid existing contact
if (oldValueDiffersFromNew && createdNewContact) {
// new value differs from old, and a new temporary
// contact was created
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.values", infoLabel, getPrevPartyContact()
.getPresentationValue(), newValue, personViewed);
} else if (createdNewContact) {
// only a new temporary contact was created
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid", infoLabel, this.getPresentationValue(),
personViewed);
} else if (oldValueDiffersFromNew) {
// only the values differ (temp contact already exists)
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.values.newEdit", infoLabel,
getPrevPartyContact().getPresentationValue(), newValue, personViewed);
} else {
// only physical address details changed (temp contact
// already exists)
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.newEdit", infoLabel,
this.getPresentationValue(), personViewed);
}
} else {
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.values.newEdit", infoLabel,
this.getPresentationValue(), newValue, personViewed);
}
} else {
// pending creation value was changed
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.create.need.valid.values.edited", infoLabel,
this.getPresentationValue(), newValue, personViewed);
}
}
}
public void logDelete(Person person) {
}
public void logDeleteAux(Person person, String typeKey) {
final String infoLabel = BundleUtil.getString(Bundle.APPLICATION, typeKey);
final String personViewed = PersonInformationLog.getPersonNameForLogDescription(person);
if (isValid()) {
// it is valid, so it is not a pending change or creation
PersonInformationLog.createLog(person, Bundle.MESSAGING, "log.personInformation.contact.generic.remove", infoLabel,
this.getPresentationValue(), personViewed);
} else {
if (getPrevPartyContact() == null) {
// no previous contact = new contact being created
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.create.need.valid.canceled", infoLabel,
this.getPresentationValue(), personViewed);
} else {
// has previous contact = edit
String oldValue = getPrevPartyContact().getPresentationValue();
if (oldValue.compareTo(getPresentationValue()) == 0) {
// previous value is the same
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.canceled", infoLabel,
this.getPresentationValue(), personViewed);
} else {
// previous is different, display previous value
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.values.canceled", infoLabel,
getPrevPartyContact().getPresentationValue(), this.getPresentationValue(), personViewed);
}
}
}
}
public void logValid(Person person) {
}
public void logValidAux(Person person, String typeKey) {
final String infoLabel = BundleUtil.getString(Bundle.APPLICATION, typeKey);
final String personViewed = PersonInformationLog.getPersonNameForLogDescription(person);
if (getPrevPartyContact() == null) {
// no previous contact = new contact being created
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.create.need.valid.accepted", infoLabel, this.getPresentationValue(),
personViewed);
} else {
// has previous contact = edit
String oldValue = getPrevPartyContact().getPresentationValue();
if (oldValue.compareTo(getPresentationValue()) == 0) {
// previous value is the same
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.accepted", infoLabel, this.getPresentationValue(),
personViewed);
} else {
// previous is different, display previous value
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.values.accepted", infoLabel, getPrevPartyContact()
.getPresentationValue(), this.getPresentationValue(), personViewed);
}
}
}
public void logRefuse(Person person) {
}
public void logRefuseAux(Person person, String typeKey) {
final String infoLabel = BundleUtil.getString(Bundle.APPLICATION, typeKey);
final String personViewed = PersonInformationLog.getPersonNameForLogDescription(person);
if (getPrevPartyContact() == null) {
// no previous contact = new contact being created
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.create.need.valid.rejected", infoLabel, this.getPresentationValue(),
personViewed);
} else {
// has previous contact = edit
String oldValue = getPrevPartyContact().getPresentationValue();
if (oldValue.compareTo(getPresentationValue()) == 0) {
// previous value is the same
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.rejected", infoLabel, this.getPresentationValue(),
personViewed);
} else {
// previous is different, display previous value
PersonInformationLog.createLog(person, Bundle.MESSAGING,
"log.personInformation.contact.generic.edit.need.valid.values.rejected", infoLabel, getPrevPartyContact()
.getPresentationValue(), this.getPresentationValue(), personViewed);
}
}
}
private static Set<PartyContact> getAllInstancesOf(Class<? extends PartyContact> type) {
return ContactRoot.getInstance().getPartyContactsSet().stream().filter((type)::isInstance).collect(Collectors.toSet());
}
}