{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Amby.Display where

import Control.Monad.Catch
import Data.Default (def)
import Text.Display
import System.IO.Unsafe (unsafePerformIO)
import System.Exit (ExitCode(..))
import System.Process (readProcessWithExitCode)

import Graphics.Rendering.Chart.Easy (Layout, EC)
import qualified Graphics.Rendering.Chart.Backend.Cairo as Cairo

import qualified Amby.Plot as Plot
import Amby.Types

instance {-# OVERLAPPING #-} Display (AmbyChart ()) where
  display a = saveAndDisplay a

instance {-# OVERLAPPING #-} Display (EC (Layout Double Double) ()) where
  display a = saveAndDisplayEC a

instance {-# OVERLAPPING #-} Display (AmbyGrid ()) where
  display a = saveAndDisplay a

saveAndDisplay :: Saveable s => s -> DisplayText
saveAndDisplay chart = saveAndDisplayIO $ do
  Plot.save chart

saveAndDisplayEC :: EC (Layout Double Double) () -> DisplayText
saveAndDisplayEC chart = saveAndDisplayIO $ do
  Cairo.toFile def Plot.cairoDefSave chart

saveAndDisplayIO :: IO () -> DisplayText
{-# NOINLINE saveAndDisplayIO #-}
saveAndDisplayIO ioAction = unsafePerformIO $ do
  ioAction
  catch readImg cHandler
  where
    readImg = do
      (ec, stdout, _) <- readProcessWithExitCode "imgcat" [Plot.cairoDefSave] ""
      if | (ExitFailure _) <- ec -> return (mkDtStr "Unable to display chart.")
         | otherwise -> return (mkDtStr stdout)
    cHandler e
      | Just (_ :: SomeException) <- fromException e =
        return $ mkDt "Could not find imgcat executable."
      | otherwise =
        return $ mkDt "Unknown display error."