{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances #-}
module Debug.TraceCall.UnsafeDeep where

import Debug.Trace
import Debug.TraceCall.Base

class TCDeepUnsafe a where
  tcDeepUnsafe :: TraceData -> Int -> (TraceData -> a) -> a -> a

instance Show a => TCDeepUnsafe a where
  tcDeepUnsafe td _ c v = trace (traceResult td (show $ c td)) $ v

instance (TADeepUnsafe a, TCDeepUnsafe r) => TCDeepUnsafe (a -> r) where
  tcDeepUnsafe (TraceData fun as ctx) i c f a =
    case taDeepUnsafe ("<<function-" ++ show i ++ ">>") a of
      Left s   -> tcDeepUnsafe (TraceData fun (as ++ [s]) ctx) i (\td -> c td a) (f a)
      Right ca -> tcDeepUnsafe (TraceData fun (as ++ ["<<function-" ++ show i ++ ">>"]) ctx) (i + 1) (\td -> c td (ca td)) (f a)


class TADeepUnsafe a where
  taDeepUnsafe :: String -> a -> Either String (TraceData -> a)

instance (Show a) => TADeepUnsafe a where
  taDeepUnsafe _ = Left . show

instance (TCDeepUnsafe (a -> r)) => TADeepUnsafe (a -> r) where
  taDeepUnsafe s f = Right $ \td -> tcDeepUnsafe (TraceData s [] $ Just td) 0 (const f) f


unsafeTraceCallDeep :: (TCDeepUnsafe a) => String -> a -> a
unsafeTraceCallDeep s f = tcDeepUnsafe (TraceData s [] Nothing) 0 (const f) f