    {-# LANGUAGE BangPatterns #-}
    -- A 'Picture' is a background paired with a set of 'Image' layers. The
    -- 'Picture' data structure is representative of the final terminal
    -- view.
    module Graphics.Vty.Picture
      ( Picture(..)
      , Cursor(..)
      , Background(..)
      , emptyPicture
      , addToTop
      , addToBottom
      , picForImage
      , picForLayers
      , picImage
      )
    where

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

    import Control.DeepSeq

    -- | A Vty picture.
    --
    -- These can be constructed directly or using `picForImage`.
    data Picture = Picture
        { picCursor :: Cursor
        -- ^ The picture's cursor.
        , picLayers :: [Image]
        -- ^ The picture's image layers (top-most first).
        , picBackground :: Background
        -- ^ The picture's background to be displayed in locations with no
        -- Image data.
        }

    instance Show Picture where
        show (Picture _ layers _ ) = "Picture ?? " ++ show layers ++ " ??"

    instance NFData Picture where
        rnf (Picture c l b) = c `deepseq` l `deepseq` b `deepseq` ()

    -- | A picture with no cursor, background or image layers.
    emptyPicture :: Picture
    emptyPicture = Picture NoCursor [] ClearBackground

    -- | Add an 'Image' as the top-most layer of a 'Picture'.
    addToTop :: Picture -> Image -> Picture
    addToTop p i = p {picLayers = i : picLayers p}

    -- | Add an 'Image' as the bottom-most layer of a 'Picture'.
    addToBottom :: Picture -> Image -> Picture
    addToBottom p i = p {picLayers = picLayers p ++ [i]}

    -- | Create a picture from the given image. The picture will not have a
    -- displayed cursor and no background pattern (ClearBackground) will be
    -- used.
    picForImage :: Image -> Picture
    picForImage i = Picture
        { picCursor = NoCursor
        , picLayers = [i]
        , picBackground = ClearBackground
        }

    -- | Create a picture with the given layers, top-most first.
    --
    -- The picture will not have a displayed cursor and no background
    -- pattern (ClearBackgroun) will be used.
    picForLayers :: [Image] -> Picture
    picForLayers is = Picture
        { picCursor = NoCursor
        , picLayers = is
        , picBackground = ClearBackground
        }

    -- | A picture can be configured to hide the cursor or to show the
    -- cursor at the specified character position.
    --
    -- There is not a 1:1 map from character positions to a row and column
    -- on the screen due to characters that take more than 1 column.
    data Cursor =
        -- | Hide the cursor
        NoCursor
        -- | Show the cursor at the given logical column accounting for
        -- character width in the presence of multi-column characters.
        | Cursor !Int !Int
        -- | Show the cursor at the given absolute terminal column and row
        | AbsoluteCursor !Int !Int

    instance NFData Cursor where
        rnf c = c `seq` ()

    -- | A 'Picture' has a background pattern. The background is either:
    --
    -- * ClearBackground, which shows the layer below or is blank if the
    --   bottom layer
    -- * A character and a display attribute
    --
    -- If the display attribute used previously should be used for a
    -- background fill then use `currentAttr` for the background attribute.
    data Background
        = Background
        { backgroundChar :: Char
        , backgroundAttr :: Attr
        }
         -- | A ClearBackground is:
         --
         -- * the space character if there are remaining non-skip ops
         --
         -- * End of line if there are no remaining non-skip ops.
        | ClearBackground

    instance NFData Background where
        rnf (Background c a) = c `seq` a `seq` ()
        rnf ClearBackground = ()

    -- | Return the top-most 'Image' layer for a picture. This is unsafe for
    -- 'Picture's without at least one layer.
    --
    -- This is provided for compatibility with applications that do not use
    -- more than a single layer.
    picImage :: Picture -> Image
    picImage = head . picLayers