package service

import "log"
import "net"
import "sync"
import "bufio"
import "errors"
import "net/http"
import "hnakra/protocol"

// HTTP is an https:// mount.
type HTTP struct {
	Mount

	// AllowInsecure allows this mount to respond to plain-text HTTP
	// requests. You can get a TLS cert for free nowadays so there are very
	// few cases where you'd want this on.
	AllowInsecure bool

	// Handler specifies the handler to invoke. If it is nil,
	// http.DefaultServeMux is used.
	Handler http.Handler

	conn net.Conn
	connLock sync.Mutex
	connReadWriter *bufio.ReadWriter
	requests requestManager
}

// Close closes the mount abruptly, interrupting any active connections.
func (mount *HTTP) Close () error {
	mount.connLock.Lock()
	defer mount.connLock.Unlock()
	return mount.conn.Close()
}

// Shutdown gracefully shuts down the service without interrupting any active
// connections.
func (mount *HTTP) Shutdown () error {
	// TODO
	return mount.Close()
}

// Run connects to the router, and blocks while fulfilling requests. This method
// will only return when the connection to the router has been closed.
func (mount *HTTP) Run () (err error) {
	if mount.AllowInsecure {
		mount.conn, err = mount.connect("http")
	} else {
		mount.conn, err = mount.connect("https")
	}
	if err != nil { return }
	
	mount.connReadWriter = bufio.NewReadWriter (
		bufio.NewReader(mount.conn),
		bufio.NewWriter(mount.conn))
	mount.requests.init()

	for {
		message, err := protocol.ReadMessage(mount.connReadWriter)
		if err != nil { return err }
		
		switch message.(type) {
		case protocol.MessageHTTPRequest:
			request := message.(protocol.MessageHTTPRequest)
			mount.requests.add(request.ID)
			go mount.handle(request)
		
		case protocol.MessageHTTPBodySegment:
			segment := message.(protocol.MessageHTTPBodySegment)
			mount.requests.feed(segment.ID, segment.Data)
		
		case protocol.MessageHTTPBodyEnd:
			end := message.(protocol.MessageHTTPBodyEnd)
			mount.requests.end(end.ID)

		case protocol.MessageStatus:
			status := message.(protocol.MessageStatus)
			log.Println("router says:", status.Status)

		default:
			mount.Close()
			return errors.New("router sent unknown type code")
		}
	}
}

// NewHTTP creates a very basic https:// mount with the specified name and
// description.
func NewHTTP (name, description string) HTTP {
	return HTTP { Mount: M(name, description) }
}

func (mount *HTTP) send (message protocol.Message) (err error) {
	mount.connLock.Lock()
	defer mount.connLock.Unlock()
	err = message.Send(mount.connReadWriter)
	if err != nil { return }
	return mount.connReadWriter.Flush()
}
