package service

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

func (mount *HTTP) handle (request protocol.MessageHTTPRequest) {
	log.Println("->?", request.Address, "requests", request.URL)
	bodyReader := &bodyReader {
		id:     request.ID,
		reader: mount.requests.readerFor(request.ID),
		send:   mount.send,
		close:  func () { mount.requests.end(request.ID) },
	}
	defer mount.requests.remove(request.ID)

	handler := mount.Handler
	if handler == nil {
		handler = http.DefaultServeMux
	}

	// TODO possibly populate the http version and ContentLength
	// TODO: if there is an error, send an error status to the server
	httpRequest, _ := http.NewRequest(request.Method, request.URL, bodyReader)
	httpRequest.Header = http.Header(request.Header)

	handler.ServeHTTP(&responseWriter {
		id:     request.ID,
		header: make(http.Header),
		send:   mount.send,
	}, httpRequest)

	mount.send(protocol.MessageHTTPBodyEnd { ID: request.ID })
}

type bodyReader struct {
	reader io.Reader
	requested bool
	id protocol.ID
	send  func (protocol.Message) error
	close func ()
}

func (reader *bodyReader) Read (buffer []byte) (amount int, err error) {
	if !reader.requested {
		err = reader.send(protocol.MessageHTTPBodyRequest {
			ID: reader.id,
		})
		if err != nil { return }
		reader.requested = true
	}
	return reader.reader.Read(buffer)
}

func (reader *bodyReader) Close () error {
	// TODO: possibly make this mthd ask the server to stop sending body
	// segments
	reader.close()
	return nil
}

type responseWriter struct {
	header http.Header
	wroteHeader bool
	id protocol.ID
	send func (protocol.Message) error
}

func (writer *responseWriter) Header () http.Header {
	return writer.header
}

func (writer *responseWriter) Write (buffer []byte) (amount int, err error) {
	if !writer.wroteHeader {
		writer.WriteHeader(http.StatusOK)
	}

	for len(buffer) > 0 {
		sent := int(protocol.MaxIntOfSize(2) - 1)
		if len(buffer) < sent {
			sent = len(buffer)
		}
		err = writer.send(protocol.MessageHTTPBodySegment {
			ID: writer.id,
			Data: buffer[:sent],
		})
		if err != nil { return }
		buffer = buffer[sent:]
		amount += sent
	}
	return
}

func (writer *responseWriter) WriteHeader (statusCode int) {
	if writer.wroteHeader { return }
	
	writer.wroteHeader = true
	writer.send(protocol.MessageHTTPResponse {
		ID:     writer.id,
		Status: uint16(statusCode),
		Header: protocol.Map(writer.header),
	})
}
