package chroma

import (
	
	
	
	
	
	
	
	
	
	
	

	
)

// Serialisation of Chroma rules to XML. The format is:
//
//	<rules>
//	  <state name="$STATE">
//	    <rule [pattern="$PATTERN"]>
//	      [<$EMITTER ...>]
//	      [<$MUTATOR ...>]
//	    </rule>
//	  </state>
//	</rules>
//
// eg. Include("String") would become:
//
//	<rule>
//	  <include state="String" />
//	</rule>
//
//	[null, null, {"kind": "include", "state": "String"}]
//
// eg. Rule{`\d+`, Text, nil} would become:
//
//	<rule pattern="\\d+">
//	  <token type="Text"/>
//	</rule>
//
// eg. Rule{`"`, String, Push("String")}
//
//	<rule pattern="\"">
//	  <token type="String" />
//	  <push state="String" />
//	</rule>
//
// eg. Rule{`(\w+)(\n)`, ByGroups(Keyword, Whitespace), nil},
//
//	<rule pattern="(\\w+)(\\n)">
//	  <bygroups token="Keyword" token="Whitespace" />
//	  <push state="String" />
//	</rule>
var (
	// ErrNotSerialisable is returned if a lexer contains Rules that cannot be serialised.
	ErrNotSerialisable = fmt.Errorf("not serialisable")
	emitterTemplates   = func() map[string]SerialisableEmitter {
		 := map[string]SerialisableEmitter{}
		for ,  := range []SerialisableEmitter{
			&byGroupsEmitter{},
			&usingSelfEmitter{},
			TokenType(0),
			&usingEmitter{},
			&usingByGroup{},
		} {
			[.EmitterKind()] = 
		}
		return 
	}()
	mutatorTemplates = func() map[string]SerialisableMutator {
		 := map[string]SerialisableMutator{}
		for ,  := range []SerialisableMutator{
			&includeMutator{},
			&combinedMutator{},
			&multiMutator{},
			&pushMutator{},
			&popMutator{},
		} {
			[.MutatorKind()] = 
		}
		return 
	}()
)

// fastUnmarshalConfig unmarshals only the Config from a serialised lexer.
func fastUnmarshalConfig( fs.FS,  string) (*Config, error) {
	,  := .Open()
	if  != nil {
		return nil, 
	}
	defer .Close()
	 := xml.NewDecoder()
	for {
		,  := .Token()
		if  != nil {
			if errors.Is(, io.EOF) {
				return nil, fmt.Errorf("could not find <config> element")
			}
			return nil, 
		}
		switch se := .(type) {
		case xml.StartElement:
			if .Name.Local != "config" {
				break
			}

			var  Config
			 = .DecodeElement(&, &)
			if  != nil {
				return nil, fmt.Errorf("%s: %w", , )
			}
			return &, nil
		}
	}
}

// MustNewXMLLexer constructs a new RegexLexer from an XML file or panics.
func ( fs.FS,  string) *RegexLexer {
	,  := NewXMLLexer(, )
	if  != nil {
		panic()
	}
	return 
}

// NewXMLLexer creates a new RegexLexer from a serialised RegexLexer.
func ( fs.FS,  string) (*RegexLexer, error) {
	,  := fastUnmarshalConfig(, )
	if  != nil {
		return nil, 
	}

	for ,  := range append(.Filenames, .AliasFilenames...) {
		,  := filepath.Match(, "")
		if  != nil {
			return nil, fmt.Errorf("%s: %q is not a valid glob: %w", .Name, , )
		}
	}

	var  func(string) float32

	if .Analyse != nil {
		type  struct {
			    *regexp2.Regexp
			 float32
		}

		 := make([], 0, len(.Analyse.Regexes))

		for ,  := range .Analyse.Regexes {
			,  := regexp2.Compile(.Pattern, regexp2.None)
			if  != nil {
				return nil, fmt.Errorf("%s: %q is not a valid analyser regex: %w", .Name, .Pattern, )
			}

			 = append(, {, .Score})
		}

		 = func( string) float32 {
			var  float32

			for ,  := range  {
				,  := ..MatchString()
				if  != nil {
					return 0
				}

				if  && .Analyse.First {
					return float32(math.Min(float64(.), 1.0))
				}

				if  {
					 += .
				}
			}

			return float32(math.Min(float64(), 1.0))
		}
	}

	return &RegexLexer{
		config:   ,
		analyser: ,
		fetchRulesFunc: func() (Rules, error) {
			var  struct {
				Config
				 Rules `xml:"rules"`
			}
			// Try to open .xml fallback to .xml.gz
			,  := .Open()
			if  != nil {
				if errors.Is(, fs.ErrNotExist) {
					 += ".gz"
					,  = .Open()
					if  != nil {
						return nil, 
					}
				} else {
					return nil, 
				}
			}
			defer .Close()
			var  io.Reader = 
			if strings.HasSuffix(, ".gz") {
				,  = gzip.NewReader()
				if  != nil {
					return nil, fmt.Errorf("%s: %w", , )
				}
			}
			 = xml.NewDecoder().Decode(&)
			if  != nil {
				return nil, fmt.Errorf("%s: %w", , )
			}
			return ., nil
		},
	}, nil
}

// Marshal a RegexLexer to XML.
func ( *RegexLexer) ([]byte, error) {
	type  struct {
		 Config `xml:"config"`
		  Rules  `xml:"rules"`
	}

	,  := .Rules()
	if  != nil {
		return nil, 
	}
	 := &{
		: *.Config(),
		:  ,
	}
	,  := xml.MarshalIndent(, "", "  ")
	if  != nil {
		return nil, 
	}
	 := regexp.MustCompile(`></[a-zA-Z]+>`)
	 = .ReplaceAll(, []byte(`/>`))
	return , nil
}

// Unmarshal a RegexLexer from XML.
func ( []byte) (*RegexLexer, error) {
	type  struct {
		 Config `xml:"config"`
		  Rules  `xml:"rules"`
	}
	 := &{}
	 := xml.Unmarshal(, )
	if  != nil {
		return nil, fmt.Errorf("invalid Lexer XML: %w", )
	}
	,  := NewLexer(&., func() Rules { return . })
	if  != nil {
		return nil, 
	}
	return , nil
}

func marshalMutator( *xml.Encoder,  Mutator) error {
	if  == nil {
		return nil
	}
	,  := .(SerialisableMutator)
	if ! {
		return fmt.Errorf("unsupported mutator: %w", ErrNotSerialisable)
	}
	return .EncodeElement(, xml.StartElement{Name: xml.Name{Local: .MutatorKind()}})
}

func unmarshalMutator( *xml.Decoder,  xml.StartElement) (Mutator, error) {
	 := .Name.Local
	,  := mutatorTemplates[]
	if ! {
		return nil, fmt.Errorf("unknown mutator %q: %w", , ErrNotSerialisable)
	}
	,  := newFromTemplate()
	if  := .DecodeElement(, &);  != nil {
		return nil, 
	}
	return ().(SerialisableMutator), nil
}

func marshalEmitter( *xml.Encoder,  Emitter) error {
	if  == nil {
		return nil
	}
	,  := .(SerialisableEmitter)
	if ! {
		return fmt.Errorf("unsupported emitter %T: %w", , ErrNotSerialisable)
	}
	return .EncodeElement(, xml.StartElement{
		Name: xml.Name{Local: .EmitterKind()},
	})
}

func unmarshalEmitter( *xml.Decoder,  xml.StartElement) (Emitter, error) {
	 := .Name.Local
	,  := emitterTemplates[]
	if ! {
		return nil, fmt.Errorf("unknown emitter %q: %w", , ErrNotSerialisable)
	}
	,  := newFromTemplate()
	if  := .DecodeElement(, &);  != nil {
		return nil, 
	}
	return ().(SerialisableEmitter), nil
}

func ( Rule) ( *xml.Encoder,  xml.StartElement) error {
	 := xml.StartElement{
		Name: xml.Name{Local: "rule"},
	}
	if .Pattern != "" {
		.Attr = append(.Attr, xml.Attr{
			Name:  xml.Name{Local: "pattern"},
			Value: .Pattern,
		})
	}
	if  := .EncodeToken();  != nil {
		return 
	}
	if  := marshalEmitter(, .Type);  != nil {
		return 
	}
	if  := marshalMutator(, .Mutator);  != nil {
		return 
	}
	return .EncodeToken(xml.EndElement{Name: .Name})
}

func ( *Rule) ( *xml.Decoder,  xml.StartElement) error {
	for ,  := range .Attr {
		if .Name.Local == "pattern" {
			.Pattern = .Value
			break
		}
	}
	for {
		,  := .Token()
		if  != nil {
			return 
		}
		switch token := .(type) {
		case xml.StartElement:
			,  := unmarshalMutator(, )
			if  != nil && !errors.Is(, ErrNotSerialisable) {
				return 
			} else if  == nil {
				if .Mutator != nil {
					return fmt.Errorf("duplicate mutator")
				}
				.Mutator = 
				continue
			}
			,  := unmarshalEmitter(, )
			if  != nil && !errors.Is(, ErrNotSerialisable) { // nolint: gocritic
				return 
			} else if  == nil {
				if .Type != nil {
					return fmt.Errorf("duplicate emitter")
				}
				.Type = 
				continue
			} else {
				return 
			}

		case xml.EndElement:
			return nil
		}
	}
}

type xmlRuleState struct {
	Name  string `xml:"name,attr"`
	Rules []Rule `xml:"rule"`
}

type xmlRules struct {
	States []xmlRuleState `xml:"state"`
}

func ( Rules) ( *xml.Encoder,  xml.StartElement) error {
	 := xmlRules{}
	for ,  := range  {
		.States = append(.States, xmlRuleState{
			Name:  ,
			Rules: ,
		})
	}
	return .EncodeElement(, xml.StartElement{Name: xml.Name{Local: "rules"}})
}

func ( *Rules) ( *xml.Decoder,  xml.StartElement) error {
	 := xmlRules{}
	if  := .DecodeElement(&, &);  != nil {
		return 
	}
	if * == nil {
		* = Rules{}
	}
	for ,  := range .States {
		(*)[.Name] = .Rules
	}
	return nil
}

type xmlTokenType struct {
	Type string `xml:"type,attr"`
}

func ( *TokenType) ( *xml.Decoder,  xml.StartElement) error {
	 := xmlTokenType{}
	if  := .DecodeElement(&, &);  != nil {
		return 
	}
	,  := TokenTypeString(.Type)
	if  != nil {
		return 
	}
	* = 
	return nil
}

func ( TokenType) ( *xml.Encoder,  xml.StartElement) error {
	.Attr = append(.Attr, xml.Attr{Name: xml.Name{Local: "type"}, Value: .String()})
	if  := .EncodeToken();  != nil {
		return 
	}
	return .EncodeToken(xml.EndElement{Name: .Name})
}

// This hijinks is a bit unfortunate but without it we can't deserialise into TokenType.
func newFromTemplate( interface{}) ( func() interface{},  interface{}) {
	 := reflect.TypeOf()
	if .Kind() == reflect.Ptr {
		 := reflect.New(.Elem())
		return .Interface, .Interface()
	}
	 := reflect.New()
	return func() interface{} { return .Elem().Interface() }, .Interface()
}

func ( *Emitters) ( *xml.Decoder,  xml.StartElement) error {
	for {
		,  := .Token()
		if  != nil {
			return 
		}
		switch token := .(type) {
		case xml.StartElement:
			,  := unmarshalEmitter(, )
			if  != nil {
				return 
			}
			* = append(*, )

		case xml.EndElement:
			return nil
		}
	}
}

func ( Emitters) ( *xml.Encoder,  xml.StartElement) error {
	if  := .EncodeToken();  != nil {
		return 
	}
	for ,  := range  {
		if  := marshalEmitter(, );  != nil {
			return 
		}
	}
	return .EncodeToken(xml.EndElement{Name: .Name})
}