/**
* 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.student.registrationStates;
import static org.fenixedu.academic.predicate.AccessControl.check;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ListIterator;
import java.util.Set;
import org.fenixedu.academic.domain.ExecutionYear;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.student.Registration;
import org.fenixedu.academic.domain.studentCurriculum.ExternalEnrolment;
import org.fenixedu.academic.domain.util.workflow.IState;
import org.fenixedu.academic.domain.util.workflow.StateBean;
import org.fenixedu.academic.domain.util.workflow.StateMachine;
import org.fenixedu.academic.dto.student.RegistrationStateBean;
import org.fenixedu.academic.predicate.AccessControl;
import org.fenixedu.academic.predicate.RegistrationStatePredicates;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.academic.util.EnrolmentAction;
import org.fenixedu.bennu.core.domain.Bennu;
import org.joda.time.DateTime;
import org.joda.time.YearMonthDay;
import pt.ist.fenixframework.dml.runtime.RelationAdapter;
/**
*
* @author - Shezad Anavarali (shezad@ist.utl.pt)
*
*/
public abstract class RegistrationState extends RegistrationState_Base implements IState {
static {
getRelationRegistrationStateRegistration().addListener(new RelationAdapter<RegistrationState, Registration>() {
@Override
public void afterAdd(RegistrationState state, Registration registration) {
super.afterAdd(state, registration);
if (registration != null && state != null) {
new RegistrationStateLog(state, EnrolmentAction.ENROL, AccessControl.getPerson());
}
}
@Override
public void beforeRemove(RegistrationState state, Registration registration) {
super.beforeRemove(state, registration);
if (registration != null && state != null) {
new RegistrationStateLog(state, EnrolmentAction.UNENROL, AccessControl.getPerson());
}
}
});
}
public static Comparator<RegistrationState> DATE_COMPARATOR = new Comparator<RegistrationState>() {
@Override
public int compare(RegistrationState leftState, RegistrationState rightState) {
int comparationResult = leftState.getStateDate().compareTo(rightState.getStateDate());
return (comparationResult == 0) ? leftState.getExternalId().compareTo(rightState.getExternalId()) : comparationResult;
}
};
public static Comparator<RegistrationState> DATE_AND_STATE_TYPE_COMPARATOR = new Comparator<RegistrationState>() {
@Override
public int compare(RegistrationState leftState, RegistrationState rightState) {
int comparationResult = DATE_COMPARATOR.compare(leftState, rightState);
if (comparationResult != 0) {
return comparationResult;
}
comparationResult = leftState.getStateType().compareTo(rightState.getStateType());
return (comparationResult == 0) ? leftState.getExternalId().compareTo(rightState.getExternalId()) : comparationResult;
}
};
public RegistrationState() {
super();
setRootDomainObject(Bennu.getInstance());
}
private static RegistrationState createState(Registration registration, Person person, DateTime dateTime,
RegistrationStateType stateType) {
RegistrationState newState = null;
switch (stateType) {
case REGISTERED:
newState = new RegisteredState(registration, person, dateTime);
break;
case CANCELED:
newState = new CanceledState(registration, person, dateTime);
break;
case CONCLUDED:
newState = new ConcludedState(registration, person, dateTime);
break;
case FLUNKED:
newState = new FlunkedState(registration, person, dateTime);
break;
case INTERRUPTED:
newState = new InterruptedState(registration, person, dateTime);
break;
case SCHOOLPARTCONCLUDED:
newState = new SchoolPartConcludedState(registration, person, dateTime);
break;
case STUDYPLANCONCLUDED:
newState = new StudyPlanConcludedState(registration, person, dateTime);
break;
case INTERNAL_ABANDON:
newState = new InternalAbandonState(registration, person, dateTime);
break;
case EXTERNAL_ABANDON:
newState = new ExternalAbandonState(registration, person, dateTime);
break;
case MOBILITY:
newState = new MobilityState(registration, person, dateTime);
break;
case TRANSITION:
newState = new TransitionalState(registration, person, dateTime);
break;
case TRANSITED:
newState = new TransitedState(registration, person, dateTime);
break;
case INACTIVE:
newState = new InactiveState(registration, person, dateTime);
break;
}
registration.getStudent().updateStudentRole();
return newState;
}
protected void init(Registration registration, Person responsiblePerson, DateTime stateDate) {
setStateDate(stateDate != null ? stateDate : new DateTime());
setRegistration(registration);
setResponsiblePerson(responsiblePerson != null ? responsiblePerson : AccessControl.getPerson());
}
protected void init(Registration registration) {
init(registration, null, null);
}
@Override
final public IState nextState() {
return nextState(new StateBean(defaultNextStateType().toString()));
}
protected RegistrationStateType defaultNextStateType() {
throw new DomainException("error.no.default.nextState.defined");
}
@Override
public IState nextState(final StateBean bean) {
return createState(getRegistration(), bean.getResponsible(), bean.getStateDateTime(),
RegistrationStateType.valueOf(bean.getNextState()));
}
@Override
final public void checkConditionsToForward() {
checkConditionsToForward(new RegistrationStateBean(defaultNextStateType()));
}
@Override
public void checkConditionsToForward(final StateBean bean) {
checkCurriculumLinesForStateDate(bean);
}
private void checkCurriculumLinesForStateDate(final StateBean bean) {
final ExecutionYear year = ExecutionYear.readByDateTime(bean.getStateDateTime());
final RegistrationStateType nextStateType = RegistrationStateType.valueOf(bean.getNextState());
if (nextStateType.canHaveCurriculumLinesOnCreation()) {
return;
}
if (getRegistration().hasAnyEnroledEnrolments(year)) {
throw new DomainException("RegisteredState.error.registration.has.enroled.enrolments.for.execution.year",
year.getName());
}
}
@Override
public Set<String> getValidNextStates() {
return Collections.emptySet();
}
public abstract RegistrationStateType getStateType();
public ExecutionYear getExecutionYear() {
return ExecutionYear.readByDateTime(getStateDate());
}
public void delete() {
check(this, RegistrationStatePredicates.deletePredicate);
RegistrationState nextState = getNext();
RegistrationState previousState = getPrevious();
if (nextState != null && previousState != null
&& !previousState.getValidNextStates().contains(nextState.getStateType().name())) {
throw new DomainException("error.cannot.delete.registrationState.incoherentState: "
+ previousState.getStateType().name() + " -> " + nextState.getStateType().name());
}
deleteWithoutCheckRules();
}
public void deleteWithoutCheckRules() {
final Registration registration = getRegistration();
try {
String responsablePersonName;
if (getResponsiblePerson() != null) {
responsablePersonName = getResponsiblePerson().getPresentationName();
} else {
responsablePersonName = "-";
}
org.fenixedu.academic.domain.student.RegistrationStateLog
.createRegistrationStateLog(getRegistration(), Bundle.MESSAGING,
"log.registration.registrationstate.removed", getStateType().getDescription(), getRemarks());
setRegistration(null);
setResponsiblePerson(null);
setRootDomainObject(null);
super.deleteDomainObject();
} finally {
registration.getStudent().updateStudentRole();
}
}
public RegistrationState getNext() {
List<RegistrationState> sortedRegistrationsStates =
new ArrayList<RegistrationState>(getRegistration().getRegistrationStatesSet());
Collections.sort(sortedRegistrationsStates, DATE_COMPARATOR);
for (ListIterator<RegistrationState> iter = sortedRegistrationsStates.listIterator(); iter.hasNext();) {
RegistrationState state = iter.next();
if (state.equals(this)) {
if (iter.hasNext()) {
return iter.next();
}
return null;
}
}
return null;
}
public RegistrationState getPrevious() {
List<RegistrationState> sortedRegistrationsStates =
new ArrayList<RegistrationState>(getRegistration().getRegistrationStatesSet());
Collections.sort(sortedRegistrationsStates, DATE_COMPARATOR);
for (ListIterator<RegistrationState> iter = sortedRegistrationsStates.listIterator(sortedRegistrationsStates.size()); iter
.hasPrevious();) {
RegistrationState state = iter.previous();
if (state.equals(this)) {
if (iter.hasPrevious()) {
return iter.previous();
}
return null;
}
}
return null;
}
public DateTime getEndDate() {
RegistrationState state = getNext();
return (state != null) ? state.getStateDate() : null;
}
public void setStateDate(YearMonthDay yearMonthDay) {
super.setStateDate(yearMonthDay.toDateTimeAtMidnight());
}
public static RegistrationState createRegistrationState(Registration registration, Person responsible, DateTime creation,
RegistrationStateType stateType) {
RegistrationStateBean bean = new RegistrationStateBean(registration);
bean.setResponsible(responsible);
bean.setStateDateTime(creation);
bean.setStateType(stateType);
return createRegistrationState(bean);
}
public static RegistrationState createRegistrationState(RegistrationStateBean bean) {
RegistrationState createdState = null;
final RegistrationState previousState = bean.getRegistration().getStateInDate(bean.getStateDateTime());
if (previousState == null) {
createdState =
RegistrationState.createState(bean.getRegistration(), null, bean.getStateDateTime(), bean.getStateType());
} else {
createdState = (RegistrationState) StateMachine.execute(previousState, bean);
}
createdState.setRemarks(bean.getRemarks());
final RegistrationState nextState = createdState.getNext();
if (nextState != null && !createdState.getValidNextStates().contains(nextState.getStateType().name())) {
throw new DomainException("error.cannot.add.registrationState.incoherentState");
}
org.fenixedu.academic.domain.student.RegistrationStateLog.createRegistrationStateLog(bean.getRegistration(),
Bundle.MESSAGING, "log.registration.registrationstate.added", bean.getStateType().getDescription(),
bean.getRemarks());
return createdState;
}
public boolean isActive() {
return getStateType().isActive();
}
public boolean includes(final ExternalEnrolment externalEnrolment) {
if (getStateType() == RegistrationStateType.MOBILITY) {
final DateTime mobilityDate = getStateDate();
return externalEnrolment.hasExecutionPeriod() && externalEnrolment.getExecutionYear().containsDate(mobilityDate);
}
throw new DomainException("RegistrationState.external.enrolments.only.included.in.mobility.states");
}
static public boolean hasAnyState(final Collection<RegistrationState> states, final Collection<RegistrationStateType> types) {
for (final RegistrationState state : states) {
if (types.contains(state.getStateType())) {
return true;
}
}
return false;
}
}