{-# LANGUAGE DisambiguateRecordFields #-}
{-# LANGUAGE NamedFieldPuns #-}
module VerifyLayersSpanGeneration where

import Verify.Graphics.Vty.Prelude

import Verify.Graphics.Vty.Attributes
import Verify.Graphics.Vty.Image
import Verify.Graphics.Vty.Picture
import Verify.Graphics.Vty.Span

import Graphics.Vty.Debug
import Graphics.Vty.PictureToSpans

import Verify

import qualified Data.Vector as Vector

largerHorizSpanOcclusion :: SingleRowSingleAttrImage -> SingleRowSingleAttrImage -> Result
largerHorizSpanOcclusion row0 row1 =
    let i0 = rowImage row0
        i1 = rowImage row1
        (iLarger, iSmaller) = if imageWidth i0 > imageWidth i1 then (i0, i1) else (i1, i0)
        expectedOps = displayOpsForImage iLarger
        p = picForLayers [iLarger, iSmaller]
        ops = displayOpsForPic p (imageWidth iLarger,imageHeight iLarger)
    in verifyOpsEquality expectedOps ops

-- | Two rows stacked vertical is equivalent to the first row rendered
-- as the top layer and the second row rendered as a bottom layer with a
-- background fill where the first row would be.
vertStackLayerEquivalence0 :: SingleRowSingleAttrImage -> SingleRowSingleAttrImage -> Result
vertStackLayerEquivalence0 row0 row1 =
    let i0 = rowImage row0
        i1 = rowImage row1
        i = i0 <-> i1
        p = picForImage i
        iLower = backgroundFill (imageWidth i0) 1 <-> i1
        pLayered = picForLayers [i0, iLower]
        expectedOps = displayOpsForImage i
        opsLayered = displayOpsForPic pLayered (imageWidth iLower,imageHeight iLower)
    in verifyOpsEquality expectedOps opsLayered

vertStackLayerEquivalence1 :: SingleRowSingleAttrImage -> SingleRowSingleAttrImage -> Result
vertStackLayerEquivalence1 row0 row1 =
    let i0 = rowImage row0
        i1 = rowImage row1
        i = i0 <-> i1
        p = picForImage i
        iLower = i0 <-> backgroundFill (imageWidth i1) 1
        iUpper = backgroundFill (imageWidth i0) 1 <-> i1
        pLayered = picForLayers [iUpper, iLower]
        expectedOps = displayOpsForImage i
        opsLayered = displayOpsForPic pLayered (imageWidth iLower,imageHeight iLower)
    in verifyOpsEquality expectedOps opsLayered

-- | Two rows horiz joined is equivalent to the first row rendered as
-- the top layer and the second row rendered as a bottom layer with a
-- background fill where the first row would be.
horizJoinLayerEquivalence0 :: SingleRowSingleAttrImage -> SingleRowSingleAttrImage -> Result
horizJoinLayerEquivalence0 row0 row1 =
    let i0 = rowImage row0
        i1 = rowImage row1
        i = i0 <|> i1
        p = picForImage i
        iLower = backgroundFill (imageWidth i0) 1 <|> i1
        pLayered = picForLayers [i0, iLower]
        expectedOps = displayOpsForImage i
        opsLayered = displayOpsForPic pLayered (imageWidth iLower,imageHeight iLower)
    in verifyOpsEquality expectedOps opsLayered

horizJoinLayerEquivalence1 :: SingleRowSingleAttrImage -> SingleRowSingleAttrImage -> Result
horizJoinLayerEquivalence1 row0 row1 =
    let i0 = rowImage row0
        i1 = rowImage row1
        i = i0 <|> i1
        p = picForImage i
        iLower = i0 <|> backgroundFill (imageWidth i1) 1
        iUpper = backgroundFill (imageWidth i0) 1 <|> i1
        pLayered = picForLayers [iUpper, iLower]
        expectedOps = displayOpsForImage i
        opsLayered = displayOpsForPic pLayered (imageWidth iLower,imageHeight iLower)
    in verifyOpsEquality expectedOps opsLayered

horizJoinAlternate0 :: Result
horizJoinAlternate0 =
    let size = 4
        str0 = replicate size 'a'
        str1 = replicate size 'b'
        i0 = string defAttr str0
        i1 = string defAttr str1
        i = horizCat $ zipWith horizJoin (replicate size i0) (replicate size i1)
        layer0 = horizCat $ replicate size $ i0 <|> backgroundFill size 1
        layer1 = horizCat $ replicate size $ backgroundFill size 1 <|> i1
        expectedOps = displayOpsForImage i
        opsLayered = displayOpsForPic (picForLayers [layer0, layer1])
                                      (imageWidth i,imageHeight i)
    in verifyOpsEquality expectedOps opsLayered

horizJoinAlternate1 :: Result
horizJoinAlternate1 =
    let size = 4
        str0 = replicate size 'a'
        str1 = replicate size 'b'
        i0 = string defAttr str0
        i1 = string defAttr str1
        i = horizCat $ zipWith horizJoin (replicate size i0) (replicate size i1)
        layers = [l | b <- take 4 [0,size*2..], let l = backgroundFill b 1 <|> i0 <|> i1]
        expectedOps = displayOpsForImage i
        opsLayered = displayOpsForPic (picForLayers layers)
                                      (imageWidth i,imageHeight i)
    in verifyOpsEquality expectedOps opsLayered

tests :: IO [Test]
tests = return
    [ verify "a larger horiz span occludes a smaller span on a lower layer"
        largerHorizSpanOcclusion
    , verify "two rows stack vertical equiv to first image layered on top of second with padding (0)"
        vertStackLayerEquivalence0
    , verify "two rows stack vertical equiv to first image layered on top of second with padding (1)"
        vertStackLayerEquivalence1
    -- , verify "two rows horiz joined equiv to first image layered on top of second with padding (0)"
    --     horizJoinLayerEquivalence0
    -- , verify "two rows horiz joined equiv to first image layered on top of second with padding (1)"
    --     horizJoinLayerEquivalence1
    -- , verify "alternating images using joins is the same as alternating images using layers (0)"
    --     horizJoinAlternate0
    -- , verify "alternating images using joins is the same as alternating images using layers (1)"
    --     horizJoinAlternate1
    ]