{-|
Module      : Client.Image.Utils
Description : Chat message view
Copyright   : (c) Eric Mertens, 2016
License     : ISC
Maintainer  : emertens@gmail.com

Provides utilities for formatting Vty Images.
-}

module Client.Image.Utils (lineWrap) where

import           Graphics.Vty.Image
import           Graphics.Vty.Attributes

-- | Given an image, break the image up into chunks of at most the
-- given width and stack the resulting chunks vertically top-to-bottom.
lineWrap ::
  Int       {- ^ terminal width       -} ->
  Maybe Int {- ^ optional indentation -} ->
  Image     {- ^ unwrapped image      -} ->
  Image     {- ^ wrapped image        -}
lineWrap w mi img
  | imageWidth img == 0 = emptyImage
  | imageWidth img <= w = terminate w img
  | otherwise =
      terminate w (cropRight w img) <->
      maybe (lineWrapNoIndent w) (lineWrapIndent w) mi
            (cropLeft (imageWidth img - w) img)

-- | Trailing space with default attributes deals with bug in VTY
-- where the formatting will continue past the end of chat messages.
-- This adds an extra space if a line doesn't end on the terminal edge.
terminate ::
  Int   {- ^ terminal width  -} ->
  Image {- ^ unwrapped image -} ->
  Image {- ^ wrapped image   -}
terminate n img
  | imageWidth img == n = img
  | otherwise           = img <|> char defAttr ' '

lineWrapNoIndent ::
  Int   {- ^ terminal width  -} ->
  Image {- ^ unwrapped image -} ->
  Image {- ^ wrapped image   -}
lineWrapNoIndent w img
  | iw <= w   = terminate w img
  | otherwise = cropRight w img <->
                lineWrapNoIndent w (cropLeft (iw - w) img)
  where
    iw = imageWidth img

lineWrapIndent ::
  Int   {- ^ terminal width  -} ->
  Int   {- ^ indentation     -} ->
  Image {- ^ unwrapped image -} ->
  Image {- ^ wrapped image   -}
lineWrapIndent w i img
  | 20 + i >  w = lineWrapNoIndent w img -- ensure we stop wrapping when it doesn't make sense
  | iw + i <= w = terminate w (leftPad i img)
  | otherwise   = leftPad i (cropRight (w-i) img) <->
                  lineWrapIndent w i (cropLeft (iw - w + i) img)
  where
    iw = imageWidth img

leftPad :: Int -> Image -> Image
leftPad i = pad i 0 0 0