// Copyright 2023 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build goexperiment.jsonv2

package jsonopts

import (
	
	
)

// Options is the common options type shared across json packages.
type Options interface {
	// JSONOptions is exported so related json packages can implement Options.
	JSONOptions(internal.NotForPublicUse)
}

// Struct is the combination of all options in struct form.
// This is efficient to pass down the call stack and to query.
type Struct struct {
	Flags jsonflags.Flags

	CoderValues
	ArshalValues
}

type CoderValues struct {
	Indent       string // jsonflags.Indent
	IndentPrefix string // jsonflags.IndentPrefix
	ByteLimit    int64  // jsonflags.ByteLimit
	DepthLimit   int    // jsonflags.DepthLimit
}

type ArshalValues struct {
	// The Marshalers and Unmarshalers fields use the any type to avoid a
	// concrete dependency on *json.Marshalers and *json.Unmarshalers,
	// which would in turn create a dependency on the "reflect" package.

	Marshalers   any // jsonflags.Marshalers
	Unmarshalers any // jsonflags.Unmarshalers

	Format      string
	FormatDepth int
}

// DefaultOptionsV2 is the set of all options that define default v2 behavior.
var DefaultOptionsV2 = Struct{
	Flags: jsonflags.Flags{
		Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags),
		Values:   uint64(0),
	},
}

// DefaultOptionsV1 is the set of all options that define default v1 behavior.
var DefaultOptionsV1 = Struct{
	Flags: jsonflags.Flags{
		Presence: uint64(jsonflags.AllFlags & ^jsonflags.WhitespaceFlags),
		Values:   uint64(jsonflags.DefaultV1Flags),
	},
}

func (*Struct) (internal.NotForPublicUse) {}

// GetUnknownOption is injected by the "json" package to handle Options
// declared in that package so that "jsonopts" can handle them.
var GetUnknownOption = func(*Struct, Options) (any, bool) { panic("unknown option") }

func [ any]( Options,  func() Options) (, bool) {
	// Collapse the options to *Struct to simplify lookup.
	,  := .(*Struct)
	if ! {
		var  Struct
		.Join()
		 = &
	}

	// Lookup the option based on the return value of the setter.
	var  
	switch opt := ().(type) {
	case jsonflags.Bools:
		 := .Flags.Get()
		 := .Flags.Has()
		return any().(), 
	case Indent:
		if !.Flags.Has(jsonflags.Indent) {
			return , false
		}
		return any(.Indent).(), true
	case IndentPrefix:
		if !.Flags.Has(jsonflags.IndentPrefix) {
			return , false
		}
		return any(.IndentPrefix).(), true
	case ByteLimit:
		if !.Flags.Has(jsonflags.ByteLimit) {
			return , false
		}
		return any(.ByteLimit).(), true
	case DepthLimit:
		if !.Flags.Has(jsonflags.DepthLimit) {
			return , false
		}
		return any(.DepthLimit).(), true
	default:
		,  := GetUnknownOption(, )
		return .(), 
	}
}

// JoinUnknownOption is injected by the "json" package to handle Options
// declared in that package so that "jsonopts" can handle them.
var JoinUnknownOption = func(*Struct, Options) { panic("unknown option") }

func ( *Struct) ( ...Options) {
	.join(false, ...)
}

func ( *Struct) ( ...Options) {
	.join(true, ...)
}

func ( *Struct) ( bool,  ...Options) {
	for ,  := range  {
		switch src := .(type) {
		case nil:
			continue
		case jsonflags.Bools:
			if  {
				 &= ^jsonflags.AllCoderFlags
			}
			.Flags.Set()
		case Indent:
			if  {
				continue
			}
			.Flags.Set(jsonflags.Multiline | jsonflags.Indent | 1)
			.Indent = string()
		case IndentPrefix:
			if  {
				continue
			}
			.Flags.Set(jsonflags.Multiline | jsonflags.IndentPrefix | 1)
			.IndentPrefix = string()
		case ByteLimit:
			if  {
				continue
			}
			.Flags.Set(jsonflags.ByteLimit | 1)
			.ByteLimit = int64()
		case DepthLimit:
			if  {
				continue
			}
			.Flags.Set(jsonflags.DepthLimit | 1)
			.DepthLimit = int()
		case *Struct:
			 := .Flags // shallow copy the flags
			if  {
				.Clear(jsonflags.AllCoderFlags)
			}
			.Flags.Join()
			if .Has(jsonflags.NonBooleanFlags) {
				if .Has(jsonflags.Indent) {
					.Indent = .Indent
				}
				if .Has(jsonflags.IndentPrefix) {
					.IndentPrefix = .IndentPrefix
				}
				if .Has(jsonflags.ByteLimit) {
					.ByteLimit = .ByteLimit
				}
				if .Has(jsonflags.DepthLimit) {
					.DepthLimit = .DepthLimit
				}
				if .Has(jsonflags.Marshalers) {
					.Marshalers = .Marshalers
				}
				if .Has(jsonflags.Unmarshalers) {
					.Unmarshalers = .Unmarshalers
				}
			}
		default:
			JoinUnknownOption(, )
		}
	}
}

type (
	Indent       string // jsontext.WithIndent
	IndentPrefix string // jsontext.WithIndentPrefix
	ByteLimit    int64  // jsontext.WithByteLimit
	DepthLimit   int    // jsontext.WithDepthLimit
	// type for jsonflags.Marshalers declared in "json" package
	// type for jsonflags.Unmarshalers declared in "json" package
)

func (Indent) (internal.NotForPublicUse)       {}
func (IndentPrefix) (internal.NotForPublicUse) {}
func (ByteLimit) (internal.NotForPublicUse)    {}
func (DepthLimit) (internal.NotForPublicUse)   {}