module Imp.Type.Alias where

import qualified Control.Monad as Monad
import qualified Control.Monad.Catch as Exception
import qualified Data.Map as Map
import qualified Imp.Exception.InvalidAlias as InvalidAlias
import qualified Imp.Type.Source as Source
import qualified Imp.Type.Target as Target

data Alias = Alias
  { Alias -> Source
source :: Source.Source,
    Alias -> Target
target :: Target.Target
  }
  deriving (Alias -> Alias -> Bool
(Alias -> Alias -> Bool) -> (Alias -> Alias -> Bool) -> Eq Alias
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Alias -> Alias -> Bool
== :: Alias -> Alias -> Bool
$c/= :: Alias -> Alias -> Bool
/= :: Alias -> Alias -> Bool
Eq, Int -> Alias -> ShowS
[Alias] -> ShowS
Alias -> String
(Int -> Alias -> ShowS)
-> (Alias -> String) -> ([Alias] -> ShowS) -> Show Alias
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Alias -> ShowS
showsPrec :: Int -> Alias -> ShowS
$cshow :: Alias -> String
show :: Alias -> String
$cshowList :: [Alias] -> ShowS
showList :: [Alias] -> ShowS
Show)

fromString :: (Exception.MonadThrow m) => String -> m Alias
fromString :: forall (m :: * -> *). MonadThrow m => String -> m Alias
fromString String
string = do
  let (String
before, String
after) = (Char -> Bool) -> String -> (String, String)
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
':') String
string
  Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
Monad.when (String -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
after) (m () -> m ()) -> (InvalidAlias -> m ()) -> InvalidAlias -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. InvalidAlias -> m ()
forall e a. (HasCallStack, Exception e) => e -> m a
forall (m :: * -> *) e a.
(MonadThrow m, HasCallStack, Exception e) =>
e -> m a
Exception.throwM (InvalidAlias -> m ()) -> InvalidAlias -> m ()
forall a b. (a -> b) -> a -> b
$ String -> InvalidAlias
InvalidAlias.new String
string
  Source
src <- String -> m Source
forall (m :: * -> *). MonadThrow m => String -> m Source
Source.fromString String
before
  Target
tgt <- String -> m Target
forall (m :: * -> *). MonadThrow m => String -> m Target
Target.fromString (String -> m Target) -> ShowS -> String -> m Target
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> ShowS
forall a. Int -> [a] -> [a]
drop Int
1 (String -> m Target) -> String -> m Target
forall a b. (a -> b) -> a -> b
$ String
after
  Alias -> m Alias
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Alias {source :: Source
source = Source
src, target :: Target
target = Target
tgt}

toMap :: [Alias] -> Map.Map Target.Target Source.Source
toMap :: [Alias] -> Map Target Source
toMap = (Source -> Source -> Source)
-> [(Target, Source)] -> Map Target Source
forall k a. Ord k => (a -> a -> a) -> [(k, a)] -> Map k a
Map.fromListWith ((Source -> Source) -> Source -> Source -> Source
forall a b. a -> b -> a
const Source -> Source
forall a. a -> a
id) ([(Target, Source)] -> Map Target Source)
-> ([Alias] -> [(Target, Source)]) -> [Alias] -> Map Target Source
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Alias -> (Target, Source)) -> [Alias] -> [(Target, Source)]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Alias
x -> (Alias -> Target
target Alias
x, Alias -> Source
source Alias
x))