package tls

import (
	
	
	
	

	
)

var ErrUnknownExtension = errors.New("extension name is unknown to the dictionary")

type ClientHelloSpecJSONUnmarshaler struct {
	CipherSuites       *CipherSuitesJSONUnmarshaler       `json:"cipher_suites"`
	CompressionMethods *CompressionMethodsJSONUnmarshaler `json:"compression_methods"`
	Extensions         *TLSExtensionsJSONUnmarshaler      `json:"extensions"`
	TLSVersMin         uint16                             `json:"min_vers,omitempty"` // optional
	TLSVersMax         uint16                             `json:"max_vers,omitempty"` // optional
}

func ( *ClientHelloSpecJSONUnmarshaler) () ClientHelloSpec {
	return ClientHelloSpec{
		CipherSuites:       .CipherSuites.CipherSuites(),
		CompressionMethods: .CompressionMethods.CompressionMethods(),
		Extensions:         .Extensions.Extensions(),
		TLSVersMin:         .TLSVersMin,
		TLSVersMax:         .TLSVersMax,
	}
}

type CipherSuitesJSONUnmarshaler struct {
	cipherSuites []uint16
}

func ( *CipherSuitesJSONUnmarshaler) ( []byte) error {
	var  []string
	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	for ,  := range  {
		if  == "GREASE" {
			.cipherSuites = append(.cipherSuites, GREASE_PLACEHOLDER)
			continue
		}

		if ,  := dicttls.DictCipherSuiteNameIndexed[];  {
			.cipherSuites = append(.cipherSuites, )
		} else {
			return fmt.Errorf("unknown cipher suite name: %s", )
		}
	}

	return nil
}

func ( *CipherSuitesJSONUnmarshaler) () []uint16 {
	return .cipherSuites
}

type CompressionMethodsJSONUnmarshaler struct {
	compressionMethods []uint8
}

func ( *CompressionMethodsJSONUnmarshaler) ( []byte) error {
	var  []string
	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	for ,  := range  {
		if ,  := dicttls.DictCompMethNameIndexed[];  {
			.compressionMethods = append(.compressionMethods, )
		} else {
			return fmt.Errorf("unknown compression method name: %s", )
		}
	}

	return nil
}

func ( *CompressionMethodsJSONUnmarshaler) () []uint8 {
	return .compressionMethods
}

type TLSExtensionsJSONUnmarshaler struct {
	AllowUnknownExt bool // if set, unknown extensions will be added as GenericExtension, without recovering ext payload
	UseRealPSK      bool // if set, PSK extension will be real PSK extension, otherwise it will be fake PSK extension
	extensions      []TLSExtensionJSON
}

func ( *TLSExtensionsJSONUnmarshaler) ( []byte) error {
	var  []tlsExtensionJSONAccepter
	if  := json.Unmarshal(, &);  != nil {
		return 
	}

	var  []TLSExtensionJSON = make([]TLSExtensionJSON, 0, len())
	for ,  := range  {
		if .extNameOnly.Name == "GREASE" {
			 = append(, &UtlsGREASEExtension{})
			continue
		}

		if ,  := dicttls.DictExtTypeNameIndexed[.extNameOnly.Name]; ! {
			return fmt.Errorf("%w: %s", ErrUnknownExtension, .extNameOnly.Name)
		} else {
			// get extension type from ID
			var  TLSExtension = ExtensionFromID()
			if  == nil {
				if .AllowUnknownExt {
					// fallback to generic extension, without recovering ext payload
					 = genericExtension(, .extNameOnly.Name)
				} else {
					return fmt.Errorf("extension %s (%d) is not JSON compatible", .extNameOnly.Name, )
				}
			}

			switch  {
			case extensionPreSharedKey:
				// PSK extension, need to see if we do real or fake PSK
				if .UseRealPSK {
					 = &UtlsPreSharedKeyExtension{}
				} else {
					 = &FakePreSharedKeyExtension{}
				}
			}

			if ,  := .(TLSExtensionJSON);  {
				 = append(, )
			} else {
				return fmt.Errorf("extension %s (%d) is not JSON compatible", .extNameOnly.Name, )
			}
		}
	}

	// unmashal extensions
	for ,  := range  {
		// json.Unmarshal will call the UnmarshalJSON method of the extension
		if  := json.Unmarshal([].origJsonInput, );  != nil {
			return 
		}
	}

	.extensions = 
	return nil
}

func ( *TLSExtensionsJSONUnmarshaler) () []TLSExtension {
	var  []TLSExtension = make([]TLSExtension, 0, len(.extensions))
	for ,  := range .extensions {
		 = append(, )
	}
	return 
}

func ( uint16,  string) TLSExtension {
	var  string = "WARNING: extension "
	 += fmt.Sprintf("%d ", )
	if len() > 0 {
		 += fmt.Sprintf("(%s) ", )
	}
	 += "is falling back to generic extension"
	 += "\n"

	fmt.Fprint(os.Stderr, )

	// fallback to generic extension
	return &GenericExtension{Id: }
}

type tlsExtensionJSONAccepter struct {
	extNameOnly struct {
		Name string `json:"name"`
	}
	origJsonInput []byte
}

func ( *tlsExtensionJSONAccepter) ( []byte) error {
	.origJsonInput = make([]byte, len())
	copy(.origJsonInput, )
	return json.Unmarshal(, &.extNameOnly)
}