content: --------------------------------------------------------------------------------
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE TemplateHaskell   #-}
  
  module Patat.Images.WezTerm
      ( backend
      ) where
  
  
  --------------------------------------------------------------------------------
  import           Codec.Picture           (DynamicImage,
                                            Image (imageHeight, imageWidth),
                                            decodeImage, dynamicMap)
  import           Control.Exception       (throwIO)
  import           Control.Monad           (unless, when)
  import qualified Data.Aeson              as A
  import qualified Data.ByteString         as B
  import qualified Data.ByteString.Base64  as B64
  import qualified Data.Text.Lazy          as TL
  import           Data.Text.Lazy.Encoding (encodeUtf8)
  import           Patat.Cleanup           (Cleanup)
  import qualified Patat.Images.Internal   as Internal
  import           System.Directory        (findExecutable)
  import           System.Environment      (lookupEnv)
  import           System.Process          (readProcess)
  
  
  --------------------------------------------------------------------------------
  backend :: Internal.Backend
  backend = Internal.Backend new
  
  
  --------------------------------------------------------------------------------
  data Config = Config deriving (Eq)
  instance A.FromJSON Config where parseJSON _ = return Config
  
  
  --------------------------------------------------------------------------------
  data Pane =
      Pane { paneSize     :: Size
           , paneIsActive :: Bool
           } deriving (Show)
  
  instance A.FromJSON Pane where
      parseJSON = A.withObject "Pane" $ \o -> Pane
          <$> o A..: "size"
          <*> o A..: "is_active"
  
  
  --------------------------------------------------------------------------------
  data Size =
      Size { sizePixelWidth  :: Int
           , sizePixelHeight :: Int
           } deriving (Show)
  
  instance A.FromJSON Size where
      parseJSON = A.withObject "Size" $ \o -> Size
          <$> o A..: "pixel_width"
          <*> o A..: "pixel_height"
  
  
  --------------------------------------------------------------------------------
  new :: Internal.Config Config -> IO Internal.Handle
  new config = do
      when (config == Internal.Auto) $ do
          termProgram <- lookupEnv "TERM_PROGRAM"
          unless (termProgram == Just "WezTerm") $ throwIO $
              Internal.BackendNotSupported "TERM_PROGRAM not WezTerm"
  
      return Internal.Handle {Internal.hDrawImage = drawImage}
  
  
  --------------------------------------------------------------------------------
  drawImage :: FilePath -> IO Cleanup
  drawImage path = do
      content <- B.readFile path
  
      wez <- wezExecutable
      resp <- fmap (encodeUtf8 . TL.pack) $ readProcess wez ["cli", "list", "--format", "json"] []
      let panes = (A.decode resp :: Maybe [Pane])
  
      Internal.withEscapeSequence $ do
          putStr "1337;File=inline=1;doNotMoveCursor=1;"
          case decodeImage content of
              Left _    -> pure ()
              Right img -> putStr $ wezArString (imageAspectRatio img) (activePaneAspectRatio panes)
          putStr ":"
          B.putStr (B64.encode content)
      return mempty
  
  
  --------------------------------------------------------------------------------
  wezArString  :: Double -> Double -> String
  wezArString i p | i < p     = "width=auto;height=95%;"
                  | otherwise = "width=100%;height=auto;"
  
  
  --------------------------------------------------------------------------------
  wezExecutable :: IO String
  wezExecutable = do
      w <- findExecutable "wezterm.exe"
      case w of
          Nothing -> return "wezterm"
          Just x  -> return x
  
  
  --------------------------------------------------------------------------------
  imageAspectRatio  :: DynamicImage -> Double
  imageAspectRatio i = imgW i / imgH i
      where
          imgH = fromIntegral . (dynamicMap imageHeight)
          imgW = fromIntegral . (dynamicMap imageWidth)
  
  
  --------------------------------------------------------------------------------
  paneAspectRatio :: Pane -> Double
  paneAspectRatio p = paneW p / paneH p
      where
          paneH = fromIntegral . sizePixelHeight . paneSize
          paneW = fromIntegral . sizePixelWidth . paneSize
  
  
  --------------------------------------------------------------------------------
  activePaneAspectRatio :: Maybe [Pane] -> Double
  activePaneAspectRatio Nothing = defaultAr -- This should never happen
  activePaneAspectRatio (Just x) =
      case filter paneIsActive x of
          [p] -> paneAspectRatio p
          _   -> defaultAr                  -- This shouldn't either
  
  
  --------------------------------------------------------------------------------
  defaultAr :: Double
  defaultAr = (4 / 3 :: Double)             -- Good enough for a VT100
  
  
  