manatee-core-0.0.1: Manatee/Toolkit/Data/Unique.hs
-- Author: Andy Stewart <lazycat.manatee@gmail.com>
-- Maintainer: Andy Stewart <lazycat.manatee@gmail.com>
--
-- Copyright (C) 2010 Andy Stewart, all rights reserved.
--
-- 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 3 of the License, or
-- 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. If not, see <http://www.gnu.org/licenses/>.
module Manatee.Toolkit.Data.Unique where
import Control.Arrow
import Data.List
import Manatee.Toolkit.General.Basic
import Manatee.Toolkit.General.FilePath
import Manatee.Toolkit.General.List
import System.FilePath
import qualified Data.Map as M
-- | Unique file path list.
unique :: [FilePath] -> [(FilePath, FilePath)]
unique filePathList =
-- Zip file name and different directory name.
zip fnl
-- Get file path.
$ map snd
-- To list.
$ M.toList
$ M.fromList
-- Swap filepath and page index.
$ map swap
-- Get different directory name for unique.
$ concatMap uniqueDiff
-- Group page name with same filename.
(uniqueGroup (pairPred fpl) uniquePick)
-- Trailing path separator when filepath is directory name.
where fpl = map dropTrailingPathSeparator filePathList
fnl = map takeFileNameExceptRoot fpl
-- | Different file path.
uniqueDiff :: [(FilePath, Int)] -> [(FilePath, Int)]
-- Don't do different when just alone file path.
uniqueDiff (xs:[]) = [first (const "") xs]
-- Generate minimum different directory between filepathes.
uniqueDiff list = concatMap uniqueDiffInternal (uniqueGroup list uniquePick_)
-- | Internal function for different file path.
uniqueDiffInternal :: [(FilePath, Int)] -> [(FilePath, Int)]
uniqueDiffInternal [] = []
-- Just add previous directory when alone file path.
uniqueDiffInternal (xs:[]) = [first getUpperDirectoryName xs]
-- Generate minimum different directory between filepathes.
uniqueDiffInternal list =
map (\(a,b) -> (uniqueMinDiffDir a (uniqueCommon $ map fst list), b)) list
-- | Get min diff directory.
uniqueMinDiffDir :: FilePath -> FilePath -> FilePath
uniqueMinDiffDir filepath common =
addTrailingPathSeparator $ take (length filepath - length common) filepath
-- | Group file path with same file name.
uniqueGroup :: [(FilePath, Int)] -> ([(FilePath, Int)] -> [(FilePath, Int)]) -> [[(FilePath, Int)]]
uniqueGroup [] _ = []
uniqueGroup list@(_:[]) _ = group list
uniqueGroup list@(_:xs) f = pl : uniqueGroup ys f
where
pl = f list
ys = if length pl == 1
-- If pick list just have one element, get remain elements.
then xs
-- Otherwise delete pick list from current list.
else (\\) list pl
-- | Pick same file name from list.
uniquePick :: [(FilePath, Int)] -> [(FilePath, Int)]
uniquePick [] = []
uniquePick (x:[]) = [x]
uniquePick (x@(a,_):y@(b,_):ys)
| takeFileName a == takeFileName b
= x : uniquePick (y:ys)
| otherwise
= uniquePick (x : ys)
-- | Pick same path part from list.
uniquePick_ :: [(FilePath, Int)] -> [(FilePath, Int)]
uniquePick_ [] = []
uniquePick_ (x:[]) = [x]
uniquePick_ (x@(a,_):y@(b,_):ys)
| fileIntersectEnd a b == takeFileName a
= uniquePick_ (x : ys)
| otherwise
= x : uniquePick_ (y:ys)
-- | Get common path with all file path.
uniqueCommon :: [FilePath] -> FilePath
uniqueCommon [] = []
-- Remove otiose characters before path separator.
uniqueCommon (x:[]) = dropWhile (/= pathSeparator) x
-- Compare all element in list for get common part.
uniqueCommon (x:y:ys) = uniqueCommon (intersectEnd x y : ys)