-- Copyright (C) 2005 David Roundy
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2, or (at your option)
-- any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; see the file COPYING.  If not, write to
-- the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-- Boston, MA 02110-1301, USA.

module FilePathUtils ( fix_maybe_absolute, unfix_maybe_absolute,
                       drop_paths, (///) ) where

import List ( isPrefixOf )
import Maybe ( catMaybes )

import Autoconf ( path_separator )
import FileName ( fn2fp, fp2fn, norm_path )
import DarcsURL ( is_absolute, is_relative, is_file )
#include "impossible.h"

fix_maybe_absolute :: FilePath -> FilePath -> FilePath -> FilePath
fix_maybe_absolute _ _ pat  | not $ is_file pat = pat
fix_maybe_absolute repo fix pat = fma $ map cleanup pat
    where fma p | is_relative p = fix /// p
                | is_absolute p = unabsolute p
                | otherwise = p
          unabsolute p
            | null repo         = p -- it's ok not to specify a repository
            | not_absolute repo = bug $ "Repository was not an absolute path: " ++ repo
            | is_in_repo p      = "." ++ (drop (length repo) p)
            | otherwise         = p
          -- Note that (repo `isPrefixOf` p) without the slash is not a good idea.
          -- The slash is important: what if your repo is "foo" and p is "foobar"?
          is_in_repo p = (repo == p || (repo ++ "/") `isPrefixOf` p)
          not_absolute = not.is_absolute -- is relative or url

unfix_maybe_absolute :: FilePath -> FilePath -> FilePath
unfix_maybe_absolute _ pat | not $ is_file pat = pat
unfix_maybe_absolute fix pat = fma $ map cleanup pat
    where fma p | is_absolute p = p
          fma p = make_dotdots fix /// p

cleanup :: Char -> Char
cleanup '\\' | path_separator == '\\' = '/'
cleanup c = c

make_dotdots :: FilePath -> FilePath
make_dotdots "" = ""
make_dotdots p | is_absolute p = bug $ "Can't make_dotdots on an absolute path:  "
make_dotdots p = "../" ++ case snd $ break (=='/') p of
                          "" -> ""
                          r -> make_dotdots r

drop_paths :: String -> [String] -> [String]
drop_paths "" ps = map norm_relative ps
    where norm_relative f | is_relative f = do_norm f
                          | otherwise = f
drop_paths fix ps = catMaybes $ map drop_path ps
  where drop_path p | not $ is_relative p = Just p
        drop_path ('.':'/':p) = drop_path $ dropWhile (=='/') p
        drop_path p = if take (length fix) p == fix
                      then Just $ dropWhile (=='/') $ drop (length fix) p
                      else if is_relative p
                           then Nothing
                           else Just p

(///) :: FilePath -> FilePath -> FilePath
""///a = do_norm a
a///b = do_norm $ a ++ "/" ++ b

do_norm :: FilePath -> FilePath
do_norm f = fn2fp $ norm_path $ fp2fn f
