{-# LANGUAGE FlexibleContexts, TypeOperators #-}
module Network.Salvia.Handler.Range
( Range (..)
, contentRange
, range
, rangeL
)
where

import Data.Record.Label
import Data.List
import Network.Protocol.Http
import Safe

-- | HTTP Range datatype.

data Range = Range (Maybe Integer) (Maybe Integer) (Maybe Integer)
  deriving Show

-- | Access the /Content-Range/ header field.

contentRange :: Http Response :-> Maybe Range
contentRange = lmap rangeL `iso` header "Content-Range"

-- | Access the /Range/ header field.

range :: Http Request :-> Maybe Range
range = lmap rangeL `iso` header "Range"

-- | Lens containing parser and pretty-printer for HTTP ranges.

rangeL :: String :<->: Range
rangeL = parser <-> printer
  where
  printer (Range f t x) = concat ["bytes ", maybe "" show f, "-", maybe "" show t, maybe "" (('/':).show) x]
  parser r =
    case span (/='-') . maybe r id $ stripPrefix "bytes=" r of
      (f, _:a) -> case span (/='/') a of
                    (t, _:x) -> Range (readMay f) (readMay t) (readMay x)
                    (t, _)   -> Range (readMay f) (readMay t) Nothing
      (f, [])  ->               Range (readMay f) Nothing Nothing

-- If-Range: "ac5319-31f76000-481fa6ec42cc0"
-- Range: bytes=125817136-
-- Content-Range:  "bytes 21010-47021/47022"
-- "ac5319-31f76000-481fa6ec42cc0"
-- Last-Modified: Wed, 17 Mar 2010 07:55:07 GMT
-- : bytes