package wire

import (
	"fmt"
	"io"
)

// MaxV2AddrPerMsg is the maximum number of version 2 addresses that will exist
// in a single addrv2 message (MsgAddrV2).
const MaxV2AddrPerMsg = 1000

// MsgAddrV2 implements the Message interface and represents a bitcoin addrv2
// message that can support longer-length addresses like torv3, cjdns, and i2p.
// It is used to gossip addresses on the network. Each message is limited to
// MaxV2AddrPerMsg addresses. This is the same limit as MsgAddr.
type MsgAddrV2 struct {
	AddrList []*NetAddressV2
}

// BtcDecode decodes r using the bitcoin protocol into a MsgAddrV2.
func (m *MsgAddrV2) BtcDecode(r io.Reader, pver uint32,
	enc MessageEncoding) error {

	count, err := ReadVarInt(r, pver)
	if err != nil {
		return err
	}

	// Limit to max addresses per message.
	if count > MaxV2AddrPerMsg {
		str := fmt.Sprintf("too many addresses for message [count %v,"+
			" max %v]", count, MaxV2AddrPerMsg)
		return messageError("MsgAddrV2.BtcDecode", str)
	}

	addrList := make([]NetAddressV2, count)
	m.AddrList = make([]*NetAddressV2, 0, count)
	for i := uint64(0); i < count; i++ {
		na := &addrList[i]
		err := readNetAddressV2(r, pver, na)
		if err != nil {
			// A network address of a type we don't know of may be
			// safely skipped. All other errors mean we should stop
			// processing the message.
			if err == ErrSkippedNetworkID {
				continue
			}

			return err
		}

		m.AddrList = append(m.AddrList, na)
	}

	return nil
}

// BtcEncode encodes the MsgAddrV2 into a writer w.
func (m *MsgAddrV2) BtcEncode(w io.Writer, pver uint32,
	enc MessageEncoding) error {

	count := len(m.AddrList)
	if count > MaxV2AddrPerMsg {
		str := fmt.Sprintf("too many addresses for message: "+
			"got %v, max %v", count, MaxV2AddrPerMsg)
		return messageError("MsgAddrV2.BtcEncode", str)
	}

	err := WriteVarInt(w, pver, uint64(count))
	if err != nil {
		return err
	}

	for _, na := range m.AddrList {
		err = writeNetAddressV2(w, pver, na)
		if err != nil {
			return err
		}
	}

	return nil
}

// Command returns the protocol command string for MsgAddrV2.
func (m *MsgAddrV2) Command() string {
	return CmdAddrV2
}

// MaxPayloadLength returns the maximum length payload possible for MsgAddrV2.
func (m *MsgAddrV2) MaxPayloadLength(pver uint32) uint32 {
	// The varint that can store the maximum number of addresses is 3 bytes
	// long. The maximum payload is then 3 + 1000 * maxNetAddressV2Payload.
	return 3 + (MaxV2AddrPerMsg * maxNetAddressV2Payload())
}

// NewMsgAddrV2 returns a new bitcoin addrv2 message that conforms to the
// Message interface.
func NewMsgAddrV2() *MsgAddrV2 {
	return &MsgAddrV2{
		AddrList: make([]*NetAddressV2, 0, MaxV2AddrPerMsg),
	}
}
