package service

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

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

	// 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 *Conn
	running bool
	requests requestManager
}

// Close closes the mount abruptly, interrupting any active connections.
func (htmount *HTTP) Close () error {
	htmount.running = false
	return htmount.conn.Close()
}

// Shutdown gracefully shuts down the service without interrupting any active
// connections.
func (htmount *HTTP) Shutdown () error {
	// TODO
	return htmount.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 (htmount *HTTP) Run (service ServiceInfo) (err error) {
	if htmount.AllowInsecure {
		htmount.MountInfo.Scheme = "http"
	} else {
		htmount.MountInfo.Scheme = "https"
	}
	htmount.conn, err = Dial(htmount.MountInfo, service)
	if err != nil { return }

	htmount.running = true	
	htmount.requests.init()

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

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

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

// NewHTTP creates a new HTTPS mount that uses the specified handler.
func NewHTTP (host, path string, handler http.Handler) *HTTP {
	return &HTTP {
		MountInfo: MountInfo {
			Host: host,
			Path: path,
		},
		Handler: handler,
	}
}
