func (p *Persons) OnlyPerson() (PatientID, *Person, error) {
	if !p.HasOnePerson() {
		return "", nil, errors.New("section Persons does not have one person only")
	}
	for k, v := range *p {
		return k, &v, nil
	}
	return "", nil, errors.New("no person found in the Persons section")
}
OnlyPerson returns the key and the value of the only item in the Persons map.
OnlyPerson returns an error if the pathway does not refer to exactly one person.
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
}
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{}
}