func (amp AMP) VMPPrescribingStatus() int64 {
	return amp.Relationship(VMPPrescribingStatus)
}
VMPPrescribingStatus returns whether the AMP's VMP is prescribable.
package dmd
import (
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"github.com/wardle/go-terminology/snomed"
	"github.com/wardle/go-terminology/terminology"
	"golang.org/x/text/language"
)
const (
	UKProduct                   = 10363601000001109
	ActualMedicinalProduct      = 10363901000001102
	ActualMedicinalProductPack  = 10364001000001104
	VirtualMedicinalProduct     = 10363801000001108
	VirtualMedicinalProductPack = 8653601000001108
	VirtuaTherapeuticMoiety     = 10363701000001104
	TradeFamily                 = 9191801000001103
	VtmReferenceSet  = 999000581000001102
	TfReferenceSet   = 999000631000001100
	AmpReferenceSet  = 999000541000001108
	AmppReferenceSet = 999000551000001106
	VmpReferenceSet  = 999000561000001109
	VmppReferenceSet = 999000571000001104
	NhsDmdRealmLanguageReferenceSet                = 999000671000001103  
	NhsRealmPharmacyLanguageReferenceSet           = 999000691000001104
	NhsRealmClinicalLanguageReferenceSet           = 999001261000000100
	NhsEPrescribingRouteAdministrationReferenceSet = 999000051000001100
	DoseFormReferenceSet               = 999000781000001107
	SugarFreeReferenceSet              = 999000601000001109
	GlutenFreeReferenceSet             = 999000611000001106
	PreservativeFreeReferenceSet       = 999000621000001102
	CombinationDrugVtm                 = 999000771000001105
	ChlorofluorocarbonFreeReferenceSet = 999000651000001105
	BlackTriangleReferenceSet          = 999000661000001108
	IsA                                  = 116680003
	PendingMove                          = 900000000000492006
	HasActiveIngredient                  = 127489000
	HasVmp                               = 10362601000001103
	HasAmp                               = 10362701000001108
	HasTradeFamilyGroup                  = 9191701000001107
	HasSpecificActiveIngredient          = 10362801000001104
	HasDispensedDoseForm                 = 10362901000001105  
	HasDoseForm                          = 411116001          
	HasExcipient                         = 8653101000001104
	PrescribingStatus                    = 8940001000001105
	NonAvailabilityIndicator             = 8940601000001102
	LegalCategory                        = 8941301000001102
	DiscontinuedIndicator                = 8941901000001101
	HasBasisOfStrength                   = 10363001000001101
	HasUnitOfAdministration              = 13085501000001109
	HasUnitOfPresentation                = 763032000
	HasNHSdmdBasisOfStrength             = 10363001000001101
	HasNHSControlledDrugCategory         = 13089101000001102
	HasVMPNonAvailabilityIndicator       = 8940601000001102
	VMPPrescribingStatus                 = 8940001000001105
	HasNHSdmdVmpRouteOfAdministration    = 13088401000001104
	HasNHSdmdVmpOntologyFormAndRoute     = 13088501000001100
	HasPresentationStrengthNumerator     = 732944001
	HasPresentationStrengthDenominator   = 732946004
	HasPresentationStrengthNumeratorUnit = 732945000
)
const (
	CautionAMPLevelPrescribingAdvised    = 13291401000001100
	NeverValidToPrescribeAsVrp           = 12459601000001102
	NeverValidToPrescribeAsVmp           = 8940401000001100
	NotRecommendedToPrescribeAsVmp       = 8940501000001101
	InvalidAsPrescribableProduct         = 8940301000001108
	NotRecommendedBrandsNotBioequivalent = 9900001000001104
	NotRecommendedNoProductSpecification = 12468201000001102
	NotRecommendedPatientTraining        = 9900101000001103
	VmpValidAsPrescribableProduct        = 8940201000001104
	VrpValidAsPrescribableProduct        = 12223601000001104
)
func prescribingStatus(statusConceptID int64) (valid bool, recommended bool) {
	switch statusConceptID {
	case CautionAMPLevelPrescribingAdvised:
		return true, false
	case NeverValidToPrescribeAsVrp:
		return false, false
	case NeverValidToPrescribeAsVmp:
		return false, false
	case NotRecommendedToPrescribeAsVmp:
		return true, false
	case InvalidAsPrescribableProduct:
		return false, false
	case NotRecommendedBrandsNotBioequivalent:
		return true, false
	case NotRecommendedNoProductSpecification:
		return true, false
	case NotRecommendedPatientTraining:
		return true, false
	case VmpValidAsPrescribableProduct:
		return true, true
	case VrpValidAsPrescribableProduct:
		return true, true
	}
	return false, false
}
type Product struct {
	svc *terminology.Svc
	*snomed.ExtendedConcept
}
func NewProduct(svc *terminology.Svc, ec *snomed.ExtendedConcept) Product {
	return Product{svc: svc, ExtendedConcept: ec}
}
func (p Product) String() string {
	if !p.IsProduct() {
		return p.ExtendedConcept.String()
	}
	var sb strings.Builder
	sb.WriteString(p.GetPreferredDescription().GetTerm())
	sb.WriteString(" (")
	switch {
	case p.IsVMP():
		sb.WriteString("VMP")
	case p.IsVMPP():
		sb.WriteString("VMPP")
	case p.IsAMP():
		sb.WriteString("AMP")
	case p.IsAMPP():
		sb.WriteString("AMPP")
	case p.IsVTM():
		sb.WriteString("VTM")
	case p.IsTradeFamily():
		sb.WriteString("TF")
	default:
		sb.WriteString("Unknown")
	}
	sb.WriteString(")")
	return sb.String()
}
func (p Product) PrettyPrint() string {
	s, _ := json.MarshalIndent(p, "", "\t")
	return string(s)
}
func (p Product) IsInReferenceSet(refset int64) bool {
	if p.ExtendedConcept == nil {
		return false
	}
	for _, rs := range p.ExtendedConcept.GetConceptRefsets() {
		if rs == refset {
			return true
		}
	}
	return false
}
func (p Product) Relationships(relationshipType int64) (result []int64) {
	if p.ExtendedConcept == nil {
		return
	}
	for _, rel := range p.ExtendedConcept.GetRelationships() {
		if rel.Active && rel.GetTypeId() == relationshipType {
			result = append(result, rel.DestinationId)
		}
	}
	return
}
func (p Product) Relationship(relationshipType int64) int64 {
	for _, rel := range p.ExtendedConcept.GetRelationships() {
		if rel.Active && rel.TypeId == relationshipType {
			return rel.DestinationId
		}
	}
	return 0
}
func (p Product) IsProduct() bool {
	if p.ExtendedConcept == nil {
		return false
	}
	if p.Concept.Id == UKProduct {
		return true
	}
	for _, rs := range p.ExtendedConcept.GetAllParentIds() {
		if rs == UKProduct {
			return true
		}
	}
	return false
}
func (p Product) IsAMP() bool {
	return p.IsInReferenceSet(AmpReferenceSet)
}
func (p Product) IsAMPP() bool {
	return p.IsInReferenceSet(AmppReferenceSet)
}
func (p Product) IsVTM() bool {
	return p.IsInReferenceSet(VtmReferenceSet)
}
func (p Product) IsVMP() bool {
	return p.IsInReferenceSet(VmpReferenceSet)
}
func (p Product) IsVMPP() bool {
	return p.IsInReferenceSet(VmppReferenceSet)
}
func (p Product) IsTradeFamily() bool {
	return p.IsInReferenceSet(TfReferenceSet)
}
func (p Product) IsSugarFree() bool {
	return p.IsInReferenceSet(SugarFreeReferenceSet)
}
type VMP struct {
	Product
}
func NewVMP(svc *terminology.Svc, ec *snomed.ExtendedConcept) (*VMP, error) {
	product := NewProduct(svc, ec)
	if product.IsVMP() {
		return &VMP{Product: product}, nil
	}
	return nil, fmt.Errorf("%s is not a VMP", product)
}
func (vmp VMP) PrescribingStatus() (valid, recommended bool) {
	return prescribingStatus(vmp.Relationship(PrescribingStatus))
}
func (vmp VMP) HasNHSControlledDrugCategory() int64 {
	return vmp.Relationship(HasNHSControlledDrugCategory)
}
func (vmp VMP) HasNHSdmdVmpRouteAdministration() int64 {
	return vmp.Relationship(HasNHSdmdVmpRouteOfAdministration)
}
func (vmp VMP) HasNHSdmdVmpOntologyFormAndRoute() int64 {
	return vmp.Relationship(HasNHSdmdVmpOntologyFormAndRoute)
}
func (vmp VMP) HasPresentationStrengthDenominator() []int64 {
	return vmp.Relationships(HasPresentationStrengthDenominator)
}
func (vmp VMP) HasPresentationStrengthNumerator() []int64 {
	return vmp.Relationships(HasPresentationStrengthNumerator)
}
func (vmp VMP) HasPresentationStrengthNumeratorUnit() []int64 {
	return vmp.Relationships(HasPresentationStrengthNumeratorUnit)
}
func (vmp VMP) HasBasisOfStrength() []int64 {
	return vmp.Relationships(HasNHSdmdBasisOfStrength)  
}
func (vmp VMP) VTMs() (result []int64) {
	for _, parent := range vmp.GetAllParentIds() {
		items, err := vmp.svc.ComponentFromReferenceSet(VtmReferenceSet, parent)
		if err == nil && len(items) > 0 {
			result = append(result, parent)
		}
	}
	return
}
func (vmp VMP) AMPs(ctx context.Context) (result []int64, err error) {
	children, err := vmp.svc.Children(vmp.GetConcept().GetId())
	if err != nil {
		return
	}
	for _, child := range children {
		isAmp, err := vmp.svc.IsInReferenceSet(child, AmpReferenceSet)
		if err != nil {
			return nil, err
		}
		if isAmp {
			result = append(result, child)
		}
	}
	return
}
func (vmp VMP) AllAMPs(ctx context.Context) (result []int64, err error) {
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()
	for child := range vmp.svc.StreamAllChildrenIDs(ctx, vmp.GetConcept().GetId(), 50000) {
		if child.Err != nil {
			err = child.Err
		}
		isAMP, err := vmp.svc.IsInReferenceSet(child.ID, AmpReferenceSet)
		if err != nil {
			return nil, err
		}
		if isAMP {
			result = append(result, child.ID)
		}
	}
	return
}
func (vmp VMP) VMPPs() (result []int64, err error) {
	rels, err := vmp.svc.ChildRelationships(vmp.ExtendedConcept.Concept.Id)
	if err != nil {
		return nil, err
	}
	for _, rel := range rels {
		if rel.Active && rel.TypeId == HasVmp {
			result = append(result, rel.SourceId)
		}
	}
	return
}
func (vmp VMP) SpecificActiveIngredients() (result []int64) {
	return vmp.Relationships(HasSpecificActiveIngredient)
}
func (vmp VMP) DisposedDoseForm() int64 {
	return vmp.Relationship(HasDispensedDoseForm)
}
type VTM struct {
	Product
}
func NewVTM(svc *terminology.Svc, ec *snomed.ExtendedConcept) (*VTM, error) {
	product := NewProduct(svc, ec)
	if product.IsVTM() {
		return &VTM{Product: product}, nil
	}
	return nil, fmt.Errorf("%s is not a VMP", product)
}
func (vtm VTM) AllVMPs(ctx context.Context) (result []int64, err error) {
	children := vtm.svc.StreamAllChildrenIDs(ctx, vtm.Concept.Id, 50000)
	for child := range children {
		if child.Err != nil {
			err = child.Err
			return
		}
		isVmp, err := vtm.svc.IsInReferenceSet(child.ID, VmpReferenceSet)
		if err != nil {
			return nil, err
		}
		if isVmp {
			result = append(result, child.ID)
		}
	}
	return
}
func (vtm VTM) VMPs(ctx context.Context) (result []int64, err error) {
	children, err := vtm.svc.Children(vtm.Concept.Id)
	if err != nil {
		return
	}
	for _, child := range children {
		isVmp, err := vtm.svc.IsInReferenceSet(child, VmpReferenceSet)
		if err != nil {
			return nil, err
		}
		if isVmp {
			result = append(result, child)
		}
	}
	return
}
func (vtm VTM) SpecificActiveIngredients(ctx context.Context, tags []language.Tag) ([]int64, error) {
	ingredients := make(map[int64]struct{})
	vmps, err := vtm.VMPs(ctx)
	if err != nil {
		return nil, err
	}
	for _, vmpID := range vmps {
		ec, err := vtm.svc.ExtendedConcept(vmpID, tags)
		if err != nil {
			return nil, err
		}
		vmp, err := NewVMP(vtm.svc, ec)
		if err != nil {
			return nil, err
		}
		for _, ingredient := range vmp.SpecificActiveIngredients() {
			ingredients[ingredient] = struct{}{}
		}
	}
	result := make([]int64, 0, len(ingredients))
	for ingredient := range ingredients {
		result = append(result, ingredient)
	}
	return result, nil
}
type AMP struct {
	Product
}
func NewAMP(svc *terminology.Svc, ec *snomed.ExtendedConcept) (*AMP, error) {
	product := NewProduct(svc, ec)
	if product.IsAMP() {
		return &AMP{Product: product}, nil
	}
	return nil, fmt.Errorf("%s is not an AMP", product)
}
func (amp AMP) AMPPs() (result []int64, err error) {
	rels, err := amp.svc.ChildRelationships(amp.ExtendedConcept.Concept.Id)
	if err != nil {
		return nil, err
	}
	for _, rel := range rels {
		if rel.Active && rel.TypeId == HasAmp {
			result = append(result, rel.SourceId)
		}
	}
	return
}
func (amp AMP) VMP() (vmp int64, err error) {
	var isVmp bool
	for _, parent := range amp.DirectParentIds {
		if isVmp, err = amp.svc.IsInReferenceSet(parent, VmpReferenceSet); err != nil {
			return
		}
		if isVmp {
			return parent, nil
		}
	}
	return
}
func (amp AMP) TF() (tf int64, err error) {
	var isTf bool
	for _, parent := range amp.DirectParentIds {
		if isTf, err = amp.svc.IsInReferenceSet(parent, TfReferenceSet); err != nil {
			return
		}
		if isTf {
			return parent, nil
		}
	}
	return
}
func (amp AMP) Excipients() (excipients []int64) {
	return amp.Relationships(HasExcipient)
}
func (amp AMP) ControlledDrugStatus() int64 {
	return amp.Relationship(HasNHSControlledDrugCategory)
}
func (amp AMP) VMPNonAvailabilityIndicator() int64 {
	return amp.Relationship(HasVMPNonAvailabilityIndicator)
}