001package org.unix4j.unix.ls;
002
003import java.io.File;
004import java.util.Comparator;
005
006import org.unix4j.util.FileUtil;
007import org.unix4j.util.sort.CompositeComparator;
008
009/**
010 * Non-instantiable class with static comparator constants used to sort files.
011 */
012class FileComparators {
013        /**
014         * Sorts files according to file type. Hidden files are listed first, then
015         * normal files, all other files and finally the directories.
016         */
017        static Comparator<File> FILE_TYPE = new Comparator<File>() {
018                @Override
019                public int compare(File f1, File f2) {
020                        if (f1.isHidden()) {
021                                return f2.isHidden() ? 0 : -1;
022                        } else if (f2.isHidden()) {
023                                return 1;
024                        }
025                        if (f1.isFile()) {
026                                return f2.isFile() ? 0 : -1;
027                        } else if (f2.isFile()) {
028                                return 1;
029                        }
030                        if (!f1.isDirectory()) {
031                                return !f2.isDirectory() ? 0 : -1;
032                        } else if (!f2.isDirectory()) {
033                                return 1;
034                        }
035                        return 0;// both directories
036                }
037        };
038
039        /**
040         * Sorts files alphabetically according to the file name.
041         */
042        static Comparator<File> FILE_NAME = new Comparator<File>() {
043                @Override
044                public int compare(File f1, File f2) {
045                        return f1.getName().compareTo(f2.getName());
046                }
047        };
048
049        /**
050         * Sorts files alphabetically according to the relative file name from the
051         * specified root to the actual file.
052         * 
053         * @param relativeTo
054         *            the root for the relative file name
055         * @return a comparator for alphabetical ordering of the relative file names
056         */
057        static Comparator<File> relativeFileName(final File relativeTo) {
058                return new Comparator<File>() {
059                        @Override
060                        public int compare(File f1, File f2) {
061                                final String relName1 = FileUtil.getRelativePath(relativeTo, f1);
062                                final String relName2 = FileUtil.getRelativePath(relativeTo, f2);
063                                return relName1.compareTo(relName2);
064                        }
065                };
066        }
067        
068        /**
069         * Sorts . before .. and then all other files.
070         * 
071         * @param relativeTo
072         *            the root to evaluate the . and .. files
073         * @return a comparator sorting . before .. before everything else
074         */
075        static Comparator<File> dotDotdotRest(final File relativeTo) {
076                return new Comparator<File>() {
077                        @Override
078                        public int compare(File f1, File f2) {
079                                final String relName1 = FileUtil.getRelativePath(relativeTo, f1);
080                                final String relName2 = FileUtil.getRelativePath(relativeTo, f2);
081
082                                final boolean isCur1 = ".".equals(relName1);
083                                final boolean isCur2 = ".".equals(relName2);
084                                if (isCur1) {
085                                        return isCur2 ? 0 : -1;
086                                } else if (isCur2) {
087                                        return 1;
088                                }
089
090                                final boolean isPar1 = "..".equals(relName1);
091                                final boolean isPar2 = "..".equals(relName2);
092                                if (isPar1) {
093                                        return isPar2 ? 0 : -1;
094                                } else if (isPar2) {
095                                        return 1;
096                                }
097
098                                return 0;
099                        }
100                };
101        }
102
103        /**
104         * Sorts files according to the last-modified time. More recently touched
105         * files appear first in a sorted list.
106         */
107        static Comparator<File> FILE_LAST_MODIFIED = new Comparator<File>() {
108                @Override
109                public int compare(File f1, File f2) {
110                        final long lastMod1 = f1.lastModified();
111                        final long lastMod2 = f2.lastModified();
112                        return lastMod1 > lastMod2 ? -1 : lastMod1 < lastMod2 ? 1 : 0;
113                }
114        };
115
116        /**
117         * Sorts files according to file type and then by relative file name. Hidden
118         * files are listed first, then normal files, all other files and finally
119         * the directories.
120         * 
121         * @param relativeTo
122         *            the root for the relative file name
123         * @return a comparator first sorting by file type and then by relative file
124         *         name
125         */
126        static Comparator<File> typeAndRelativeFileName(File relativeTo) {
127                return new CompositeComparator<File>(dotDotdotRest(relativeTo), FILE_TYPE, relativeFileName(relativeTo));
128        }
129
130        /**
131         * Sorts files according to the last modified time (last touched files
132         * first) and then by relative file name.
133         * @param relativeTo
134         *            the root for the relative file name
135         * @return a comparator first sorting by last modified time and then by relative file
136         *         name
137         */
138        static Comparator<File> timeAndRelativeFileName(File relativeTo) {
139                return new CompositeComparator<File>(FILE_LAST_MODIFIED, relativeFileName(relativeTo));
140        }
141
142        // no instances
143        private FileComparators() {
144                super();
145        }
146
147}