/**
* 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.phd.seminar;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.fenixedu.academic.domain.Person;
import org.fenixedu.academic.domain.accessControl.academicAdministration.AcademicOperationType;
import org.fenixedu.academic.domain.caseHandling.Activity;
import org.fenixedu.academic.domain.caseHandling.PreConditionNotValidException;
import org.fenixedu.academic.domain.caseHandling.StartActivity;
import org.fenixedu.academic.domain.exceptions.DomainException;
import org.fenixedu.academic.domain.phd.PhdIndividualProgramDocumentType;
import org.fenixedu.academic.domain.phd.PhdIndividualProgramProcess;
import org.fenixedu.academic.domain.phd.PhdProgramProcessDocument;
import org.fenixedu.academic.domain.phd.alert.AlertService;
import org.fenixedu.academic.predicate.AccessControl;
import org.fenixedu.academic.util.Bundle;
import org.fenixedu.bennu.core.domain.User;
import org.fenixedu.bennu.core.i18n.BundleUtil;
import org.joda.time.LocalDate;
public class PublicPresentationSeminarProcess extends PublicPresentationSeminarProcess_Base {
static abstract private class PhdActivity extends Activity<PublicPresentationSeminarProcess> {
@Override
public void checkPreConditions(PublicPresentationSeminarProcess process, User userView) {
processPreConditions(process, userView);
activityPreConditions(process, userView);
}
protected void processPreConditions(final PublicPresentationSeminarProcess process, final User userView) {
if (process != null && process.isExempted()) {
throw new PreConditionNotValidException();
}
}
abstract protected void activityPreConditions(final PublicPresentationSeminarProcess process, final User userView);
}
@StartActivity
static public class RequestComission extends PhdActivity {
@Override
protected void processPreConditions(PublicPresentationSeminarProcess process, User userView) {
// overrided to prevent exempted test
}
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
// Activity on main process ensures access control
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess noProcess, User userView,
Object object) {
PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
final PublicPresentationSeminarProcess result =
new PublicPresentationSeminarProcess(bean.getPhdIndividualProgramProcess(), bean);
result.createState(PublicPresentationSeminarProcessStateType.WAITING_FOR_COMMISSION_CONSTITUTION,
userView.getPerson(), ((PublicPresentationSeminarProcessBean) object).getRemarks());
return result;
}
}
static public class SubmitComission extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.WAITING_FOR_COMMISSION_CONSTITUTION) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)
&& !process.getIndividualProgramProcess().isCoordinatorForPhdProgram(userView.getPerson())) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
bean.getDocument().setType(PhdIndividualProgramDocumentType.PUBLIC_PRESENTATION_SEMINAR_COMISSION);
process.addDocument(bean.getDocument(), userView.getPerson());
process.createState(PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION,
userView.getPerson(), bean.getRemarks());
if (bean.getGenerateAlert()) {
AlertService.alertAcademicOffice(process.getIndividualProgramProcess(),
AcademicOperationType.VIEW_PHD_PUBLIC_PRESENTATION_ALERTS,
"message.phd.alert.public.presentation.seminar.comission.validation.subject",
"message.phd.alert.public.presentation.seminar.comission.validation.body");
}
return process;
}
}
static public class ValidateComission extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
bean.getDocument().setType(PhdIndividualProgramDocumentType.PUBLIC_PRESENTATION_SEMINAR_COMISSION);
if (bean.getDocument().hasAnyInformation()) {
process.addDocument(bean.getDocument(), userView.getPerson());
}
process.createState(PublicPresentationSeminarProcessStateType.COMMISSION_VALIDATED, userView.getPerson(),
bean.getRemarks());
if (bean.getGenerateAlert()) {
AlertService.alertGuiders(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.comission.validated.subject",
"message.phd.alert.public.presentation.seminar.comission.validated.body");
AlertService.alertStudent(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.comission.validated.subject",
"message.phd.alert.public.presentation.seminar.comission.validated.body");
}
return process;
}
}
static public class RejectComission extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
PublicPresentationSeminarState mostRecentState = process.getMostRecentState();
PublicPresentationSeminarState.createWithGivenStateDate(process,
PublicPresentationSeminarProcessStateType.WAITING_FOR_COMMISSION_CONSTITUTION, userView.getPerson(),
bean.getRemarks(), mostRecentState.getStateDate().plus(5));
if (bean.getGenerateAlert()) {
AlertService.alertCoordinators(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.comission.rejected.subject",
"message.phd.alert.public.presentation.seminar.comission.rejected.body");
}
return process;
}
}
static public class SchedulePresentationDate extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.COMMISSION_VALIDATED) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)
&& !process.getIndividualProgramProcess().isCoordinatorForPhdProgram(userView.getPerson())) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
process.setPresentationDate(bean.getPresentationDate());
process.createState(PublicPresentationSeminarProcessStateType.PUBLIC_PRESENTATION_DATE_SCHEDULED,
userView.getPerson(), bean.getRemarks());
if (bean.getGenerateAlert()) {
AlertService.alertAcademicOffice(process.getIndividualProgramProcess(),
AcademicOperationType.VIEW_PHD_PUBLIC_PRESENTATION_ALERTS,
"message.phd.alert.public.presentation.seminar.scheduled.presentation.date.subject",
"message.phd.alert.public.presentation.seminar.scheduled.presentation.date.body");
AlertService.alertGuiders(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.scheduled.presentation.date.subject",
"message.phd.alert.public.presentation.seminar.scheduled.presentation.date.body");
AlertService.alertStudent(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.scheduled.presentation.date.subject",
"message.phd.alert.public.presentation.seminar.scheduled.presentation.date.body");
}
return process;
}
}
static public class UploadReport extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.PUBLIC_PRESENTATION_DATE_SCHEDULED) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)
&& !process.getIndividualProgramProcess().isGuider(userView.getPerson())) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
bean.getDocument().setType(PhdIndividualProgramDocumentType.PUBLIC_PRESENTATION_SEMINAR_REPORT);
process.addDocument(bean.getDocument(), userView.getPerson());
process.createState(PublicPresentationSeminarProcessStateType.REPORT_WAITING_FOR_VALIDATION, userView.getPerson(),
bean.getRemarks());
if (bean.getGenerateAlert()) {
AlertService.alertAcademicOffice(process.getIndividualProgramProcess(),
AcademicOperationType.VIEW_PHD_PUBLIC_PRESENTATION_ALERTS,
"message.phd.alert.public.presentation.seminar.report.uploaded.subject",
"message.phd.alert.public.presentation.seminar.report.uploaded.body");
}
return process;
}
}
static public class ValidateReport extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.REPORT_WAITING_FOR_VALIDATION) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
bean.getDocument().setType(PhdIndividualProgramDocumentType.PUBLIC_PRESENTATION_SEMINAR_REPORT);
if (bean.getDocument().hasAnyInformation()) {
process.addDocument(bean.getDocument(), userView.getPerson());
}
process.createState(PublicPresentationSeminarProcessStateType.REPORT_VALIDATED, userView.getPerson(),
bean.getRemarks());
if (bean.getGenerateAlert()) {
AlertService.alertCoordinators(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.report.validated.subject",
"message.phd.alert.public.presentation.seminar.report.validated.body");
AlertService.alertGuiders(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.report.validated.subject",
"message.phd.alert.public.presentation.seminar.report.validated.body");
AlertService.alertStudent(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.report.validated.subject",
"message.phd.alert.public.presentation.seminar.report.validated.body");
}
return process;
}
}
static public class RejectReport extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (process.getActiveState() != PublicPresentationSeminarProcessStateType.REPORT_WAITING_FOR_VALIDATION) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
final PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
process.createState(PublicPresentationSeminarProcessStateType.PUBLIC_PRESENTATION_DATE_SCHEDULED,
userView.getPerson(), bean.getRemarks());
if (bean.getGenerateAlert()) {
AlertService.alertGuiders(process.getIndividualProgramProcess(),
"message.phd.alert.public.presentation.seminar.report.rejected.subject",
"message.phd.alert.public.presentation.seminar.report.rejected.body");
}
return process;
}
}
static public class DownloadReportDocument extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.hasReportDocument()) {
throw new PreConditionNotValidException();
}
if (process.isAllowedToManageProcess(userView)
|| process.getIndividualProgramProcess().isCoordinatorForPhdProgram(userView.getPerson())
|| process.getIndividualProgramProcess().isGuiderOrAssistentGuider(userView.getPerson())) {
return;
}
if (process.getActiveState() == PublicPresentationSeminarProcessStateType.REPORT_VALIDATED
&& process.getIndividualProgramProcess().getPerson() == userView.getPerson()) {
return;
}
throw new PreConditionNotValidException();
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
// Nothing to be done
return null;
}
}
static public class DownloadComissionDocument extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.hasComissionDocument()) {
throw new PreConditionNotValidException();
}
if (process.isAllowedToManageProcess(userView)
|| process.getIndividualProgramProcess().isCoordinatorForPhdProgram(userView.getPerson())
|| process.getIndividualProgramProcess().isGuiderOrAssistentGuider(userView.getPerson())) {
return;
}
if (process.hasState(PublicPresentationSeminarProcessStateType.COMMISSION_VALIDATED)
&& process.getIndividualProgramProcess().getPerson() == userView.getPerson()) {
return;
}
throw new PreConditionNotValidException();
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
// Nothing to be done
return null;
}
}
static public class RevertToWaitingForComissionConstitution extends PhdActivity {
@Override
public void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.getActiveState().equals(PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION)) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
if (!process.getActiveState().equals(PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION)) {
throw new DomainException("error.PublicPresentationSeminarProcess.is.not.in.comission.waiting.for.validation");
}
PublicPresentationSeminarState mostRecentState = process.getMostRecentState();
PublicPresentationSeminarState.createWithGivenStateDate(process,
PublicPresentationSeminarProcessStateType.WAITING_FOR_COMMISSION_CONSTITUTION, userView.getPerson(), "",
mostRecentState.getStateDate().plusMinutes(1));
return process;
}
}
static public class RevertToWaitingComissionForValidation extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.getActiveState().equals(PublicPresentationSeminarProcessStateType.COMMISSION_VALIDATED)) {
throw new PreConditionNotValidException();
}
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
if (!process.getActiveState().equals(PublicPresentationSeminarProcessStateType.COMMISSION_VALIDATED)) {
throw new DomainException("error.PublicPresentationSeminarProcess.is.not.in.comission.validated.state");
}
PublicPresentationSeminarState mostRecentState = process.getMostRecentState();
PublicPresentationSeminarState.createWithGivenStateDate(process,
PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION, userView.getPerson(), "",
mostRecentState.getStateDate().plusMinutes(1));
return process;
}
}
static public class AddState extends PhdActivity {
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
process.createState(bean.getProcessState(), AccessControl.getPerson(), bean.getRemarks());
return process;
}
}
static public class RemoveLastState extends PhdActivity {
@Override
protected void processPreConditions(PublicPresentationSeminarProcess process, User userView) {
// no pre-conditions
}
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
process.removeLastState();
return process;
}
}
static public class EditProcessAttributes extends PhdActivity {
@Override
protected void processPreConditions(PublicPresentationSeminarProcess process, User userView) {
}
@Override
protected void activityPreConditions(PublicPresentationSeminarProcess process, User userView) {
if (!process.isAllowedToManageProcess(userView)) {
throw new PreConditionNotValidException();
}
}
@Override
protected PublicPresentationSeminarProcess executeActivity(PublicPresentationSeminarProcess process, User userView,
Object object) {
PublicPresentationSeminarProcessBean bean = (PublicPresentationSeminarProcessBean) object;
process.setPresentationDate(bean.getPresentationDate());
process.setPresentationRequestDate(bean.getPresentationRequestDate());
return process;
}
}
static private List<Activity> activities = new ArrayList<Activity>();
static {
activities.add(new SubmitComission());
activities.add(new ValidateComission());
activities.add(new RejectComission());
activities.add(new SchedulePresentationDate());
activities.add(new UploadReport());
activities.add(new ValidateReport());
activities.add(new RejectReport());
activities.add(new DownloadReportDocument());
activities.add(new DownloadComissionDocument());
activities.add(new RevertToWaitingForComissionConstitution());
activities.add(new RevertToWaitingComissionForValidation());
activities.add(new AddState());
activities.add(new RemoveLastState());
activities.add(new EditProcessAttributes());
}
@Override
public boolean isAllowedToManageProcess(User userView) {
return this.getIndividualProgramProcess().isAllowedToManageProcess(userView);
}
private PublicPresentationSeminarProcess(final PhdIndividualProgramProcess individualProcess,
final PublicPresentationSeminarProcessBean bean) {
super();
String[] args = {};
if (individualProcess == null) {
throw new DomainException("error.phd.PublicPresentationSeminarProcess.individualProgramProcess.cannot.be.null", args);
}
this.setIndividualProgramProcess(individualProcess);
if (!individualProcess.isMigratedProcess()) {
if (bean.getPresentationRequestDate() == null) {
throw new DomainException("error.seminar.PublicPresentationSeminarProcess.presentation.request.date.required");
}
}
setPresentationRequestDate(bean.getPresentationRequestDate());
}
public boolean hasReportDocument() {
return getReportDocument() != null;
}
public PhdProgramProcessDocument getReportDocument() {
return getLatestDocumentVersionFor(PhdIndividualProgramDocumentType.PUBLIC_PRESENTATION_SEMINAR_REPORT);
}
public boolean hasComissionDocument() {
return getComissionDocument() != null;
}
public PhdProgramProcessDocument getComissionDocument() {
return getLatestDocumentVersionFor(PhdIndividualProgramDocumentType.PUBLIC_PRESENTATION_SEMINAR_COMISSION);
}
@Override
public String getDisplayName() {
return BundleUtil.getString(Bundle.PHD, getClass().getSimpleName());
}
@Override
public boolean canExecuteActivity(User userView) {
return false;
}
@Override
public List<Activity> getActivities() {
return activities;
}
@Override
public PublicPresentationSeminarState getMostRecentState() {
return (PublicPresentationSeminarState) super.getMostRecentState();
}
@Override
public PublicPresentationSeminarProcessStateType getActiveState() {
return (PublicPresentationSeminarProcessStateType) super.getActiveState();
}
public void createState(final PublicPresentationSeminarProcessStateType type, final Person person, final String remarks) {
PublicPresentationSeminarState.createWithInferredStateDate(this, type, person, remarks);
}
@Override
protected Person getPerson() {
return getIndividualProgramProcess().getPerson();
}
public boolean isExempted() {
return getActiveState() == PublicPresentationSeminarProcessStateType.EXEMPTED;
}
public boolean isConcluded() {
return getActiveState() == PublicPresentationSeminarProcessStateType.REPORT_VALIDATED;
}
public List<PublicPresentationSeminarProcessStateType> getPossibleNextStates() {
PublicPresentationSeminarProcessStateType activeState = getActiveState();
if (activeState == null) {
return Collections.singletonList(PublicPresentationSeminarProcessStateType.WAITING_FOR_COMMISSION_CONSTITUTION);
}
switch (activeState) {
case WAITING_FOR_COMMISSION_CONSTITUTION:
final List<PublicPresentationSeminarProcessStateType> result =
new ArrayList<PublicPresentationSeminarProcessStateType>();
result.add(PublicPresentationSeminarProcessStateType.COMMISSION_WAITING_FOR_VALIDATION);
result.add(PublicPresentationSeminarProcessStateType.EXEMPTED);
return result;
case COMMISSION_WAITING_FOR_VALIDATION:
return Collections.singletonList(PublicPresentationSeminarProcessStateType.COMMISSION_VALIDATED);
case COMMISSION_VALIDATED:
return Collections.singletonList(PublicPresentationSeminarProcessStateType.PUBLIC_PRESENTATION_DATE_SCHEDULED);
case PUBLIC_PRESENTATION_DATE_SCHEDULED:
return Collections.singletonList(PublicPresentationSeminarProcessStateType.REPORT_WAITING_FOR_VALIDATION);
case REPORT_WAITING_FOR_VALIDATION:
return Collections.singletonList(PublicPresentationSeminarProcessStateType.REPORT_VALIDATED);
case EXEMPTED:
return Collections.emptyList();
}
return Collections.emptyList();
}
public void removeLastState() {
if (getStates().size() == 1) {
throw new DomainException("phd.seminar.PublicPresentationSeminarProcess.process.has.only.one.state");
}
getMostRecentState().delete();
}
@Override
public LocalDate getPresentationRequestDate() {
if (super.getPresentationRequestDate() != null) {
return super.getPresentationRequestDate();
}
if (!getIndividualProgramProcess().getStudyPlan().isExempted()) {
if (getIndividualProgramProcess().getRegistration().isConcluded()) {
return getIndividualProgramProcess().getRegistration().getConclusionDate().toLocalDate();
}
}
if (getPresentationDate() != null) {
return getPresentationDate().minusMonths(1);
}
return getIndividualProgramProcess().getWhenStartedStudies();
}
@Override
public java.util.Set<org.fenixedu.academic.domain.phd.seminar.PublicPresentationSeminarState> getStates() {
return getStatesSet();
}
@Override
public boolean hasAnyStates() {
return !getStatesSet().isEmpty();
}
}