-- mkEffectorBody --------------------------------------------------------------

{- | build a (do) stmt that takes a GetoptName__ record, for each field in turn
     extracts the PCLV, passes through the relevant defaulter, to the relevant
     enactor; and ultimately builds a GetoptName record from the resultant values

     type of the resulting expression is GetoptName__ -> IO GetoptName
-}

-- mkEffectorBody g = do
--   ((a, b, ...), exs) <- runWriterT $ do
--                             a <- tryWriteF $ enactor (dfGetter a___)
--                             b <- tryWriteF $ enactor (dfGetter b___)
--                             ...
--                             return (a, b, ...)
--   return $ if null exs
--            then Right $ GetoptName (fromJust a) (fromJust b) ...
--            else Left exs

-- (do
--   ((string_x', incr_x', handle_x'), exs) <- runWriterT $ do
--           string_x    <- tryWriteF $
--                            return (((fromMaybe "") . (view s___)) pclv);
--           incr_x      <- tryWriteF $ return (view incr___ pclv)
--           handle_x    <- tryWriteF $
--                            openFileRO (((fromMaybe "/etc/motd")
--                                         . (view handle___)) pclv)
--           return (string_x, incr_x, handle_x)
--   return $ if null exs
--            then Right $ Getoptsx (fromJust string_x')
--                                  (fromJust incr_x')
--                                  (fromJust handle_x')
--            else Left exs
--  above)

mkEffectorBody :: [OptDesc]  -- ^ option field list
               -> String     -- ^ name of the generated getopt_th
               -> Name       -- ^ name of the fn param
               -> ExpQ

mkEffectorBody optdescs getoptName pclv =  do
  -- bs are the names that are assigned to, within the writer monad
  -- binds are each individual bound defaulted option
  (bs, binds) <- mapAndUnzipM (effectBind pclv) optdescs
  -- mbs are the names of the maybe values, having been try-ed; in each case,
  -- it's the name from within the writer, plus a trailing "'"
  mbs         <- sequence $ fmap (newName . nameBase) bs
  -- rtn_bs_tup is the return of a tuple of each bind (return (a, b, ...))
  let rtn_bs_tup = [NoBindS (AppE (VarE 'return) (TupE (fmap VarE bs)))]
      run_writer = composeApE (VarE 'runWriterT) (DoE (binds ++ rtn_bs_tup))
      exs        = mkName "exs"
      -- c'tor args are the map of fromJust across the maybe binds
      c'tor_args = fmap (AppE (VarE 'fromJust) . VarE) mbs
      c'tor      = mAppE ((ConE $ ov_typename getoptName) : c'tor_args)
      check      = CondE -- if null exs
                         (AppE (VarE 'null) (VarE exs))
                         -- then Right $ GetoptName (fromJust a) (fromJust b) ...
                         (composeApE (ConE 'Right) c'tor)
                         -- else Left exs
                         (AppE (ConE 'Left) (VarE exs))
  return (DoE --  ((a, b, ...), exs) <- runWriterT...
              [ BindS (TupP [TupP (fmap VarP mbs), VarP exs]) run_writer
              --  return $ if ...
              , NoBindS (composeApE (VarE 'return) check)
              ])

-- effectBind ------------------------------------------------------------------

-- | given some var pclv which is of type GetoptName__, return a stmt of the
--   form b <- enactor (dfGetter pclv)
--   (e.g., string_x <- tryWriteF $ return (((fromMaybe "") . (view s___)) pclv
--    above)
mkEffectorBody :: [OptDesc]  -- ^ option field list
               -> String     -- ^ name of the generated getopt_th
               -> Name       -- ^ name of the fn param
               -> ExpQ
mkEffectorBody optdescs getoptName pclv =  do
  -- bs are the names that are assigned to, within the writer monad
  -- binds are each individual bound defaulted option
  (bs, binds) <- mapAndUnzipM (effectBind pclv) optdescs
  -- mbs are the names of the maybe values, having been try-ed; in each case,
  -- it's the name from within the writer, plus a trailing "'"
  mbs         <- sequence $ fmap (newName . nameBase) bs
  -- rtn_bs_tup is the return of a tuple of each bind (return (a, b, ...))
  let rtn_bs_tup = [NoBindS (AppE (VarE 'return) (TupE (fmap VarE bs)))]
      run_writer = composeApE (VarE 'runWriterT) (DoE (binds ++ rtn_bs_tup))
      exs        = mkName "exs"
      -- c'tor args are the map of fromJust across the maybe binds
      c'tor_args = fmap (AppE (VarE 'fromJust) . VarE) mbs
      c'tor      = mAppE ((ConE $ ov_typename getoptName) : c'tor_args)
      check      = CondE -- if null exs
                         (AppE (VarE 'null) (VarE exs))
                         -- then Right $ GetoptName (fromJust a) (fromJust b) ...
                         (composeApE (ConE 'Right) c'tor)
                         -- else Left exs
                         (AppE (ConE 'Left) (VarE exs))
  return (DoE --  ((a, b, ...), exs) <- runWriterT...
              [ BindS (TupP [TupP (fmap VarP mbs), VarP exs]) run_writer
              --  return $ if ...
              , NoBindS (composeApE (VarE 'return) check)
              ])

-- effectBind ------------------------------------------------------------------

-- | given some var pclv which is of type GetoptName__, return a stmt of the
--   form b <- enactor (dfGetter pclv)
--   (e.g., string_x <- tryWriteF $ return (((fromMaybe "") . (view s___)) pclv
--    above)
mkEffectorBody optdescs getoptName pclv =  do
  -- bs are the names that are assigned to, within the writer monad
  -- binds are each individual bound defaulted option
  (bs, binds) <- mapAndUnzipM (effectBind pclv) optdescs
  -- mbs are the names of the maybe values, having been try-ed; in each case,
  -- it's the name from within the writer, plus a trailing "'"
  mbs         <- sequence $ fmap (newName . nameBase) bs
  -- rtn_bs_tup is the return of a tuple of each bind (return (a, b, ...))
  let rtn_bs_tup = [NoBindS (AppE (VarE 'return) (TupE (fmap VarE bs)))]
      run_writer = composeApE (VarE 'runWriterT) (DoE (binds ++ rtn_bs_tup))
      exs        = mkName "exs"
      -- c'tor args are the map of fromJust across the maybe binds
      c'tor_args = fmap (AppE (VarE 'fromJust) . VarE) mbs
      c'tor      = mAppE ((ConE $ ov_typename getoptName) : c'tor_args)
      check      = CondE -- if null exs
                         (AppE (VarE 'null) (VarE exs))
                         -- then Right $ GetoptName (fromJust a) (fromJust b) ...
                         (composeApE (ConE 'Right) c'tor)
                         -- else Left exs
                         (AppE (ConE 'Left) (VarE exs))
  return (DoE --  ((a, b, ...), exs) <- runWriterT...
              [ BindS (TupP [TupP (fmap VarP mbs), VarP exs]) run_writer
              --  return $ if ...
              , NoBindS (composeApE (VarE 'return) check)
              ])

-- effectBind ------------------------------------------------------------------

-- | given some var pclv which is of type GetoptName__, return a stmt of the
--   form b <- enactor (dfGetter pclv)
--   (e.g., string_x <- tryWriteF $ return (((fromMaybe "") . (view s___)) pclv
--    above)