module Rest.Gen.Base.Link 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)