API -> String
markdown = unlines . concat . map (uncurry printEndpoint) . HM.toList

  where printEndpoint :: Endpoint -> Action -> [String]
        printEndpoint endpoint action =
          str :
          replicate len '-' :
          "" :
          capturesStr (action ^. captures) ++
          headersStr (action ^. headers) ++
          paramsStr (action ^. params) ++
          rqbodyStr (action ^. rqbody) ++
          responseStr (action ^. response) ++
          []

          where str = show (endpoint^.method) ++ " " ++ endpoint^.path
                len = length str

        capturesStr :: [DocCapture] -> [String]
        capturesStr [] = []
        capturesStr l =
          "**Captures**: " :
          "" :
          map captureStr l ++
          "" :
          []
        captureStr cap =
          "- *" ++ (cap ^. capSymbol) ++ "*: " ++ (cap ^. capDesc)

        headersStr :: [Text] -> [String]
        headersStr [] = []
        headersStr l = [""] ++ map headerStr l ++ [""]

          where headerStr hname = "- This endpoint is sensitive to the value of the **"
                               ++ unpack hname ++ "** HTTP header."

        paramsStr :: [DocQueryParam] -> [String]
        paramsStr [] = []
        paramsStr l =
          "**GET Parameters**: " :
          "" :
          map paramStr l ++
          "" :
          []
        paramStr param = unlines $
          (" - " ++ param ^. paramName) :
          (if (not (null values) || param ^. paramKind /= Flag)
            then ["     - **Values**: *" ++ intercalate ", " values ++ "*"]
            else []) ++
          ("     - **Description**: " ++ param ^. paramDesc) :
          (if (param ^. paramKind == List)
            then ["     - This parameter is a **list**. All GET parameters with the name "
                  ++ param ^. paramName ++ "[] will forward their values in a list to the handler."]
            else []) ++
          (if (param ^. paramKind == Flag)
            then ["     - This parameter is a **flag**. This means no value is expected to be associated to this parameter."]
            else []) ++
          []

          where values = param ^. paramValues

        rqbodyStr :: Maybe ByteString -> [String]
        rqbodyStr Nothing = []
        rqbodyStr (Just b) =
          "**Request Body**: " :
          jsonStr b

        jsonStr b =
          "" :
          "``` javascript" :
          cs b :
          "```" :
          "" :
          []

        responseStr :: Response -> [String]
        responseStr resp =
          "**Response**: " :
          "" :
          (" - Status code " ++ show (resp ^. respStatus)) :
          (resp ^. respBody &
            maybe [" - No response body\n"]
                  (\b -> " - Response body as below." : jsonStr b))

-- * Instances

-- | The generated docs for @a ':<|>' b@ just appends the docs
--   for @a@ with the docs for @b@.
instance (H
markdown :: API -> String
markdown = unlines . concat . map (uncurry printEndpoint) . HM.toList

  where printEndpoint :: Endpoint -> Action -> [String]
        printEndpoint endpoint action =
          str :
          replicate len '-' :
          "" :
          capturesStr (action ^. captures) ++
          headersStr (action ^. headers) ++
          paramsStr (action ^. params) ++
          rqbodyStr (action ^. rqbody) ++
          responseStr (action ^. response) ++
          []

          where str = show (endpoint^.method) ++ " " ++ endpoint^.path
                len = length str

        capturesStr :: [DocCapture] -> [String]
        capturesStr [] = []
        capturesStr l =
          "**Captures**: " :
          "" :
          map captureStr l ++
          "" :
          []
        captureStr cap =
          "- *" ++ (cap ^. capSymbol) ++ "*: " ++ (cap ^. capDesc)

        headersStr :: [Text] -> [String]
        headersStr [] = []
        headersStr l = [""] ++ map headerStr l ++ [""]

          where headerStr hname = "- This endpoint is sensitive to the value of the **"
                               ++ unpack hname ++ "** HTTP header."

        paramsStr :: [DocQueryParam] -> [String]
        paramsStr [] = []
        paramsStr l =
          "**GET Parameters**: " :
          "" :
          map paramStr l ++
          "" :
          []
        paramStr param = unlines $
          (" - " ++ param ^. paramName) :
          (if (not (null values) || param ^. paramKind /= Flag)
            then ["     - **Values**: *" ++ intercalate ", " values ++ "*"]
            else []) ++
          ("     - **Description**: " ++ param ^. paramDesc) :
          (if (param ^. paramKind == List)
            then ["     - This parameter is a **list**. All GET parameters with the name "
                  ++ param ^. paramName ++ "[] will forward their values in a list to the handler."]
            else []) ++
          (if (param ^. paramKind == Flag)
            then ["     - This parameter is a **flag**. This means no value is expected to be associated to this parameter."]
            else []) ++
          []

          where values = param ^. paramValues

        rqbodyStr :: Maybe ByteString -> [String]
        rqbodyStr Nothing = []
        rqbodyStr (Just b) =
          "**Request Body**: " :
          jsonStr b

        jsonStr b =
          "" :
          "``` javascript" :
          cs b :
          "```" :
          "" :
          []

        responseStr :: Response -> [String]
        responseStr resp =
          "**Response**: " :
          "" :
          (" - Status code " ++ show (resp ^. respStatus)) :
          (resp ^. respBody &
            maybe [" - No response body\n"]
                  (\b -> " - Response body as below." : jsonStr b))

-- * Instances

-- | The generated docs for @a ':<|>' b@ just appends the docs
--   for @a@ with the docs for @b@.
markdown = unlines . concat . map (uncurry printEndpoint) . HM.toList

  where printEndpoint :: Endpoint -> Action -> [String]
        printEndpoint endpoint action =
          str :
          replicate len '-' :
          "" :
          capturesStr (action ^. captures) ++
          headersStr (action ^. headers) ++
          paramsStr (action ^. params) ++
          rqbodyStr (action ^. rqbody) ++
          responseStr (action ^. response) ++
          []

          where str = show (endpoint^.method) ++ " " ++ endpoint^.path
                len = length str

        capturesStr :: [DocCapture] -> [String]
        capturesStr [] = []
        capturesStr l =
          "**Captures**: " :
          "" :
          map captureStr l ++
          "" :
          []
        captureStr cap =
          "- *" ++ (cap ^. capSymbol) ++ "*: " ++ (cap ^. capDesc)

        headersStr :: [Text] -> [String]
        headersStr [] = []
        headersStr l = [""] ++ map headerStr l ++ [""]

          where headerStr hname = "- This endpoint is sensitive to the value of the **"
                               ++ unpack hname ++ "** HTTP header."

        paramsStr :: [DocQueryParam] -> [String]
        paramsStr [] = []
        paramsStr l =
          "**GET Parameters**: " :
          "" :
          map paramStr l ++
          "" :
          []
        paramStr param = unlines $
          (" - " ++ param ^. paramName) :
          (if (not (null values) || param ^. paramKind /= Flag)
            then ["     - **Values**: *" ++ intercalate ", " values ++ "*"]
            else []) ++
          ("     - **Description**: " ++ param ^. paramDesc) :
          (if (param ^. paramKind == List)
            then ["     - This parameter is a **list**. All GET parameters with the name "
                  ++ param ^. paramName ++ "[] will forward their values in a list to the handler."]
            else []) ++
          (if (param ^. paramKind == Flag)
            then ["     - This parameter is a **flag**. This means no value is expected to be associated to this parameter."]
            else []) ++
          []

          where values = param ^. paramValues

        rqbodyStr :: Maybe ByteString -> [String]
        rqbodyStr Nothing = []
        rqbodyStr (Just b) =
          "**Request Body**: " :
          jsonStr b

        jsonStr b =
          "" :
          "``` javascript" :
          cs b :
          "```" :
          "" :
          []

        responseStr :: Response -> [String]
        responseStr resp =
          "**Response**: " :
          "" :
          (" - Status code " ++ show (resp ^. respStatus)) :
          (resp ^. respBody &
            maybe [" - No response body\n"]
                  (\b -> " - Response body as below." : jsonStr b))

-- * Instances

-- | The generated docs for @a ':<|>' b@ just appends the docs
--   for @a@ with the docs for @b@.