package jx

import 

// Encoder encodes json to underlying buffer.
//
// Zero value is valid.
type Encoder struct {
	w      Writer // underlying writer
	indent int    // count of spaces for single indentation level

	// first handles state for comma and indentation writing.
	//
	// New Object or Array appends new level to this slice, and
	// last element of this slice denotes whether first element was written.
	//
	// We write commas only before non-first element of Array or Object.
	//
	// See comma, begin, end and FieldStart for implementation details.
	//
	// Note: probably, this can be optimized as bit set to ease memory
	// consumption.
	//
	// See https://yourbasic.org/algorithms/your-basic-int/#simple-sets
	first []bool
}

// Write implements io.Writer.
func ( *Encoder) ( []byte) ( int,  error) {
	return .w.Write()
}

// WriteTo implements io.WriterTo.
func ( *Encoder) ( io.Writer) ( int64,  error) {
	return .w.WriteTo()
}

// SetIdent sets length of single indentation step.
func ( *Encoder) ( int) {
	.indent = 
}

// String returns string of underlying buffer.
func ( Encoder) () string {
	return .w.String()
}

// Reset resets underlying buffer.
//
// If e is in streaming mode, it is reset to non-streaming mode.
func ( *Encoder) () {
	.w.Reset()
	.first = .first[:0]
}

// ResetWriter resets underlying buffer and sets output writer.
func ( *Encoder) ( io.Writer) {
	.w.ResetWriter()
	.first = .first[:0]
}

// Grow grows the underlying buffer
func ( *Encoder) ( int) {
	.w.Grow()
}

// Bytes returns underlying buffer.
func ( Encoder) () []byte { return .w.Buf }

// SetBytes sets underlying buffer.
func ( *Encoder) ( []byte) { .w.Buf =  }

// byte writes a single byte.
func ( *Encoder) ( byte) bool {
	return .w.byte()
}

// RawStr writes string as raw json.
func ( *Encoder) ( string) bool {
	return .comma() ||
		.w.RawStr()
}

// Raw writes byte slice as raw json.
func ( *Encoder) ( []byte) bool {
	return .comma() ||
		.w.Raw()
}

// Null writes null.
func ( *Encoder) () bool {
	return .comma() ||
		.w.Null()
}

// Bool encodes boolean.
func ( *Encoder) ( bool) bool {
	return .comma() ||
		.w.Bool()
}

// ObjStart writes object start, performing indentation if needed.
//
// Use Obj as convenience helper for writing objects.
func ( *Encoder) () ( bool) {
	 = .comma() || .w.ObjStart()
	.begin()
	return  || .writeIndent()
}

// FieldStart encodes field name and writes colon.
//
// For non-zero indentation also writes single space after colon.
//
// Use Field as convenience helper for encoding fields.
func ( *Encoder) ( string) ( bool) {
	 = .comma() || .w.FieldStart()
	if .indent > 0 {
		 =  || .byte(' ')
	}
	if len(.first) > 0 {
		.first[.current()] = true
	}
	return 
}

// Field encodes field start and then invokes callback.
//
// Has ~5ns overhead over FieldStart.
func ( *Encoder) ( string,  func( *Encoder)) ( bool) {
	 = .FieldStart()
	// TODO(tdakkota): return bool from f?
	()
	return 
}

// ObjEnd writes end of object token, performing indentation if needed.
//
// Use Obj as convenience helper for writing objects.
func ( *Encoder) () bool {
	.end()
	return .writeIndent() || .w.ObjEnd()
}

// ObjEmpty writes empty object.
func ( *Encoder) () bool {
	return .comma() ||
		.w.ObjStart() ||
		.w.ObjEnd()
}

// Obj writes start of object, invokes callback and writes end of object.
//
// If callback is nil, writes empty object.
func ( *Encoder) ( func( *Encoder)) ( bool) {
	if  == nil {
		return .ObjEmpty()
	}
	 = .ObjStart()
	// TODO(tdakkota): return bool from f?
	()
	return  || .ObjEnd()
}

// ArrStart writes start of array, performing indentation if needed.
//
// Use Arr as convenience helper for writing arrays.
func ( *Encoder) () ( bool) {
	 = .comma() || .w.ArrStart()
	.begin()
	return  || .writeIndent()
}

// ArrEmpty writes empty array.
func ( *Encoder) () bool {
	return .comma() ||
		.w.ArrStart() ||
		.w.ArrEnd()
}

// ArrEnd writes end of array, performing indentation if needed.
//
// Use Arr as convenience helper for writing arrays.
func ( *Encoder) () bool {
	.end()
	return .writeIndent() ||
		.w.ArrEnd()
}

// Arr writes start of array, invokes callback and writes end of array.
//
// If callback is nil, writes empty array.
func ( *Encoder) ( func( *Encoder)) ( bool) {
	if  == nil {
		return .ArrEmpty()
	}
	 = .ArrStart()
	// TODO(tdakkota): return bool from f?
	()
	return  || .ArrEnd()
}

func ( *Encoder) () ( bool) {
	if .indent == 0 {
		return false
	}
	 = .byte('\n')
	for  := 0;  < len(.first)*.indent && !; ++ {
		 =  || .byte(' ')
	}
	return 
}