-- |Make a FA complete.
complete :: forall sym sta.( Ord sym, Ord sta) => Set sym -> Fa sym sta -> Fa sym (Set sta)
complete symbols fa@(Fa initialStates finalStates transitions) =
  Fa init final trans
    where
      init = Set.map Set.singleton initialStates
      final = Set.map Set.singleton finalStates

      wrap :: Ord a => Set a -> Set (Set a)
      wrap =
        Set.map Set.singleton

      wrapOrEmptySet :: Ord a => Set a -> Set (Set a)
      wrapOrEmptySet elements =
        if null elements
          then Set.singleton Set.empty
          else wrap elements

      trans :: Ord sym => Set (Transition sym (Set sta))
      trans =
        symbols `andThen` (\symbol ->
        Set.insert Set.empty (wrap $ states fa) `andThen` (\state ->
        wrapOrEmptySet (post fa state symbol) `andThen` (\postState ->
        Helpers.return $ Transition symbol state postState)))

-- |Creates a union of two FAs with product state ('sta1', 'sta2'). Note: Input FAs must be complete.
complete :: forall sym sta.( Ord sym, Ord sta) => Set sym -> Fa sym sta -> Fa sym (Set sta)
complete symbols fa@(Fa initialStates finalStates transitions) =
  Fa init final trans
    where
      init = Set.map Set.singleton initialStates
      final = Set.map Set.singleton finalStates

      wrap :: Ord a => Set a -> Set (Set a)
      wrap =
        Set.map Set.singleton

      wrapOrEmptySet :: Ord a => Set a -> Set (Set a)
      wrapOrEmptySet elements =
        if null elements
          then Set.singleton Set.empty
          else wrap elements

      trans :: Ord sym => Set (Transition sym (Set sta))
      trans =
        symbols `andThen` (\symbol ->
        Set.insert Set.empty (wrap $ states fa) `andThen` (\state ->
        wrapOrEmptySet (post fa state symbol) `andThen` (\postState ->
        Helpers.return $ Transition symbol state postState)))

-- |Creates a union of two FAs with product state ('sta1', 'sta2'). Note: Input FAs must be complete.
complete symbols fa@(Fa initialStates finalStates transitions) =
  Fa init final trans
    where
      init = Set.map Set.singleton initialStates
      final = Set.map Set.singleton finalStates

      wrap :: Ord a => Set a -> Set (Set a)
      wrap =
        Set.map Set.singleton

      wrapOrEmptySet :: Ord a => Set a -> Set (Set a)
      wrapOrEmptySet elements =
        if null elements
          then Set.singleton Set.empty
          else wrap elements

      trans :: Ord sym => Set (Transition sym (Set sta))
      trans =
        symbols `andThen` (\symbol ->
        Set.insert Set.empty (wrap $ states fa) `andThen` (\state ->
        wrapOrEmptySet (post fa state symbol) `andThen` (\postState ->
        Helpers.return $ Transition symbol state postState)))

-- |Creates a union of two FAs with product state ('sta1', 'sta2'). Note: Input FAs must be complete.