package starmap

import (
	"encoding/gob"
	"os"
	"time"

	"b612.me/notify"
)

func init() {
	notify.RegisterName("b612.me/starmap/kvmsg", kvMsg{})
	notify.RegisterName("b612.me/starmap/error", starMapErr{})
}

type starMapErr struct {
	Err string
}

func (s starMapErr) Error() string {
	return s.Err
}
func newStarMapErr(err error) error {
	if err == nil {
		return nil
	}
	return starMapErr{Err: err.Error()}
}

type kvMsg struct {
	Key   interface{}
	Value interface{}
	Err   error
}

type RemoteKv struct {
	server      notify.Server
	client      notify.Client
	kvmap       StarMapKV
	addr        string
	network     string
	readTimeout time.Duration
	timeout     time.Duration
}

func NewServer(network, addr string) (*RemoteKv, error) {
	var err error
	kv := RemoteKv{
		server:  notify.NewServer(),
		kvmap:   NewStarMap(),
		addr:    addr,
		network: network,
	}
	err = kv.server.Listen(network, addr)
	if err == nil {
		kv.bind()
	}
	return &kv, err
}

func NewClient(network, addr string, dialTimeout time.Duration) (*RemoteKv, error) {
	var err error
	kv := RemoteKv{
		client:      notify.NewClient(),
		kvmap:       NewStarMap(),
		addr:        addr,
		network:     network,
		timeout:     dialTimeout,
		readTimeout: time.Second * 5,
	}
	err = kv.client.ConnectTimeout(network, addr, dialTimeout)
	return &kv, err
}

func (kv *RemoteKv) Register(data interface{}) {
	gob.Register(data)
}

func (kv *RemoteKv) RegisterAll(data []interface{}) {
	for _, v := range data {
		gob.Register(v)
	}
}

func (kv *RemoteKv) bind() {
	//for server
	kv.server.SetDefaultLink(kv.dispatch)
	//for client
}

func (kv *RemoteKv) reconnect() error {
	if kv.server != nil {
		return nil
	}
	if kv.client != nil {
		if kv.client.Status().Alive {
			return nil
		}
		return kv.client.ConnectTimeout(kv.network, kv.addr, kv.timeout)
	}
	return os.ErrInvalid
}
