content: {-# LANGUAGE NoImplicitPrelude #-}
  
  module Brok.Types.Document where
  
  import ClassyPrelude
  
  import Brok.IO.Http      (check)
  import Brok.Parser.Links (links)
  import Brok.Types.Brok   (Brok)
  import Brok.Types.Link
  import Brok.Types.URL    (URL)
  import Data.Map.Strict   as M (empty, insert, (!?))
  
  type TFilePath = Text
  
  type Error = Text
  
  data Phase
      = Content Text
      | NotFound
      | ParseError Error
      | Links [Link]
      deriving (Show, Eq)
  
  data Document =
      Document TFilePath
               Phase
      deriving (Show, Eq)
  
  type LDAcc a = (LinkDictionary, [a])
  
  getPath :: Document -> TFilePath
  getPath (Document path _) = path
  
  notFound :: TFilePath -> Document
  notFound path = Document path NotFound
  
  withContent :: TFilePath -> Text -> Document
  withContent path text = Document path (Content text)
  
  parseLinks :: Document -> Document
  parseLinks (Document path (Content text)) =
      case links text of
          Left err   -> Document path (ParseError err)
          Right lnks -> Document path (Links $ urlToLink <$> lnks)
  parseLinks result = result
  
  findLinks :: ([URL] -> Link -> Link) -> [URL] -> Document -> Document
  findLinks fn urls (Document path (Links lnks)) = Document path (Links $ fn urls <$> lnks)
  findLinks _ _ result                           = result
  
  cachedLinks :: [URL] -> Document -> Document
  cachedLinks = findLinks cachedLink
  
  ignoredLinks :: [URL] -> Document -> Document
  ignoredLinks = findLinks ignoredLink
  
  -- go over each link, building up a list of found links
  checkLink :: LDAcc Link -> Link -> Brok (LDAcc Link)
  checkLink (prev, lnks) (Link url UnresolvedLink) = do
      case prev !? url of
          Just result -> pure $ (prev, lnks <> [result])
          Nothing -> do
              result <- check (Link url UnresolvedLink)
              let newPrev = insert url result prev
              pure $ (newPrev, lnks <> [result])
  checkLink (prev, lnks) lnk = pure $ (prev, lnks <> [lnk])
  
  -- go over each document, building up a list of found links
  checkDocument :: LDAcc Document -> Document -> Brok (LDAcc Document)
  checkDocument (prev, documents) (Document path (Links lnks)) = do
      (newPrev, newLnks) <- foldlM checkLink (prev, []) lnks
      pure $ (newPrev, documents <> [Document path (Links newLnks)])
  checkDocument (prev, documents) document = pure $ (prev, documents <> [document])
  
  -- check links in all documents
  checkLinks :: [Document] -> Brok [Document]
  checkLinks documents = snd <$> foldlM checkDocument (M.empty, []) documents
  
  justLinks :: Document -> [Link]
  justLinks (Document _ (Links lnks)) = lnks
  justLinks _                         = []
  