func (p *Persons) isDefault() bool {
	if !p.HasOnePerson() {
		return false
	}
	patientIDs := make([]PatientID, 1)
	for pID := range *p {
		patientIDs[0] = pID
	}
	return patientIDs[0] == defaultPatientID && (*p)[defaultPatientID] == Person{}
}
isDefault returns whether the underlying map is the default one, ie:
if it contains only one empty Person.
Pathways without a persons section defined are initialized with default Persons
in the Init(pathwayName) function.
package pathway
import (
	"fmt"
	"math/rand"
	"reflect"
	"regexp"
	"sort"
	"strconv"
	"time"
	"github.com/pkg/errors"
	"github.com/google/simhospital/pkg/clock"
	"github.com/google/simhospital/pkg/constants"
	"github.com/google/simhospital/pkg/logging"
	"github.com/google/simhospital/pkg/orderprofile"
)
const (
	StepDelay                  = "Delay"
	StepAdmission              = "Admission"
	StepOrder                  = "Order"
	StepResults                = "Result"
	StepDischarge              = "Discharge"
	StepRegistration           = "Registration"
	StepPreAdmission           = "PreAdmission"
	StepTransfer               = "Transfer"
	StepAddPerson              = "AddPerson"
	StepUpdatePerson           = "UpdatePerson"
	StepMerge                  = "Merge"
	StepBedSwap                = "BedSwap"
	StepTransferInError        = "TransferInError"
	StepDischargeInError       = "DischargeInError"
	StepCancelVisit            = "CancelVisit"
	StepCancelTransfer         = "CancelTransfer"
	StepCancelDischarge        = "CancelDischarge"
	StepPendingAdmission       = "PendingAdmission"
	StepPendingDischarge       = "PendingDischarge"
	StepPendingTransfer        = "PendingTransfer"
	StepCancelPendingAdmission = "CancelPendingAdmission"
	StepCancelPendingDischarge = "CancelPendingDischarge"
	StepCancelPendingTransfer  = "CancelPendingTransfer"
	StepDeleteVisit            = "DeleteVisit"
	StepTrackDeparture         = "TrackDeparture"
	StepTrackArrival           = "TrackArrival"
	StepUsePatient             = "UsePatient"
	StepAutoGenerate           = "AutoGenerate"
	StepClinicalNote           = "ClinicalNote"
	StepHardcodedMessage       = "HardcodedMessage"
	StepDocument               = "Document"
	StepGeneric                = "Generic"
	StepGenerateResources      = "GenerateResources"
)
const (
	Current = "CURRENT"
	stepInvalid      = "Invalid"
	defaultPatientID = "main-patient"
)
const (
	TrackMode = "track"
	TransitMode = "transit"
	TemporaryMode = "temporary"
)
const (
	Append    = "append"
	Overwrite = "overwrite"
)
var (
	log = logging.ForCallerPackage()
	randomValues = map[string]bool{constants.NormalValue: true, constants.AbnormalHigh: true, constants.AbnormalLow: true}
	extractDecimalsRegexp = regexp.MustCompile(`[0-9]+.([0-9]+)`)
)
type Person struct {
	Age *Age
	DateOfBirth *time.Time `yaml:"date_of_birth"`
	Gender      Gender
	FirstName   string `yaml:"first_name"`
	Surname     OptionalRandomString
	Address     *Address
	NHS         string
	MRN         string
}
type Gender OptionalRandomString
func (g Gender) IsSet() bool {
	return g != ""
}
const (
	Male = Gender("M")
	Female = Gender("F")
)
type UpdatePerson struct {
	Person     *Person
	Diagnoses  []*DiagnosisOrProcedure
	Procedures []*DiagnosisOrProcedure
	Allergies  []Allergy
}
type OptionalRandomString string
func (s OptionalRandomString) IsSet() bool {
	return s != ""
}
func (s OptionalRandomString) IsFixedValue() bool {
	return IsFixedValue(s.String())
}
func IsFixedValue(s string) bool {
	return s != "" && s != constants.RandomString
}
func (s OptionalRandomString) String() string {
	return string(s)
}
type Address struct {
	AllRandom  bool                 `yaml:"all_random"`
	FirstLine  OptionalRandomString `yaml:"first_line"`
	SecondLine OptionalRandomString `yaml:"second_line"`
	City       OptionalRandomString
	Postcode   OptionalRandomString
	Country    OptionalRandomString
	Type OptionalRandomString
}
type Parameters struct {
	DelayMessage *Delay `yaml:"delay_message,omitempty"`
	TimeFromNow *time.Duration `yaml:"time_from_now,omitempty"`
	Status *DeathStatus
	SendingApplication string `yaml:"sending_application,omitempty"`
	ReceivingApplication string `yaml:"receiving_application,omitempty"`
	SendingFacility string `yaml:"sending_facility,omitempty"`
	ReceivingFacility string `yaml:"receiving_facility,omitempty"`
	Custom map[string]string `yaml:"custom,omitempty"`
}
type Order struct {
	OrderID string `yaml:"order_id"`
	OrderProfile string `yaml:"order_profile"`
	OrderStatus string `yaml:"order_status"`
	NoAcknowledgementMessage bool `yaml:"no_acknowledgement_message"`
}
type Results struct {
	OrderID string `yaml:"order_id"`
	OrderProfile string `yaml:"order_profile"`
	OrderStatus string `yaml:"order_status"`
	ResultStatus string `yaml:"results_status"`
	CollectedDateTime string `yaml:"collected_datetime"`
	ReceivedInLabDateTime string `yaml:"received_in_lab_datetime"`
	Results []*Result
	TriggerEvent string `yaml:"trigger_event"`
	ExpectCorrection bool `yaml:"expect_correction"`
}
type Result struct {
	TestName string `yaml:"test_name"`
	ID string
	ResultStatus string `yaml:"result_status"`
	Value string `yaml:"value"`
	Unit string
	ObservationDateTimeOffset time.Duration `yaml:"observation_datetime_offset"`
	ReferenceRange string `yaml:"reference_range"`
	AbnormalFlag constants.AbnormalFlag `yaml:"abnormal_flag"`
	Notes []string
}
type Admission struct {
	Loc         string
	Bed         string    `yaml:",omitempty"`
	Allergies   []Allergy `yaml:",omitempty"`
	AdmitReason string    `yaml:"admit_reason,omitempty"`
}
type Transfer struct {
	Loc string
	Bed string
}
type Discharge struct {
	Note          string
	Allergies     []Allergy  `yaml:",omitempty"`
	DischargeTime *time.Time `yaml:"discharge_time"`
}
type Generic struct {
	Name string
}
type Document struct {
	DocumentType string `yaml:"document_type"`
	CompletionStatus string `yaml:"completion_status"`
	ObsIdentifierID *string `yaml:"observation_identifier_id"`
	ObsIdentifierText *string `yaml:"observation_identifier_text"`
	ObsIdentifierCS *string `yaml:"observation_identifier_coding_system"`
	ID string
	UpdateType string `yaml:"update_type"`
	EndingContentLines []string `yaml:"ending_content_lines"`
	HeaderContentLines []string `yaml:"header_content_lines"`
	NumRandomContentLines *Interval `yaml:"num_random_content_lines"`
}
type Registration struct {
	PatientClass string `yaml:"patient_class"`
	Allergies    []Allergy
}
type PreAdmission struct {
	Loc string
	Bed string
	ExpectedAdmissionTimeFromNow *time.Duration `yaml:"expected_admission_time_from_now"`
	Allergies                    []Allergy
}
type TransferInError struct {
	Loc string
	Bed string
}
type DischargeInError struct {
	Note          string
	Allergies     []Allergy
	DischargeTime *time.Time `yaml:"discharge_time"`
}
type CancelVisit struct{}
type AddPerson struct {
	Allergies []Allergy
}
type CancelTransfer struct{}
type CancelDischarge struct{}
type PendingAdmission struct {
	Loc string
	Bed string
	ExpectedAdmissionTimeFromNow *time.Duration `yaml:"expected_admission_time_from_now"`
}
type PendingDischarge struct {
	ExpectedDischargeTimeFromNow *time.Duration `yaml:"expected_discharge_time_from_now"`
}
type PendingTransfer struct {
	Loc string
	Bed string
	ExpectedTransferTimeFromNow *time.Duration `yaml:"expected_transfer_time_from_now"`
}
type CancelPendingAdmission struct{}
type CancelPendingDischarge struct{}
type CancelPendingTransfer struct{}
type TrackDeparture struct {
	Mode string
	DestinationLoc string `yaml:"destination_loc"`
	DestinationBed string `yaml:"destination_bed"`
}
type TrackArrival struct {
	Mode string
	Loc string
	Bed string
	IsTemporary bool `yaml:"is_temporary"`
}
type Persons map[PatientID]Person
func (p *Persons) HasOnePerson() bool {
	return !p.isEmpty() && len(*p) == 1
}
func (p *Persons) isEmpty() bool {
	return p == nil || len(*p) == 0
}