// Copyright 2018 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.

package json

import (
	"strconv"
	"strings"

	"google.golang.org/protobuf/internal/detrand"
	"google.golang.org/protobuf/internal/errors"
)

// Encoder provides methods to write out JSON constructs and values. The user is
// responsible for producing valid sequences of JSON constructs and values.
type Encoder struct {
	indent   string
	lastType Type
	indents  []byte
	out      []byte
}

// NewEncoder returns an Encoder.
//
// If indent is a non-empty string, it causes every entry for an Array or Object
// to be preceded by the indent and trailed by a newline.
func NewEncoder(indent string) (*Encoder, error) {
	e := &Encoder{}
	if len(indent) > 0 {
		if strings.Trim(indent, " \t") != "" {
			return nil, errors.New("indent may only be composed of space or tab characters")
		}
		e.indent = indent
	}
	return e, nil
}

// Bytes returns the content of the written bytes.
func (e *Encoder) Bytes() []byte {
	return e.out
}

// WriteNull writes out the null value.
func (e *Encoder) WriteNull() {
	e.prepareNext(Null)
	e.out = append(e.out, "null"...)
}

// WriteBool writes out the given boolean value.
func (e *Encoder) WriteBool(b bool) {
	e.prepareNext(Bool)
	if b {
		e.out = append(e.out, "true"...)
	} else {
		e.out = append(e.out, "false"...)
	}
}

// WriteString writes out the given string in JSON string value.
func (e *Encoder) WriteString(s string) error {
	e.prepareNext(String)
	var err error
	if e.out, err = appendString(e.out, s); err != nil {
		return err
	}
	return nil
}

// WriteFloat writes out the given float and bitSize in JSON number value.
func (e *Encoder) WriteFloat(n float64, bitSize int) {
	e.prepareNext(Number)
	e.out = appendFloat(e.out, n, bitSize)
}

// WriteInt writes out the given signed integer in JSON number value.
func (e *Encoder) WriteInt(n int64) {
	e.prepareNext(Number)
	e.out = append(e.out, strconv.FormatInt(n, 10)...)
}

// WriteUint writes out the given unsigned integer in JSON number value.
func (e *Encoder) WriteUint(n uint64) {
	e.prepareNext(Number)
	e.out = append(e.out, strconv.FormatUint(n, 10)...)
}

// StartObject writes out the '{' symbol.
func (e *Encoder) StartObject() {
	e.prepareNext(StartObject)
	e.out = append(e.out, '{')
}

// EndObject writes out the '}' symbol.
func (e *Encoder) EndObject() {
	e.prepareNext(EndObject)
	e.out = append(e.out, '}')
}

// WriteName writes out the given string in JSON string value and the name
// separator ':'.
func (e *Encoder) WriteName(s string) error {
	e.prepareNext(Name)
	// Errors returned by appendString() are non-fatal.
	var err error
	e.out, err = appendString(e.out, s)
	e.out = append(e.out, ':')
	return err
}

// StartArray writes out the '[' symbol.
func (e *Encoder) StartArray() {
	e.prepareNext(StartArray)
	e.out = append(e.out, '[')
}

// EndArray writes out the ']' symbol.
func (e *Encoder) EndArray() {
	e.prepareNext(EndArray)
	e.out = append(e.out, ']')
}

// prepareNext adds possible comma and indentation for the next value based
// on last type and indent option. It also updates lastType to next.
func (e *Encoder) prepareNext(next Type) {
	defer func() {
		// Set lastType to next.
		e.lastType = next
	}()

	if len(e.indent) == 0 {
		// Need to add comma on the following condition.
		if e.lastType&(Null|Bool|Number|String|EndObject|EndArray) != 0 &&
			next&(Name|Null|Bool|Number|String|StartObject|StartArray) != 0 {
			e.out = append(e.out, ',')
			// For single-line output, add a random extra space after each
			// comma to make output unstable.
			if detrand.Bool() {
				e.out = append(e.out, ' ')
			}
		}
		return
	}

	switch {
	case e.lastType&(StartObject|StartArray) != 0:
		// If next type is NOT closing, add indent and newline.
		if next&(EndObject|EndArray) == 0 {
			e.indents = append(e.indents, e.indent...)
			e.out = append(e.out, '\n')
			e.out = append(e.out, e.indents...)
		}

	case e.lastType&(Null|Bool|Number|String|EndObject|EndArray) != 0:
		switch {
		// If next type is either a value or name, add comma and newline.
		case next&(Name|Null|Bool|Number|String|StartObject|StartArray) != 0:
			e.out = append(e.out, ',', '\n')

		// If next type is a closing object or array, adjust indentation.
		case next&(EndObject|EndArray) != 0:
			e.indents = e.indents[:len(e.indents)-len(e.indent)]
			e.out = append(e.out, '\n')
		}
		e.out = append(e.out, e.indents...)

	case e.lastType&Name != 0:
		e.out = append(e.out, ' ')
		// For multi-line output, add a random extra space after key: to make
		// output unstable.
		if detrand.Bool() {
			e.out = append(e.out, ' ')
		}
	}
}
