{-# Language BangPatterns #-}
{-|
Module      : Client.View.Mentions
Description : Mentions view
Copyright   : (c) Eric Mertens, 2016
License     : ISC
Maintainer  : emertens@gmail.com

This module provides the lines that have been highlighted
across the client in sorted order.

-}
module Client.View.Mentions
  ( mentionsViewLines
  ) where

import           Client.Image.Palette
import           Client.State
import           Client.State.Focus
import           Client.State.Window
import qualified Data.Map as Map
import           Control.Lens
import           Data.Text (Text)
import           Data.Time (UTCTime)
import           Irc.Identifier (idText)
import           Graphics.Vty.Image

-- | Generate the list of message lines marked important ordered by
-- time. Each run of lines from the same channel will be grouped
-- together. Messages are headed by their window, network, and channel.
mentionsViewLines :: ClientState -> [Image]
mentionsViewLines st = addMarkers pal entries

  where
    pal = clientPalette st

    names = clientWindowNames st ++ repeat '?'

    detail = view clientDetailView st

    entries = merge
              [windowEntries detail n net (idText chan) v
              | (n,(ChannelFocus net chan, v))
                <- names `zip` Map.toList (view clientWindows st) ]

data MentionLine = MentionLine
  { mlTimestamp  :: UTCTime
  , mlWindowName :: Char
  , mlNetwork    :: Text
  , mlChannel    :: Text
  , mlImage      :: Image
  }

addMarkers ::
  Palette       {- ^ palette                           -} ->
  [MentionLine] {- ^ list of mentions in time order    -} ->
  [Image]       {- ^ mention images and channel labels -}
addMarkers _ [] = []
addMarkers !pal (!ml : xs) =
  mlImage ml : map mlImage same ++ windowMarker : addMarkers pal rest
  where
    isSame ml' = mlWindowName ml == mlWindowName ml'
              && mlNetwork    ml == mlNetwork    ml'
              && mlChannel    ml == mlChannel    ml'

    (same,rest) = span isSame xs

    windowMarker = char (view palWindowName pal) (mlWindowName ml) <|>
                   char defAttr ':' <|>
                   text' (view palLabel pal) (mlNetwork ml) <|>
                   char defAttr ':' <|>
                   text' (view palLabel pal) (mlChannel ml)

windowEntries ::
  Bool   {- ^ detailed view -} ->
  Char   {- ^ window name   -} ->
  Text   {- ^ network name  -} ->
  Text   {- ^ channel name  -} ->
  Window {- ^ window        -} ->
  [MentionLine]
windowEntries !detailed name net chan w =
  [ MentionLine
      { mlTimestamp  = view wlTimestamp l
      , mlWindowName = name
      , mlNetwork    = net
      , mlChannel    = chan
      , mlImage      = if detailed then view wlFullImage l else view wlImage l
      }
  | l <- view winMessages w
  , WLImportant == view wlImportance l
  ]

-- | Merge a list of sorted lists of mention lines into a single sorted list
-- in descending order.
merge :: [[MentionLine]] -> [MentionLine]
merge []  = []
merge [x] = x
merge xss = merge (merge2s xss)

merge2s :: [[MentionLine]] -> [[MentionLine]]
merge2s (x:y:z) = merge2 x y : merge2s z
merge2s xs      = xs

merge2 :: [MentionLine] -> [MentionLine] -> [MentionLine]
merge2 [] ys = ys
merge2 xs [] = xs
merge2 xxs@(x:xs) yys@(y:ys)
  | mlTimestamp x >= mlTimestamp y = x : merge2 xs yys
  | otherwise                      = y : merge2 xxs ys