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