/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.TreeSet;
import org.openmrs.util.NaturalStrings;
/**
* ProgramWorkflow
*/
public class ProgramWorkflow extends BaseOpenmrsMetadata implements java.io.Serializable {
private static final long serialVersionUID = 1L;
// ******************
// Properties
// ******************
private Integer programWorkflowId;
private Program program;
private Concept concept;
private Set<ProgramWorkflowState> states = new HashSet<ProgramWorkflowState>();
// ******************
// Constructors
// ******************
/** Default Constructor */
public ProgramWorkflow() {
}
/** Constructor with id */
public ProgramWorkflow(Integer programWorkflowId) {
setProgramWorkflowId(programWorkflowId);
}
// ******************
// Instance methods
// ******************
/**
* Adds a new {@link ProgramWorkflowState} to this ProgramWorkflow
*
* @param state - the {@link ProgramWorkflowState} to add
*/
public void addState(ProgramWorkflowState state) {
state.setProgramWorkflow(this);
getStates().add(state);
}
/**
* Removes a {@link ProgramWorkflowState} from this ProgramWorkflow
*
* @param state - the {@link ProgramWorkflowState} to remove
*/
public void removeState(ProgramWorkflowState state) {
if (getStates().contains(state)) {
getStates().remove(state);
state.setProgramWorkflow(null);
}
}
/**
* Retires a {@link ProgramWorkflowState}
*
* @param state - the {@link ProgramWorkflowState} to retire
*/
public void retireState(ProgramWorkflowState state) {
state.setRetired(true);
}
/**
* Returns a {@link ProgramWorkflowState} whose primary key id matches the input parameter
*
* @param programWorkflowStateId the primary key {@link Integer} id to match
* @return a {@link ProgramWorkflowState} whose identifier matches the passed
* <code>programWorkflowStateId</code>
*/
public ProgramWorkflowState getState(Integer programWorkflowStateId) {
for (ProgramWorkflowState s : getStates()) {
if (s.getProgramWorkflowStateId().equals(programWorkflowStateId)) {
return s;
}
}
return null;
}
/**
* Returns a {@link ProgramWorkflowState} whose Concept matches the passed concept
*
* @param concept the Concept to match
* @return Returns a {@link ProgramWorkflowState} whose {@link Concept} matches the passed
* <code>concept</code>
*/
public ProgramWorkflowState getState(Concept concept) {
for (ProgramWorkflowState s : getStates()) {
if (s.getConcept().equals(concept)) {
return s;
}
}
return null;
}
/**
* Returns a {@link ProgramWorkflowState} whose Concept name matches the passed name in any
* {@link Locale}
*
* @param name the Concept name to match in any {@link Locale}
* @return a {@link ProgramWorkflowState} whose {@link Concept} name matches the passed
* <code>name</code>
*/
public ProgramWorkflowState getState(String name) {
for (ProgramWorkflowState s : getStates()) {
if (s.getConcept().isNamed(name)) {
return s;
}
}
return null;
}
/**
* Returns a {@link ProgramWorkflowState} whose {@link Concept} has any {@link ConceptName} that
* matches the given <code>name</name>
*
* @param name the {@link ProgramWorkflowState} name, in any {@link Locale}
* @return a {@link ProgramWorkflowState} which has the passed <code>name</code> in any
* {@link Locale}
*/
public ProgramWorkflowState getStateByName(String name) {
for (ProgramWorkflowState s : getStates()) {
if (s.getConcept().isNamed(name)) {
return s;
}
}
return null;
}
/**
* Returns a Set<{@link ProgramWorkflowState}> including all non-retired ProgramWorkflowStates
* and all retired ProgramWorkflowStates in this ProgramWorkflow if <code>includeRetired</code>
* is true
*
* @param includeRetired - if false, returns only non-retired {@link ProgramWorkflowState}
* objects in this ProgramWorkflow
* @return Set<ProgramWorkflowState> - all ProgramWorkflowStates matching input parameters
*/
public Set<ProgramWorkflowState> getStates(boolean includeRetired) {
Set<ProgramWorkflowState> ret = new HashSet<ProgramWorkflowState>();
for (ProgramWorkflowState s : getStates()) {
if (includeRetired || !s.isRetired()) {
ret.add(s);
}
}
return ret;
}
/**
* Returns a Set<{@link ProgramWorkflowState}> including all ProgramWorkflowStates, sorted by
* {@link ConceptName}
*
* @return Set<ProgramWorkflowState> - all ProgramWorkflowStates, sorted by {@link ConceptName}
* @should sort names containing numbers intelligently
*/
public Set<ProgramWorkflowState> getSortedStates() {
final Comparator<String> naturalComparator = NaturalStrings.getNaturalComparator();
Comparator<ProgramWorkflowState> stateComparator = new Comparator<ProgramWorkflowState>() {
public int compare(ProgramWorkflowState o1, ProgramWorkflowState o2) {
return naturalComparator.compare(o1.getConcept().getName().getName(), o2.getConcept().getName().getName());
}
};
TreeSet<ProgramWorkflowState> sorted = new TreeSet<ProgramWorkflowState>(stateComparator);
if (getStates() != null) {
sorted.addAll(getStates());
}
return sorted;
}
/**
* Returns a List<{@link ProgramWorkflowState}> including all possible next
* ProgramWorkflowStates, for the passed {@link PatientProgram} ordered by {@link ConceptName}
*
* @param patientProgram - The PatientProgram to check
* @return List<ProgramWorkflowState> - all possible next ProgramWorkflowStates, for the passed
* {@link PatientProgram} ordered by {@link ConceptName}
*/
public List<ProgramWorkflowState> getPossibleNextStates(PatientProgram patientProgram) {
List<ProgramWorkflowState> ret = new ArrayList<ProgramWorkflowState>();
PatientState currentState = patientProgram.getCurrentState(this);
for (ProgramWorkflowState st : getSortedStates()) {
if (isLegalTransition(currentState == null ? null : currentState.getState(), st)) {
ret.add(st);
}
}
return ret;
}
/**
* Check whether it is allowable to transition from <code>fromState</code> to
* <code>toState</code>.
*
* @param fromState {@link ProgramWorkflowState} to check transition from
* @param toState {@link ProgramWorkflowState} to check transition to
* @return boolean true if it is allowable to transition from <code>fromState</code> to
* <code>toState</code>
*/
public boolean isLegalTransition(ProgramWorkflowState fromState, ProgramWorkflowState toState) {
// If there's no current state then we need tom move into an initial state
if (fromState == null) {
return toState.getInitial();
}
// Does not allow patient to move into the same state
if (fromState.equals(toState)) {
return false;
}
// Otherwise all other state transitions are legal
return true;
}
/** @see Object#equals(Object) */
@Override
public boolean equals(Object obj) {
if (obj != null && obj instanceof ProgramWorkflow) {
ProgramWorkflow p = (ProgramWorkflow) obj;
if (this.getProgramWorkflowId() != null) {
return (this.getProgramWorkflowId().equals(p.getProgramWorkflowId()));
}
}
return this == obj;
}
/** @see Object#toString() */
@Override
public String toString() {
return "ProgramWorkflow(id=" + getProgramWorkflowId() + ")";
}
// ******************
// Property Access
// ******************
public Set<ProgramWorkflowState> getStates() {
return states;
}
public void setStates(Set<ProgramWorkflowState> states) {
this.states = states;
}
public Concept getConcept() {
return concept;
}
public void setConcept(Concept concept) {
this.concept = concept;
}
public Program getProgram() {
return program;
}
public void setProgram(Program program) {
this.program = program;
}
public Integer getProgramWorkflowId() {
return programWorkflowId;
}
public void setProgramWorkflowId(Integer programWorkflowId) {
this.programWorkflowId = programWorkflowId;
}
/**
* @since 1.5
* @see org.openmrs.OpenmrsObject#getId()
*/
public Integer getId() {
return getProgramWorkflowId();
}
/**
* @since 1.5
* @see org.openmrs.OpenmrsObject#setId(java.lang.Integer)
*/
public void setId(Integer id) {
setProgramWorkflowId(id);
}
}