func segmentName(segment Token, d *Delimiters) (string, *ParseError) {
	if len(segment.Value) < 4 || segment.Value[3] != d.Field {
		l := len(segment.Value)
		if l == 3 {
			return string(segment.Value[:3]), nil
		}
		if l > 3 {
			l = 3
		}
		return "", segment.Error(&BadSegmentError{string(segment.Value[0:l])})
	}
	return string(segment.Value[:3]), nil
}
segmentName returns the name of the given segment.
Segment names are either 3 characters long, and are followed by the field delimiter.
If the value is exactly 3 characters long without a trailing field delimiter, we treat that as correct.
package hl7
import (
	"bytes"
	"fmt"
	"reflect"
	"regexp"
	"strings"
	"time"
	"github.com/pkg/errors"
	"golang.org/x/text/encoding/charmap"
	"golang.org/x/text/encoding"
	"golang.org/x/text/encoding/unicode"
	"github.com/google/simhospital/pkg/constants"
)
const (
	SegmentTerminator = constants.SegmentTerminator
	SegmentTerminatorStr = constants.SegmentTerminatorStr
	asciiNewLine byte = 0xa
)
var (
	Timezone string
	Location *time.Location
	encodings = map[string]encoding.Encoding{
		"ASCII":   encoding.Nop,
		"8859/1":  charmap.ISO8859_1,
		"8859/2":  charmap.ISO8859_2,
		"8859/3":  charmap.ISO8859_3,
		"8859/4":  charmap.ISO8859_4,
		"8859/5":  charmap.ISO8859_5,
		"8859/6":  charmap.ISO8859_6,
		"8859/7":  charmap.ISO8859_7,
		"8859/8":  charmap.ISO8859_8,
		"8859/9":  charmap.ISO8859_9,
		"8859/15": charmap.ISO8859_15,
		"UNICODE":       encoding.Nop,  
		"UNICODE UTF-8": encoding.Nop,  
	}
	null = []byte(`""`)
	segmentTypeRegex = regexp.MustCompile(`^[a-zA-Z0-9]{3}$`)
	messageTypeRegex = regexp.MustCompile(`^[a-zA-Z0-9]{3}_[a-zA-Z0-9]{3}$`)
	DefaultDelimiters = &Delimiters{
		Field:        '|',
		Component:    '^',
		Subcomponent: '&',
		Repetition:   '~',
		Escape:       '\\',
	}
	DefaultContextWithoutLocation = &Context{
		Decoder:    unicode.UTF8.NewDecoder(),
		Delimiters: DefaultDelimiters,
		Rewrite:    []Rewrite{NopRewrite},
		Nesting:    0,
	}
)
func TimezoneAndLocation(tz string) error {
	loc, err := time.LoadLocation(tz)
	if err != nil {
		return errors.Wrapf(err, "invalid timezone: %q", tz)
	}
	Timezone = tz
	Location = loc
	return nil
}
type Segment interface {
	SegmentName() string
}
type Context struct {
	Decoder    *encoding.Decoder
	Rewrite    []Rewrite
	Delimiters *Delimiters
	Nesting int
	TimezoneLoc     *time.Location
	IncludeTimezone bool
}
func (c *Context) Nested() *Context {
	newContext := *c
	newContext.Nesting++
	return &newContext
}
type ParseMessageOptions struct {
	TimezoneLoc *time.Location
	SegmentTerminator []byte
	Rewrites          *[]Rewrite
	AllowNullHeader   bool
}
func NewParseMessageOptions() *ParseMessageOptions {
	return &ParseMessageOptions{
		TimezoneLoc:       Location,
		SegmentTerminator: []byte{SegmentTerminator},
		Rewrites:          &[]Rewrite{NopRewrite},
	}
}
type Delimiters struct {
	Field        byte
	Component    byte
	Subcomponent byte
	Repetition   byte
	Escape       byte
}
var _ Primitive = (*Delimiters)(nil)
func (d *Delimiters) Marshal(_ *Context) ([]byte, error) {
	return []byte{d.Component, d.Repetition, d.Escape, d.Subcomponent}, nil
}
func (d *Delimiters) Unmarshal(field []byte, c *Context) error {
	if len(field) < 4 {
		return ErrBadValue
	}
	*d = Delimiters{
		Field:        c.Delimiters.Field,
		Component:    field[0],
		Repetition:   field[1],
		Escape:       field[2],
		Subcomponent: field[3],
	}
	c.Delimiters = d
	return nil
}
func (d Delimiters) splitFields(segment Token) []Token {
	return split(segment, d.Field)
}
func (d Delimiters) splitComponents(field Token, nesting int) []Token {
	switch nesting {
	case 0:
		return split(field, d.Component)
	case 1:
		return split(field, d.Subcomponent)
	default:
		return []Token{field}
	}
}
func (d Delimiters) joinComponents(components [][]byte, nesting int) []byte {
	if len(components) == 1 {
		return components[0]
	}
	switch nesting {
	case 0:
		return bytes.Join(components, []byte{d.Component})
	case 1:
		return bytes.Join(components, []byte{d.Subcomponent})
	default:
		panic("Too many nesting levels")
	}
}
func (d Delimiters) splitRepeated(field Token) []Token {
	return split(field, d.Repetition)
}
func (d Delimiters) joinRepeated(repetitions [][]byte) []byte {
	return bytes.Join(repetitions, []byte{d.Repetition})
}
func split(input Token, delimiter byte) []Token {
	return splitMultiCharDelimiter(input, []byte{delimiter})
}
func splitMultiCharDelimiter(input Token, delimiter []byte) []Token {
	r := make([]Token, 0, 16)
	start := 0
	tks := bytes.Split(input.Value, delimiter)
	for _, tk := range tks {
		r = append(r, Token{tk, input.Offset + start, input.Location})
		start += len(tk) + len(delimiter)
	}
	return r
}
type BadSegmentError struct {
	Name string
}
func (e *BadSegmentError) Error() string {
	return fmt.Sprintf("bad segment %q", e.Name)
}
type BadMessageTypeError struct {
	Name string
}
type MessageType interface {
	MessageTypeName() string
}
func (e *BadMessageTypeError) Error() string {
	errMsg := "bad message type"
	if segmentTypeRegex.MatchString(e.Name) || messageTypeRegex.MatchString(e.Name) {
		return fmt.Sprintf("%s: %s", errMsg, e.Name)
	}
	return errMsg
}
func toSegment(v reflect.Value) (Segment, bool) {
	segment := reflect.ValueOf((*Segment)(nil)).Type().Elem()
	if v.Type().Implements(segment) {
		return v.Interface().(Segment), true
	}
	if reflect.PtrTo(v.Type()).Implements(segment) {
		return v.Addr().Interface().(Segment), true
	}
	return nil, false
}
var ErrBadValue = errors.New("bad value for primitive HL7 type")
type ParseError struct {
	Offset   int
	Location string
	Cause    error
}
func (e *ParseError) Error() string {
	return fmt.Sprintf("error in %s: %v", e.Location, e.Cause.Error())
}
type ParseErrors []ParseError
func (e ParseErrors) Error() string {
	s := make([]string, len(e))
	for i, err := range e {
		s[i] = err.Error()
	}
	return fmt.Sprintf("errors (%d): %s", len(e), strings.Join(s, ", "))
}
type Token struct {
	Value  []byte
	Offset int
	Location string
}
func (t Token) Error(err error) *ParseError {
	return &ParseError{t.Offset, t.Location, err}
}
func (t Token) Errors(err error) ParseErrors {
	return ParseErrors{*t.Error(err)}
}
func parseTag(f reflect.StructField) (string, bool) {
	parts := strings.SplitN(f.Tag.Get("hl7"), ",", 2)
	if len(parts) == 2 {
		return parts[1], parts[0] == "true"
	}
	return parts[0], false
}
func fieldLocation(t reflect.Type, i int) string {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	name, _ := parseTag(t.Field(i))
	if name != "" {
		name = "-" + name
	}
	return fmt.Sprintf("%s-%d%s", t.Name(), i+1, name)
}
func appendLocation(location string, next string) string {
	if location != "" {
		return location + "/" + next
	}
	return next
}
type Message struct {
	*Context
	Segments []Token
	msh      MSH
}
func (m *Message) messageTypeName() (string, error) {
	if m.msh.MessageType == nil || m.msh.MessageType.MessageCode == nil {
		return "", &BadMessageTypeError{}
	}
	name := string(*m.msh.MessageType.MessageCode)
	if m.msh.MessageType.TriggerEvent != nil {
		name += "_" + string(*m.msh.MessageType.TriggerEvent)
	}
	return name, nil
}
type StringSet map[string]bool
func ParseMessage(input []byte) (*Message, error) {
	mo := NewParseMessageOptions()
	return ParseMessageWithOptions(input, mo)
}
func ParseMessageWithOptions(input []byte, options *ParseMessageOptions) (*Message, error) {
	m := &Message{
		Context: &Context{
			Decoder:     encoding.Nop.NewDecoder(),
			Delimiters:  DefaultDelimiters,
			Nesting:     0,
			TimezoneLoc: options.TimezoneLoc,
			Rewrite:     *options.Rewrites,
		},
		Segments: splitMultiCharDelimiter(Token{input, 0, ""}, options.SegmentTerminator),
	}
	if len(input) < 8 || !bytes.HasPrefix(input, []byte("MSH")) {
		if !options.AllowNullHeader {
			return nil, errors.New("Bad HL7 MSH header")
		}
		return m, nil
	}
	m.Delimiters = &Delimiters{
		Field: input[3],
	}
	rewriteRes, err := parseSegment(m.Segments[0].Value, m.Context, &m.msh)
	if err != nil {
		return nil, err
	}
	if rewriteRes.action == deleteToken {
		return nil, errors.New("MSH segment was deleted during rewrite")
	}
	if len(m.msh.CharacterSet) > 0 && m.msh.CharacterSet[0] != "" {
		enc, ok := encodings[strings.TrimSpace(string(m.msh.CharacterSet[0]))]
		if !ok {
			return nil, fmt.Errorf("bad character set: %q", string(m.msh.CharacterSet[0]))
		}
		m.Context.Decoder = enc.NewDecoder()
	}
	return m, nil
}
func parseCompositeValue(input Token, c *Context, v reflect.Value) error {
	components := c.Delimiters.splitComponents(input, c.Nesting)
	errs := ParseErrors{}
	for i := 0; i < v.NumField(); i++ {
		if i >= len(components) {
			break
		}
		component := components[i]
		component.Location = appendLocation(component.Location, fieldLocation(v.Type(), i))
		err := parseValue(component, c.Nested(), v.Field(i))
		if err != nil {
			if perr, ok := err.(ParseErrors); ok {
				errs = append(errs, perr...)
			} else {
				return err
			}
		}
	}
	if len(errs) == 0 {
		return nil
	}
	return errs
}
func parseSegment(input []byte, c *Context, v interface{}) (*RewriteResult, error) {
	return parseSegmentValue(Token{input, 0, ""}, c, reflect.ValueOf(v).Elem())
}
func parseSegmentValue(input Token, c *Context, v reflect.Value) (*RewriteResult, error) {
	input.Location = v.Type().Name()
	vType := v.Type()
	if vType.Kind() == reflect.Ptr {
		vType = vType.Elem()
	}
	input.Location = vType.Name()
	rwRes, err := rewrite(c, input)
	if err != nil {
		return nil, err
	}
	switch rwRes.action {
	case noop:
	case replaceValue:
		input.Value = rwRes.value
	case deleteToken:
		return rwRes, nil
	default:
		return nil, fmt.Errorf("Unknown rewriteAction value: %v", rwRes.action)
	}
	fields := c.Delimiters.splitFields(input)
	errs := ParseErrors{}
	for i := 0; i < v.NumField(); i++ {
		if i+1 >= len(fields) {
			break
		}
		field := fields[i+1]
		field.Location = fieldLocation(v.Type(), i)
		err := parseValue(field, c, v.Field(i))
		if err != nil {
			if perr, ok := err.(ParseErrors); ok {
				errs = append(errs, perr...)
			} else {
				return rwRes, err
			}
		}
	}
	if len(errs) == 0 {
		return rwRes, nil
	}
	return rwRes, errs
}
func parseRepeatedValue(input Token, c *Context, v reflect.Value) error {
	elements := c.Delimiters.splitRepeated(input)
	errs := ParseErrors{}
	slice := reflect.MakeSlice(v.Type(), len(elements), len(elements))
	for i := 0; i < len(elements); i++ {
		err := parseValue(elements[i], c, slice.Index(i))
		if err != nil {
			if perr, ok := err.(ParseErrors); ok {
				errs = append(errs, perr...)
			} else {
				return err
			}
		}
	}
	v.Set(slice)
	if len(errs) == 0 {
		return nil
	}
	return errs
}
func isHL7Null(field []byte) bool {
	return bytes.Equal(field, null)
}
func parseValue(input Token, c *Context, v reflect.Value) error {
	if !v.CanSet() {
		panic("Can't set value")  
	}
	rwRes, err := rewrite(c, input)
	if err != nil {
		return err
	}
	switch rwRes.action {
	case noop:
	case replaceValue:
		input.Value = rwRes.value
	case deleteToken:
		return nil
	default:
		return fmt.Errorf("Unknown rewriteAction value: %v", rwRes.action)
	}
	if len(input.Value) == 0 {
		return nil
	}
	var primitive Primitive
	primitiveType := reflect.TypeOf((*Primitive)(nil)).Elem()
	if v.Type().Implements(primitiveType) {
		n := reflect.New(v.Type().Elem())
		v.Set(n)
		primitive = n.Interface().(Primitive)
	} else if reflect.PtrTo(v.Type()).Implements(primitiveType) {
		primitive = v.Addr().Interface().(Primitive)
	}
	if primitive != nil {
		err := primitive.Unmarshal(input.Value, c)
		if err != nil {
			return input.Errors(err)
		}
		return nil
	}
	switch v.Kind() {
	case reflect.Ptr:
		n := reflect.New(v.Type().Elem())
		v.Set(n)
		return parseCompositeValue(input, c, n.Elem())
	case reflect.Slice:
		return parseRepeatedValue(input, c, v)
	case reflect.Struct:
		return parseCompositeValue(input, c, v)
	default:
		panic("Unexpected kind: " + string(v.Kind()) + " type: " + v.Type().Name())  
	}
}