001package org.unix4j.io;
002
003import java.io.File;
004import java.io.FileDescriptor;
005import java.io.FileInputStream;
006import java.io.FileNotFoundException;
007import java.io.FileReader;
008import java.io.InputStreamReader;
009import java.util.ArrayList;
010import java.util.List;
011
012import org.unix4j.util.FileUtil;
013
014/**
015 * Input device reading from a {@link File}.
016 */
017public class FileInput extends ReaderInput {
018
019        private final String fileInfo;
020
021        public FileInput(FileReader fileReader) {
022                super(fileReader);
023                this.fileInfo = fileReader.toString();
024        }
025
026        public FileInput(File currentDirectory, File file) {
027                super(createFileReader(currentDirectory, file));
028                this.fileInfo = file.toString();
029        }
030
031        public FileInput(File file) {
032                super(createFileReader(file));
033                this.fileInfo = file.toString();
034        }
035
036        public FileInput(FileInputStream fileStream) {
037                super(new InputStreamReader(fileStream));
038                this.fileInfo = fileStream.toString();
039        }
040
041        public FileInput(FileDescriptor fileDesc) {
042                super(new FileReader(fileDesc));
043                this.fileInfo = fileDesc.toString();
044        }
045
046        public FileInput(String file) {
047                this(new File(file));
048        }
049        public FileInput(File currentDirectory, String file) {
050                this(currentDirectory, new File(file));
051        }
052
053        /**
054         * Creates a new {@link FileInput} object for each of the specified files
055         * and resturns a list with all input objects.
056         * 
057         * @param files
058         *            the files for whose to create a {@code FileInput} object
059         */
060        public static List<FileInput> multiple(File... files) {
061                final List<FileInput> inputs = new ArrayList<FileInput>(files.length);
062                for (int i = 0; i < files.length; i++) {
063                        inputs.add(new FileInput(files[i]));
064                }
065                return inputs;
066        }
067
068        /**
069         * Creates a new {@link FileInput} object for each of the specified files
070         * and resturns a list with all input objects.
071         * 
072         * @param files
073         *            the files for whose to create a {@code FileInput} object
074         */
075        public static List<FileInput> multiple(List<File> files) {
076                final List<FileInput> inputs = new ArrayList<FileInput>(files.size());
077                for (int i = 0; i < files.size(); i++) {
078                        inputs.add(new FileInput(files.get(i)));
079                }
080                return inputs;
081        }
082
083        /**
084         * Creates and returns an input composed from the specified files
085         * altogether. The resulting input object returns the lines lines of the
086         * first file first, then the lines of the second file etc.
087         * 
088         * @param files
089         *            the files to combine into a single input object
090         */
091        public static Input composite(File... files) {
092                if (files.length == 0)
093                        return NullInput.INSTANCE;
094                if (files.length == 1)
095                        return new FileInput(files[0]);
096                return new CompositeInput(multiple(files));
097        }
098
099        /**
100         * Creates and returns an input composed from the specified files
101         * altogether. The resulting input object returns the lines lines of the
102         * first file first, then the lines of the second file etc.
103         * 
104         * @param files
105         *            the files to combine into a single input object
106         */
107        public static Input composite(List<File> files) {
108                if (files.size() == 0)
109                        return NullInput.INSTANCE;
110                if (files.size() == 1)
111                        return new FileInput(files.get(0));
112                return new CompositeInput(multiple(files));
113        }
114
115        private static FileReader createFileReader(File file) {
116                try {
117                        return new FileReader(file);
118                } catch (FileNotFoundException e) {
119                        throw new RuntimeException(e);
120                }
121        }
122
123        private static FileReader createFileReader(File currentDirectory, File path) {
124                try {
125                        final File file = FileUtil.toAbsoluteFile(currentDirectory, path);
126                        return new FileReader(file);
127                } catch (FileNotFoundException e) {
128                        throw new RuntimeException(e);
129                }
130        }
131
132        /**
133         * Returns the file info string, for instance a file path or file name.
134         * 
135         * @return the file info string, usually the file name or path.
136         */
137        public String getFileInfo() {
138                return fileInfo;
139        }
140
141        /**
142         * Returns the file info string relative to the given root directory. If a
143         * relative path cannot be evaluated, the method defaults to
144         * {@link #getFileInfo()}.
145         * 
146         * @param relativeRoot
147         *            the relative root for the returned path, may be ignored if a
148         *            relative path cannot be evaluated for the underlying source
149         *            object
150         * @return the file info string, usually the file name or path relative to
151         *         the given root directory
152         */
153        public String getFileInfo(File relativeRoot) {
154                try {
155                        return FileUtil.getRelativePath(relativeRoot, new File(fileInfo));
156                } catch (Exception e) {
157                        return getFileInfo();
158                }
159        }
160
161        @Override
162        public String toString() {
163                return getClass().getSimpleName() + "(fileInfo=" + getFileInfo() + ")";
164        }
165}