001package org.unix4j.unix.ls;
002
003import java.io.File;
004import java.util.Calendar;
005import java.util.List;
006import java.util.Locale;
007
008import org.unix4j.line.SimpleLine;
009import org.unix4j.processor.LineProcessor;
010import org.unix4j.util.FileUtil;
011import org.unix4j.util.Java7Util;
012import org.unix4j.util.StringUtil;
013
014/**
015 * Formatter for long file output including permissions, owner, size etc. An
016 * example output with long format looks like this:
017 * 
018 * <pre>
019 * -rw-r--r--@  1 myself  geeks   1.6K May  8 23:20 EFMTool Test Case.zip
020 * -rw-r--r--   1 myself  myself  2.6M May  5  2011 EM_FX_RANK_2011-1.pages
021 * -rw-r--r--   1 myself  geeks   466K May  5  2011 EM_FX_RANK_2011-1.pdf
022 * -rw-r--r--   1 myself  geeks   1.3M May  5  2011 EM_FX_RANK_2011.pdf
023 * -rw-r--r--@  1 myself  geeks   118M Apr 11  2011 PS_AIO_07_B110_USW_Full_Mac_WW_11.dmg
024 * drwxrwxrwx   5 myself  geeks   170B Mar  6  2011 Private Tax
025 * -rw-r--r--   1 myself  myself   37M Apr 26  2011 Scanned Image 111160000.pdf
026 * -rw-r--r--   1 myself  mysel    37M Apr 26  2011 Scanned Image 111160008.pdf
027 * drwxrwxrwx   9 myself  geeks   306B Apr 19  2011 aevum
028 * drwxr-xr-x   3 myself  geeks   102B Dec 21  2011 baby
029 * drwxr-xr-x   4 myself  geeks   136B May 18  2011 bills
030 * drwxrwxrwx  17 myself  geeks   578B Jun 15 11:21 cv
031 * </pre>
032 */
033class LsFormatterLong implements LsFormatter {
034
035        protected final ThreadLocal<Calendar> calendar = new ThreadLocal<Calendar>() {
036                @Override
037                protected Calendar initialValue() {
038                        return Calendar.getInstance();
039                }
040        };
041        protected final ThreadLocal<Integer> maxSizeStringLength = new ThreadLocal<Integer>() {
042                @Override
043                protected Integer initialValue() {
044                        return Integer.valueOf(0);
045                }
046        };
047
048        protected Calendar getCalendar() {
049                return calendar.get();
050        }
051
052        @Override
053        public boolean writeFormatted(File relativeTo, File file, LsArguments args, LineProcessor output) {
054                return output.processLine(
055                                new SimpleLine(
056                                                getFilePermissions(file, args) + ' ' +
057                                                                getOwner(file, args) + ' ' +
058                                                                getGroup(file, args) + ' ' +
059                                                                getSize(file, args) + ' ' +
060                                                                getDateTime(file, args) + ' ' +
061                                                                getName(relativeTo, file, args)
062                                        )
063                                );
064        }
065
066        protected String getFilePermissions(File file, LsArguments args) {
067                final boolean r = file.canRead();
068                final boolean w = file.canWrite();
069                final boolean x = file.canExecute();
070                return (file.isDirectory() ? "d" : "-") +
071                                //owner
072                                (r ? 'r' : '-') +
073                                (w ? 'w' : '-') +
074                                (x ? 'x' : '-') +
075                                //group
076                                (r ? '.' : '-') +
077                                (w ? '.' : '-') +
078                                (x ? '.' : '-') +
079                                //other
080                                (r ? '.' : '-') +
081                                (w ? '.' : '-') +
082                                (x ? '.' : '-');
083        }
084
085        protected String getOwner(File file, LsArguments args) {
086                return StringUtil.fixSizeString(7, true, "???");
087        }
088
089        protected String getGroup(File file, LsArguments args) {
090                return StringUtil.fixSizeString(7, true, "???");
091        }
092
093        protected String getSize(File file, LsArguments args) {
094                final String sizeString = LsCommand.getSizeString(args, file.length());
095                return StringUtil.fixSizeString(maxSizeStringLength.get(), false, sizeString);
096        }
097
098        protected long getLastModifiedMS(File file, LsArguments args) {
099                return file.lastModified();
100        }
101
102        protected String getDateTime(File file, LsArguments args) {
103                final Calendar cal = calendar.get();
104                cal.setTimeInMillis(System.currentTimeMillis());//set current date to get current year below
105                final int curYear = cal.get(Calendar.YEAR);
106                cal.setTimeInMillis(getLastModifiedMS(file, args));
107                final int fileYear = cal.get(Calendar.YEAR);
108                final String month = cal.getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault());
109
110                final String sM = StringUtil.fixSizeString(3, true, month);
111                final String sD = StringUtil.fixSizeString(2, false, ' ', cal.get(Calendar.DAY_OF_MONTH));
112                if (curYear == fileYear) {
113                        final String sHou = StringUtil.fixSizeString(2, false, '0', cal.get(Calendar.HOUR_OF_DAY));
114                        final String sMin = StringUtil.fixSizeString(2, false, '0', cal.get(Calendar.MINUTE));
115                        return sM + ' ' + sD + ' ' + sHou + ':' + sMin;
116                } else {
117                        final String sY = StringUtil.fixSizeString(5, false, ' ', fileYear);
118                        return sM + ' ' + sD + ' ' + sY;
119                }
120        }
121
122        protected String getName(File relativeTo, File file, LsArguments args) {
123                return FileUtil.getRelativePath(relativeTo, file);
124        }
125
126        static Factory FACTORY = new Factory() {
127                @Override
128                public LsFormatter create(File relativeTo, File directory, List<File> directoryFiles, LsArguments args) {
129                        final LsFormatterLong fmt = Java7Util.newInstance(LsFormatterLong.class, new LsFormatterLong());
130                        fmt.maxSizeStringLength.set(calculateMaxSizeStringLength(directoryFiles, args));
131                        return fmt;
132                }
133
134                private int calculateMaxSizeStringLength(List<File> directoryFiles, LsArguments args) {
135                        int maxSizeStringLength = 0;
136                        for (final File f : directoryFiles) {
137                                if (f.isFile()) {
138                                        if (f.isFile()) {
139                                                final String sizeString = LsCommand.getSizeString(args, f.length());
140                                                maxSizeStringLength = Math.max(maxSizeStringLength, sizeString.length());
141                                        }
142                                }
143                        }
144                        return maxSizeStringLength;
145                }
146        };
147
148}