-- | Removes all occurrences of the element from the list.
remove :: (Eq a) => a    -- ^ element to be removed
                 -> [a]  -- ^ input list
                 -> [a]  -- ^ output list
remove y [] = []
remove y (x:xs) | y == x    = remove y xs
                | otherwise = x : remove y xs   

----------------------------------------------------------------------

-- | Removes all occurrences of elements belonging to the second lista
--   from the first list.
infix 1 \\
(\\) :: (Eq a) => [a]  -- ^ input list
               -> [a]  -- ^ elements to be removed
               -> [a]  -- ^ output list
xs \\ []     = xs
xs \\ [y]    = remove y xs
xs \\ (y:ys) = (remove y xs) \\ ys

---------------------------------------------------------------------

-- | Returns True if the first list is prefix of the second list,
--   and returns False otherwise
prefix :: Eq a => [a]   -- ^ first list
               -> [a]   -- ^ second list
               -> Bool  -- ^ return value
prefix [] ys = True
prefix (x:xs) [] = False
prefix (x:xs) (y:ys) = (x == y) && prefix xs ys

----------------------------------------------------------------------

-- | Search a context information list for a 'CProc' with a name of 
--   the agent (first parameter) procedure.
--   Returns /CProc Null/, if such an entry does not exist.
findProc :: Agent            -- ^ agent
         -> [ContentsInfo]   -- ^ context information list
         -> ContentsInfo     -- ^ return 'CProc' entry
findProc _ [] = CProc None
findProc agent ((CProc port):xs) 
  | (agent == agentName port) = CProc port
  | otherwise = findProc agent xs
findProc agent (_:xs) = findProc agent xs

----------------------------------------------------------------------

-- | Returns True if the context list does not contain a 'CProc' entry,
--   and returns False otherwise
procFree :: [ContentsInfo] -> Bool
procFree [] = True
procFree ((CProc _):_) = False
procFree (_:xs) = procFree xs

----------------------------------------------------------------------

-- | Returns the first port of the communication transition.
fstPort :: TTransition -> Port
fstPort (TInAP   port _ _) = port
fstPort (TInPP   port _ _) = port
fstPort (TInF    port _ _) = port
fstPort (TOutAP  port _ _) = port 
fstPort (TOutPP  port _ _) = port
fstPort (TOutF   port _ _) = port
fstPort (STInAP  port _ _) = port
fstPort (STInPP  port _ _) = port
fstPort (STOutAP port _ _) = port
fstPort (STOutPP port _ _) = port

----------------------------------------------------------------------

-- | Returns the second port of the communication transition.
sndPort :: TTransition -> Port
sndPort (TInAP   _ port _) = port
sndPort (TInPP   _ port _) = port
sndPort (TInF    _ port _) = port
sndPort (TOutAP  _ port _) = port 
sndPort (TOutPP  _ port _) = port
sndPort (TOutF   _ port _) = port
sndPort (STInAP  _ port _) = port
sndPort (STInPP  _ port _) = port
sndPort (STOutAP _ port _) = port
sndPort (STOutPP _ port _) = port

----------------------------------------------------------------------

-- | Returns True if the transition is a communication transition,
--   and returns False otherwise.
isInOutTransition :: TTransition -> Bool
isInOutTransition (TInAP _ _ _)   = True
isInOutTransition (TInPP _ _ _)   = True
isInOutTransition (TInF _ _ _)    = True
isInOutTransition (TOutAP _ _ _)  = True
isInOutTransition (TOutPP _ _ _)  = True
isInOutTransition (TOutF _ _ _)   = True
isInOutTransition (STInAP _ _ _)  = True
isInOutTransition (STInPP _ _ _)  = True
isInOutTransition (STOutAP _ _ _) = True
isInOutTransition (STOutPP _ _ _) = True
isInOutTransition _               = False

----------------------------------------------------------------------

-- | Removes from the input list all communication transitions that
-- use the given port as the first argument.
removeTransitions1 :: Port             -- ^ port
                   -> [TTransition]    -- ^ input list of transitions
                   -> [TTransition]    -- ^ output list of transitions
removeTransitions1 _ [] = []
removeTransitions1 port (tr:trs) | isInOutTransition tr && port == fstPort tr = removeTransitions1 port trs
                                 | otherwise = tr : removeTransitions1 port trs

----------------------------------------------------------------------

-- | Removes from the input list all communication transitions that
-- use the given port as the second argument.
removeTransitions2 :: Port             -- ^ port
                   -> [TTransition]    -- ^ input list of transitions
                   -> [TTransition]    -- ^ output list of transitions
removeTransitions2 _ [] = []
removeTransitions2 port (tr:trs) | isInOutTransition tr && port == sndPort tr = removeTransitions2 port trs
                                 | otherwise = tr : removeTransitions2 port trs

----------------------------------------------------------------------

-- | Removes from the input list all communication transitions that
-- use the given port
removeTransitions :: Port             -- ^ port
                  -> [TTransition]    -- ^ input list of transitions
                  -> [TTransition]    -- ^ output list of transitions
removeTransitions port trans = removeTransitions2 port (removeTransitions1 port trans) 

----------------------------------------------------------------------

-- | Returns value of the lowest priority. The highest priority in Alvis is equal to 0.
--   The lowest priority in Alvis is equal to 9.
minPriority :: Int
minPriority = 9

----------------------------------------------------------------------

