package libnmdc

import (
	"crypto/rand"
)

type HubConnectionOptions struct {
	Address           HubAddress
	SkipVerifyTLS     bool // using a negative verb, because bools default to false
	SkipAutoReconnect bool // as above
	Self              *UserInfo
	NickPassword      string
	AdcPID            string // blank: autogenerate
}

func NewPID() string {
	pidBytes := make([]byte, 24)
	n, err := rand.Read(pidBytes)
	if err != nil {
		panic(err) // Insufficient cryptographic randomness
	}

	if n != 24 {
		panic("Insufficient cryptographic randomness")
	}

	return Base32(pidBytes)
}

func (this *HubConnectionOptions) prepareConnection() *HubConnection {
	if this.Self.ClientTag == "" {
		this.Self.ClientTag = DEFAULT_CLIENT_TAG
		this.Self.ClientVersion = DEFAULT_CLIENT_VERSION
	}

	// Shouldn't be blank either
	if this.Self.ClientVersion == "" {
		this.Self.ClientVersion = "0"
	}

	if this.AdcPID == "" {
		this.AdcPID = NewPID()
	}

	hc := HubConnection{
		Hco:      this,
		HubName:  DEFAULT_HUB_NAME,
		State:    CONNECTIONSTATE_DISCONNECTED,
		users:    make(map[string]UserInfo),
		userSIDs: make(map[string]string),

		autoReconnect: !this.SkipAutoReconnect,
	}

	return &hc
}

// ConnectAsync connects to a hub server, and spawns a background goroutine to handle
// protocol messages. Events will be sent by channel to the supplied onEvent channel,
// the client is responsible for selecting off this.
func ConnectAsync(opts *HubConnectionOptions, onEvent chan HubEvent) *HubConnection {
	hc := opts.prepareConnection()
	hc.processEvent = func(ev HubEvent) {
		onEvent <- ev
	}

	go hc.worker()
	return hc
}

// ConnectSync connects to a hub server, and blocks forever to handle protocol messages.
// Client code should supply an event handling function as hco.OnEventSync.
func ConnectSync(opts *HubConnectionOptions, onEvent func(hub *HubConnection, ev HubEvent)) {
	hc := opts.prepareConnection()
	hc.processEvent = func(ev HubEvent) {
		onEvent(hc, ev)
	}
	hc.worker()
}
