module Text.Parsix.Highlight where

import Data.IntervalMap.FingerTree(IntervalMap)
import qualified Data.IntervalMap.FingerTree as IntervalMap
import Data.List
import Data.Semigroup
import Data.Text(Text)
import Data.Text.Prettyprint.Doc
import Data.Text.Prettyprint.Doc.Render.Terminal
import Text.Parser.Token.Highlight

import Text.Parsix.Internal

type Highlights = IntervalMap Int Highlight

highlightInterval
  :: Semigroup a
  => (Text -> a)
  -> (Highlight -> a -> a)
  -> Text
  -> Int
  -> Int
  -> Highlights
  -> a
highlightInterval textPart highlightPart input start end highlights = go start boundaries
  where
    boundaries
      = uniq
      $ sort
      [ i
      | (s, e) <- rightOpenView . fst <$> IntervalMap.intersections
          (rightOpen start end)
          highlights
      , i <- [max start s, min end e]
      ]

    part s e
      = foldr
        highlightPart
        (textPart $ codeUnitSlice s e input)
        (snd <$> IntervalMap.dominators (rightOpen s e) highlights)

    go s [] = part s end
    go s (e:bs) = part s e <> go e bs

    uniq :: Eq a => [a] -> [a]
    uniq [] = []
    uniq (x:xs) = uniq1 x xs

    uniq1 :: Eq a => a -> [a] -> [a]
    uniq1 x [] = [x]
    uniq1 x (y:ys)
      | x == y = uniq1 x ys
      | otherwise = x : uniq1 y ys

prettyInterval
  :: Text
  -> Int
  -> Int
  -> Highlights
  -> Doc Highlight
prettyInterval = highlightInterval pretty annotate

defaultStyle :: Highlight -> AnsiStyle
defaultStyle h = case h of
  Comment -> color Blue
  ReservedIdentifier -> color Magenta
  ReservedConstructor -> color Magenta
  EscapeCode -> color Magenta
  Operator -> color Yellow
  CharLiteral -> color Cyan
  StringLiteral -> color Cyan
  Constructor -> bold
  ReservedOperator -> color Yellow
  ConstructorOperator -> color Yellow
  ReservedConstructorOperator -> color Yellow
  _ -> mempty