--
-- Copyright (c) B.Zapf July 2005
--
--

-- | This is a little helper for completion interfaces.

module Yi.Keymap.Completion (
        CompletionTree(CT),
        stepTree, obvious, mergeTrees, listToTree, complete)
   where

import Data.List

-- inside a completion tree, the a's must be unique on each level

data CompletionTree a = CT [(a,CompletionTree a)]

instance (Show a) => Show (CompletionTree a) where
  show x = show' x

show' :: (Show a) => CompletionTree a -> String
show' (CT []) = []
show' (CT [(a,st)]) = shows a $ show' st
show' (CT trees) = "["++
                   (concat $
                    intersperse "|" $
                    map (\(x,y)->shows x $ show' y) trees)
                   ++"]"

compareBy :: (Ord b) => (a->b)->a->a->Ordering
compareBy f a b = compare (f a) (f b)

listToTree :: [a] -> CompletionTree a
listToTree = foldr (\a b->CT [(a,b)]) (CT [])

stepTree :: Eq a => CompletionTree a->a->Maybe ([a],CompletionTree a)
stepTree (CT completions) letter = Just $ obvious $ CT $ filter
                                   ((letter==).fst) completions

obvious :: CompletionTree a -> ([a],CompletionTree a)
obvious (CT [(letter,moretrees)]) = ((\(x,y)->(letter:x,y)) $
                                             obvious moretrees)
obvious remainingchoice           = ([],remainingchoice)

mergeTrees :: Ord a => [CompletionTree a] -> CompletionTree a
mergeTrees a = mergeTrees' (map sort' a)
  where sort' = CT.(sortBy (compareBy fst).(\(CT l)->l))

mergeTrees':: Ord a => [CompletionTree a] -> CompletionTree a
mergeTrees' trees = CT $
                    map (\x->(fst $ head x,mergeTrees $ map snd x)) $
                    groupBy (((EQ==).).compareBy fst)  $
                    sortBy (compareBy fst) $
                    concat $
                    map (\(CT x)->x) trees

complete :: Eq a => CompletionTree a -> [a] -> ([a],CompletionTree a)
complete tree    [] = ([],tree)
complete (CT []) _  = ([],CT [])
complete (CT level) (a:ta) = (\(x,y)->(a:x,y)) $
    case match of
       Just m -> complete (snd m) ta
       Nothing -> ([],CT [])
     where match = find ((a==).fst) level


--alternatives :: CompletionTree a->[[a]]