package server

import (
	"fmt"
	"io"
	"strings"

	"git.loafle.net/commons_go/rpc"
	"git.loafle.net/commons_go/rpc/protocol"
)

type RPCServerHandlers struct {
	RPCRegistry rpc.Registry
	codecs      map[string]protocol.ServerCodec
}

// RegisterCodec adds a new codec to the server.
//
// Codecs are defined to process a given serialization scheme, e.g., JSON or
// XML. A codec is chosen based on the "Content-Type" header from the request,
// excluding the charset definition.
func (rpcSH *RPCServerHandlers) RegisterCodec(codec protocol.ServerCodec, contentType string) {
	if nil == rpcSH.codecs {
		rpcSH.codecs = make(map[string]protocol.ServerCodec)
	}
	rpcSH.codecs[strings.ToLower(contentType)] = codec
}

func (rpcSH *RPCServerHandlers) GetContentType(r io.Reader) string {
	return ""
}

func (rpcSH *RPCServerHandlers) OnPreRead(r io.Reader) {
	// no op
}

func (rpcSH *RPCServerHandlers) OnPostRead(r io.Reader) {
	// no op
}

func (rpcSH *RPCServerHandlers) OnPreWriteResult(w io.Writer, result interface{}) {
	// no op
}

func (rpcSH *RPCServerHandlers) OnPostWriteResult(w io.Writer, result interface{}) {
	// no op
}

func (rpcSH *RPCServerHandlers) OnPreWriteError(w io.Writer, err error) {
	// no op
}

func (rpcSH *RPCServerHandlers) OnPostWriteError(w io.Writer, err error) {
	// no op
}

func (rpcSH *RPCServerHandlers) Validate() {
	if nil == rpcSH.RPCRegistry {
		panic("RPCRegistry must be specified.")
	}
}

func (rpcSH *RPCServerHandlers) GetCodec(contentType string) (protocol.ServerCodec, error) {
	var codec protocol.ServerCodec
	if contentType == "" && len(rpcSH.codecs) == 1 {
		// If Content-Type is not set and only one codec has been registered,
		// then default to that codec.
		for _, c := range rpcSH.codecs {
			codec = c
		}
	} else if codec = rpcSH.codecs[strings.ToLower(contentType)]; codec == nil {
		return nil, fmt.Errorf("Unrecognized Content-Type: %s", contentType)
	}

	return codec, nil
}

func (rpcSH *RPCServerHandlers) invoke(codec protocol.RegistryCodec) (result interface{}, err error) {
	return rpcSH.RPCRegistry.Invoke(codec)
}