{-# Language OverloadedStrings #-}
{-|
Module      : Client.View.Palette
Description : View current palette and to see all terminal colors
Copyright   : (c) Eric Mertens, 2016
License     : ISC
Maintainer  : emertens@gmail.com

Lines for the @/palette@ command. This view shows all the colors of
the current palette as well as the colors available in the terminal.

-}

module Client.View.Palette
  ( paletteViewLines
  ) where

import           Client.Image.Palette
import           Client.Image.MircFormatting
import           Client.Image.PackedImage
import           Control.Lens
import           Data.List
import           Data.List.Split (chunksOf)
import           Graphics.Vty.Attributes
import qualified Data.Vector as Vector
import           Numeric (showHex)

columns :: [Image'] -> Image'
columns = mconcat . intersperse (char defAttr ' ')

indent :: Image' -> Image'
indent x = "   " <> x

-- | Generate lines used for @/palette@. These lines show
-- all the colors used in the current palette as well as
-- the colors available for use in palettes.
paletteViewLines :: Palette -> [Image']
paletteViewLines pal = reverse $

  [ "Current client palette:"
  , ""
  , columns (paletteEntries pal)
  , ""
  , "Current client palette nick highlight colors:"
  , ""
  ] ++
  nickHighlights pal ++
  [ ""
  , "Chat formatting modes:"
  , ""
  , "   C-b  C-_       C-]    C-v     C-^           C-q       C-o"
  , parseIrcText pal "   \^Bbold\^B \^_underline\^_ \^]italic\^] \^Vreverse\^V \^^strikethrough\^^ \^Qmonospace\^Q reset"
  , ""
  , "Chat formatting colors: C-c[foreground[,background]]"
  , ""
  ] ++
  colorTable ++
  [ ""
  , "Available terminal palette colors (hex)"
  , ""
  ] ++
  terminalColorTable

terminalColorTable :: [Image']
terminalColorTable =
  isoColors ++
  "" : colorBox 0x10 ++
  "" : colorBox 0x7c ++
  "" : indent (foldMap (\c -> colorBlock showPadHex c (Color240 (fromIntegral (c-16)))) [0xe8 .. 0xf3])
     : indent (foldMap (\c -> colorBlock showPadHex c (Color240 (fromIntegral (c-16)))) [0xf4 .. 0xff])
     : []

colorBox :: Int -> [Image']
colorBox start =
  [ indent $ columns
      [ mconcat
          [ colorBlock showPadHex k (Color240 (fromIntegral (k - 16)))
          | k <- [j, j+6 .. j + 30 ] ]
      | j <- [i, i + 0x24, i + 0x48 ]
      ]
  | i <- [ start .. start + 5 ]
  ]

isLight :: Color -> Bool
isLight (ISOColor c) = c `elem` [7, 10, 11, 14, 15]
isLight (Color240 c) =
  case color240CodeToRGB c of
    Just (r, g, b) -> (r `max` g `max` b) > 200
    Nothing        -> True
isLight (RGBColor r g b) = (r `max` g `max` b) > 200


isoColors :: [Image']
isoColors =
  [ indent (foldMap (\c -> colorBlock showPadHex c (ISOColor (fromIntegral c))) [0 .. 7])
  , indent (foldMap (\c -> colorBlock showPadHex c (ISOColor (fromIntegral c))) [8 .. 15])
  ]

colorTable :: [Image']
colorTable
  = map (indent . mconcat)
  $ chunksOf 8 [ colorBlock showPadDec i (mircColors Vector.! i) | i <- [0 .. 15] ]
  ++ [[]]
  ++ chunksOf 12 [ colorBlock showPadDec i (mircColors Vector.! i) | i <- [16 .. 98] ]

colorBlock :: (Int -> String) -> Int -> Color -> Image'
colorBlock showNum i c =
  string (withForeColor (withBackColor defAttr c) (if isLight c then black else white)) (showNum i)

showPadDec :: Int -> String
showPadDec i
  | i < 10    = ' ' : '0' : shows i " "
  | otherwise = ' ' :       shows i " "

showPadHex :: Int -> String
showPadHex i
  | i < 16    = ' ' : '0' : showHex i " "
  | otherwise = ' ' :       showHex i " "

paletteEntries :: Palette -> [Image']
paletteEntries pal =
  [ text' (view l pal) name
  | (name, Lens l) <- paletteMap
  ]

nickHighlights :: Palette -> [Image']
nickHighlights pal =
  [ indent (columns line)
  | line <- chunksOf 8
            [ string attr "nicks"
            | attr <- views palNicks Vector.toList pal ]
  ]
