module Nitpick.Debug
  ( hasDebugUses
  )
  where


import qualified Data.Map.Utils as Map

import qualified AST.Optimized as Opt



-- HAS DEBUG USES


hasDebugUses :: Opt.LocalGraph -> Bool
hasDebugUses (Opt.LocalGraph _ graph _) =
  Map.any nodeHasDebug graph


nodeHasDebug :: Opt.Node -> Bool
nodeHasDebug node =
  case node of
    Opt.Define expr _           -> hasDebug expr
    Opt.DefineTailFunc _ expr _ -> hasDebug expr
    Opt.Ctor _ _                -> False
    Opt.Enum _                  -> False
    Opt.Box                     -> False
    Opt.Link _                  -> False
    Opt.Cycle _ vs fs _         -> any (hasDebug . snd) vs || any defHasDebug fs
    Opt.Manager _               -> False
    Opt.Kernel _ _              -> False
    Opt.PortIncoming expr _     -> hasDebug expr
    Opt.PortOutgoing expr _     -> hasDebug expr


hasDebug :: Opt.Expr -> Bool
hasDebug expression =
  case expression of
    Opt.Bool _           -> False
    Opt.Chr _            -> False
    Opt.Str _            -> False
    Opt.Int _            -> False
    Opt.Float _          -> False
    Opt.VarLocal _       -> False
    Opt.VarGlobal _      -> False
    Opt.VarEnum _ _      -> False
    Opt.VarBox _         -> False
    Opt.VarCycle _ _     -> False
    Opt.VarDebug _ _ _ _ -> True
    Opt.VarKernel _ _    -> False
    Opt.List exprs       -> any hasDebug exprs
    Opt.Function _ expr  -> hasDebug expr
    Opt.Call e es        -> hasDebug e || any hasDebug es
    Opt.TailCall _ args  -> any (hasDebug . snd) args
    Opt.If conds finally -> any (\(c,e) -> hasDebug c || hasDebug e) conds || hasDebug finally
    Opt.Let def body     -> defHasDebug def || hasDebug body
    Opt.Destruct _ expr  -> hasDebug expr
    Opt.Case _ _ d jumps -> deciderHasDebug d || any (hasDebug . snd) jumps
    Opt.Accessor _       -> False
    Opt.Access r _       -> hasDebug r
    Opt.Update r fs      -> hasDebug r || any hasDebug fs
    Opt.Record fs        -> any hasDebug fs
    Opt.Unit             -> False
    Opt.Tuple a b c      -> hasDebug a || hasDebug b || maybe False hasDebug c
    Opt.Shader _ _ _     -> False


defHasDebug :: Opt.Def -> Bool
defHasDebug def =
  case def of
    Opt.Def _ expr       -> hasDebug expr
    Opt.TailDef _ _ expr -> hasDebug expr


deciderHasDebug :: Opt.Decider Opt.Choice -> Bool
deciderHasDebug decider =
  case decider of
    Opt.Leaf (Opt.Inline expr)  -> hasDebug expr
    Opt.Leaf (Opt.Jump _)       -> False
    Opt.Chain _ success failure -> deciderHasDebug success || deciderHasDebug failure
    Opt.FanOut _ tests fallback -> any (deciderHasDebug . snd) tests || deciderHasDebug fallback



-- TODO: FIND GLOBALLY UNUSED DEFINITIONS?
-- TODO: FIND PACKAGE USAGE STATS? (e.g. elm/core = 142, author/project = 2, etc.)
