content: module Vimus.Util where
  
  import           Control.Applicative
  import           Data.List (isPrefixOf)
  import           Data.Char as Char
  import           Data.Maybe (fromJust)
  import           System.FilePath ((</>))
  import           System.Environment (getEnvironment)
  
  import           Network.MPD (MonadMPD, PlaylistName, Id)
  import qualified Network.MPD as MPD
  
  -- | Remove leading and trailing whitespace
  strip :: String -> String
  strip = dropWhile Char.isSpace . reverse . dropWhile Char.isSpace . reverse
  
  data MatchResult = None | Match String | Ambiguous [String]
    deriving (Eq, Show)
  
  match :: String -> [String] -> MatchResult
  match s l = case filter (isPrefixOf s) l of
    []  -> None
    [x] -> Match x
    xs   -> if s `elem` xs then Match s else Ambiguous xs
  
  -- | Get longest common prefix of a list of strings.
  --
  -- >>> commonPrefix ["foobar", "foobaz", "foosomething"]
  -- "foo"
  commonPrefix :: [String] -> String
  commonPrefix [] = ""
  commonPrefix xs = foldr1 go xs
    where
      go (y:ys) (z:zs)
        | y == z = y : go ys zs
      go _ _     = []
  
  -- | Add a song which is inside a playlist, returning its id.
  addPlaylistSong :: MonadMPD m => PlaylistName -> Int -> m Id
  addPlaylistSong plist index = do
    current <- MPD.playlistInfo Nothing
    MPD.load plist
    new <- MPD.playlistInfo Nothing
  
    let (first, this:rest) = splitAt index . map (fromJust . MPD.sgId) $ drop (length current) new
    mapM_ MPD.deleteId $ first ++ rest
  
    return this
  
  -- | A copy of `System.Process.Internals.translate`.
  posixEscape :: String -> String
  posixEscape str = '\'' : foldr escape "'" str
    where escape '\'' = showString "'\\''"
          escape c    = showChar c
  
  
  -- | Expand a tilde at the start of a string to the users home directory.
  --
  -- Expansion is only performed if the tilde is either followed by a slash or
  -- the only character in the string.
  expandHome :: FilePath -> IO (Either String FilePath)
  expandHome path = do
    home <- maybe err Right . lookup "HOME" <$> getEnvironment
    case path of
      "~"            -> return home
      '~' : '/' : xs -> return $ (</> xs) `fmap` home
      xs             -> return (Right xs)
    where
      err = Left ("expansion of " ++ show path ++ " failed: $HOME is not defined")
  
  -- | Confine a number to an interval.
  --
  -- The result will be greater or equal to a given lower bound and (if still
  -- possible) smaller than a given upper bound.
  clamp :: Int -- ^ lower bound (inclusive)
        -> Int -- ^ upper bound (exclusive)
        -> Int
        -> Int
  clamp lower upper n = max lower $ min (pred upper) n
  
  -- | Emit ANSI sequence to change the console window title.
  setTitle :: String -> IO ()
  setTitle title = putStrLn $ "\ESC]0;" ++ filter (/= '\007') title ++ "\007"
  