content: {-# LANGUAGE NoImplicitPrelude #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Brok.Parser.Links
      ( links
      , url
      ) where
  
  import ClassyPrelude
  
  import Data.Attoparsec.Text
  import Data.List            (nub)
  
  import Brok.Parser.Attoparsec
  import Brok.Types.URL         (URL)
  
  type Token = Maybe URL
  
  preQueryChars :: String
  preQueryChars = "-._~:/#%@"
  
  queryBodyChars :: String
  queryBodyChars = preQueryChars <> "!$&*+,;="
  
  chars :: String -> Parser Char
  chars chrs = digit <|> letter <|> choice (char <$> chrs)
  
  -- parentheses
  parens :: Parser Text -> Parser Text
  parens parser = surround '(' ')' parser <|> surround '[' ']' parser
  
  -- urls
  part :: String -> Parser Text
  part str = concat <$> many1 (parens (part str) <|> manyChars (chars str))
  
  query :: Parser Text
  query = (<>) <$> string "?" <*> part queryBodyChars
  
  url :: Parser Text
  url =
      concat5 <$> string "http" <*> chopt 's' <*> string "://" <*> part preQueryChars <*>
      option "" query
  
  noise :: Parser Token
  noise = anyChar $> Nothing
  
  urls :: Parser [URL]
  urls = nub . catMaybes <$> many1 ((Just <$> url) <|> noise)
  
  -- run parser
  links :: Text -> Either Text [URL]
  links ""      = Right []
  links content = first tshow $ parseOnly urls content
  