content: module Rest.Gen.Base.Link
    ( Link
    , LinkItem (..)
    , flattenLast
    , flattenLastResource
    , flattenLink
    , getLinkIds
    , hasParam
    , itemString
    , setLinkIds
    ) where
  
  -- | Data structure representing Api links
  data LinkItem =
      LResource String
    | LAction String
    | LParam String
    | LAccess [Link] deriving Show
  
  instance Eq LinkItem where
    (==) (LAccess a) (LAccess b) = a == b
    (==) (LAccess _) _ = False
    (==) _ (LAccess _) = False
    (==) a b = itemString a == itemString b
  
  type Link = [LinkItem]
  
  hasParam :: LinkItem -> Bool
  hasParam (LAccess l) = any (any hasParam) l
  hasParam (LParam _) = True
  hasParam _ = False
  
  itemString :: LinkItem -> String
  itemString li =
    case li of
      LResource s   -> s
      LAction   s   -> s
      LParam    s   -> s
      _             -> ""
  
  flattenLink :: Link -> [Link]
  flattenLink []               = [[]]
  flattenLink (LAccess ls: rs) = [l ++ r | l <- concatMap flattenLink ls, r <- flattenLink rs]
  flattenLink (v: rs)          = map (v :) $ flattenLink rs
  
  flattenFrom :: (LinkItem -> Bool) -> Link -> [Link]
  flattenFrom f = (\(end, start) -> [ reverse start ++ epart | epart <- flattenLink (reverse end)]) . break f . reverse
  
  flattenLast :: Link -> [Link]
  flattenLast [] = [[]]
  flattenLast xs = (\l -> map (reverse (tail l) ++) $ flattenLink [head l]) . reverse $ xs
  
  flattenLastResource :: Link -> [Link]
  flattenLastResource = flattenFrom $ \x -> case x of LResource _ -> True; _ -> False
  {-
  -- | Make link by replacing identifiers with data
  mkLink :: Link -> [String] -> String
  mkLink []                     _        = ""
  mkLink ((LAction s) : ls)     ps       = "/" ++ s ++ mkLink ls ps
  mkLink ((LAccess _) : ls)     (p : ps) = "/" ++ p ++ mkLink ls ps
  
  -- | Make link by replacing the identifying parts
  mkLink' :: Link -> [String] -> String
  mkLink' []                     _            = ""
  mkLink' ((LAction s) : ls)     ps           = "/" ++ s ++ mkLink' ls ps
  mkLink' ((LAccess _) : ls)     (p : ps)     = "/" ++ p ++ mkLink' ls ps
  -}
  
  getLinkIds :: Link -> [(String, [(String, String)])]
  getLinkIds l =
    case l of
      []                   -> []
      (q: LParam p   : rs) -> (itemString q, [(itemString q, p)]) : getLinkIds rs
      (q: LAccess ls : rs) -> (itemString q, concatMap snd $ concatMap (getLinkIds . (q : )) ls) : getLinkIds rs
      (_: rs)              -> getLinkIds rs
  
  setLinkIds :: Link -> [String] -> String
  setLinkIds _ [] = error "Error in setLinkIds, not enough parameters"
  setLinkIds l (p : ps) =
    case l of
      []                    -> ""
      (_: LParam _  : rs) -> "/" ++ p ++ setLinkIds rs ps
      (_: LAccess _ : rs) -> "/" ++ p ++ setLinkIds rs ps
      (s: rs)               -> "/" ++ itemString s ++ setLinkIds rs (p: ps)
  