package scalaz
package http
package response
import request.Request
import request.UserAgent
import Scalaz._
import Util._
import Util.Nel._
sealed trait Response[OUT[_]] {
val line: StatusLine
val headers: List[(ResponseHeader, NonEmptyList[Char])]
val body: OUT[Byte]
import Response.response
def apply(h: ResponseHeader, v: NonEmptyList[Char]) = response[OUT](line, (h, v) :: headers, body)
def apply(h: ResponseHeader, s: String): Response[OUT] = apply(h, s.charsNelErr("Header values must be non-empty"))
def apply(l: StatusLine) = response[OUT](l, headers, body)
def apply(h: ResponseHeader) = headersMapHeads.get(h)
def >>(b: OUT[Byte]) = response[OUT](line, headers, b)
def |+|(b: OUT[Byte])(implicit s: Semigroup[OUT[Byte]]) = response[OUT](line, headers, s.append(body, b))
def -(h: ResponseHeader) = response[OUT](line, headers filter { case (k, _) => h != k }, body)
def <<[A](a: A)(implicit b: Body[OUT, A], s: Semigroup[OUT[Byte]]) = response[OUT](line, headers, s.append(body, b(a)))
def <<:[A](a: A)(implicit b: Body[OUT, A], s: Semigroup[OUT[Byte]]) = response[OUT](line, headers, s.append(b(a), body))
lazy val headersMap = asHashMap[List, NonEmptyList](headers)
lazy val headersMapHeads = mapHeads(headersMap)
def versionMajor = line.version.major
def versionMinor = line.version.minor
def status = line.status
def reasonPhrase = line.reasonPhrase
def isOK = status == OK
def isBadRequest = status == BadRequest
def contentType(f: NonEmptyList[Char] => Boolean) =
(this(ContentType): Iterable[NonEmptyList[Char]]) exists f
def contentTypeEquals(s: String) = contentType(_.mkString == s)
def hasContentType = this(ContentType).isDefined
def bodyLength(implicit f: Foldable[OUT]) = body.count
def bodyString(implicit e: Each[OUT]) = {
val s = new StringBuilder
e.each(body, (b: Byte) => s append (b.toChar))
s.toString
}
def html = this(ContentType, "text/html")
def xhtml = this(ContentType, "application/xhtml+xml")
def xml = this(ContentType, "text/xml")
def unary_~[IN[_]](implicit request: Request[IN]) =
ContentTypeResolver.w3cMimeReference(request.pathExtension) map (this(ContentType, _)) getOrElse this
def acceptsXhtml[IN[_]](implicit req: Request[IN]) =
if(hasContentType) this else this(ContentType, if(req.isInternetExplorer) "text/html" else "application/xhtml+xml")
}
import request.Request
import StatusLine.statusLine
object Response {
def response[OUT[_]](l: StatusLine, h: List[(ResponseHeader, NonEmptyList[Char])], b: OUT[Byte]) =
new Response[OUT] {
val line = l
val headers = h
val body = b
}
def emptyHeadersResponse[OUT[_]](l: StatusLine, b: OUT[Byte]): Response[OUT] = response[OUT](l, Nil, b)
def emptyResponse[OUT[_]](l: StatusLine, h: List[(ResponseHeader, NonEmptyList[Char])])(implicit e: Empty[OUT]) =
response[OUT](l, h, e.empty)
def emptyHeadersBodyResponse[OUT[_]](l: StatusLine)(implicit e: Empty[OUT]) =
emptyResponse[OUT](l, Nil)
def statusResponse[OUT[_], IN[_]](s: Status, h: List[(ResponseHeader, NonEmptyList[Char])], b: OUT[Byte])(implicit req: Request[IN]) =
response[OUT](statusLine[IN](s), h, b)
def emptyHeadersStatusResponse[OUT[_], IN[_]](s: Status, b: OUT[Byte])(implicit req: Request[IN]) =
response[OUT](statusLine[IN](s), Nil, b)
def emptyStatusResponse[OUT[_], IN[_]](s: Status, h: List[(ResponseHeader, NonEmptyList[Char])])(implicit e: Empty[OUT], req: Request[IN]) =
response[OUT](statusLine[IN](s), h, e.empty)
def emptyHeadersBodyStatusResponse[OUT[_], IN[_]](s: Status)(implicit e: Empty[OUT], req: Request[IN]) =
response[OUT](statusLine[IN](s), Nil, e.empty)
def versionStatusResponse[OUT[_]](v: Version, s: Status, h: List[(ResponseHeader, NonEmptyList[Char])], b: OUT[Byte]) =
response[OUT](statusLine(v, s), h, b)
def emptyHeadersVersionStatusResponse[OUT[_]](v: Version, s: Status, b: OUT[Byte]) =
response[OUT](statusLine(v, s), Nil, b)
def emptyVersionStatusResponse[OUT[_]](v: Version, s: Status, h: List[(ResponseHeader, NonEmptyList[Char])])(implicit e: Empty[OUT]) =
response[OUT](statusLine(v, s), h, e.empty)
def emptyHeadersBodyVersionStatusResponse[OUT[_]](v: Version, s: Status)(implicit e: Empty[OUT]) =
response[OUT](statusLine(v, s), Nil, e.empty)
def versionRedirect[OUT[_]](version: Version, location: NonEmptyList[Char])(implicit e: Empty[OUT]) =
response[OUT](statusLine(version, MovedPermanently), List((Location, location)), e.empty)
def versionRedirects[OUT[_]](version: Version, location: String)(implicit e: Empty[OUT]) =
response[OUT](statusLine(version, MovedPermanently), List((Location, location.charsNelErr("location must be non-empty"))), e.empty)
def redirect[OUT[_], IN[_]](location: NonEmptyList[Char], parameters: (String, String)*)(implicit e: Empty[OUT], req: Request[IN]) =
response[OUT](statusLine[IN](MovedPermanently), List((Location, if(parameters.isEmpty) location else location :::> ('?' + encode(parameters: _*)).toList)), e.empty)
def redirects[OUT[_], IN[_]](location: String, parameters: (String, String)*)(implicit e: Empty[OUT], req: Request[IN]) =
redirect[OUT, IN](location.charsNelErr("location must be non-empty"), parameters: _*)
}