001package org.unix4j.unix.from;
002
003
004import org.unix4j.command.Arguments;
005import org.unix4j.context.ExecutionContext;
006import org.unix4j.convert.ValueConverter;
007import org.unix4j.util.ArrayUtil;
008import org.unix4j.variable.Arg;
009import org.unix4j.variable.VariableContext;
010
011import org.unix4j.unix.From;
012
013/**
014 * Arguments and options for the {@link From from} command.
015 */
016public final class FromArguments implements Arguments<FromArguments> {
017        
018
019        
020        // operand: <path>
021        private String path;
022        private boolean pathIsSet = false;
023        
024        // operand: <input>
025        private org.unix4j.io.Input input;
026        private boolean inputIsSet = false;
027        
028        /**
029         * Constructor to use if no options are specified.
030         */
031        public FromArguments() {
032                super();
033        }
034
035        private Object resolveVariable(VariableContext context, String variable) {
036                final Object value = context.getValue(variable);
037                if (value != null) {
038                        return value;
039                }
040                throw new IllegalArgumentException("cannot resolve variable " + variable + 
041                                " in command: from " + this);
042        }
043        private <V> V convert(ExecutionContext context, String operandName, Class<V> operandType, Object value) {
044                final ValueConverter<V> converter = context.getValueConverterFor(operandType);
045                final V convertedValue;
046                if (converter != null) {
047                        convertedValue = converter.convert(value);
048                } else {
049                        convertedValue = null;
050                }
051                if (convertedValue != null) {
052                        return convertedValue;
053                }
054                throw new IllegalArgumentException("cannot convert --" + operandName + 
055                                " value '" + value + "' into the type " + operandType.getName() + 
056                                " for from command");
057        }
058        
059        @Override
060        public FromArguments getForContext(ExecutionContext context) {
061                if (context == null) {
062                        throw new NullPointerException("context cannot be null");
063                }
064                //no String... args for this command, hence nothing to resolve
065                return this;
066        }
067        
068        /**
069         * Returns the {@code <path>} operand value (variables are NOT resolved): the file to use as input; wildcards * and ? are supported; relative 
070                        paths are resolved on the basis of the current working directory.
071         * 
072         * @return the {@code <path>} operand value (variables are not resolved)
073         * @throws IllegalStateException if this operand has never been set
074         * @see #getPath(ExecutionContext)
075         */
076        public String getPath() {
077                if (pathIsSet) {
078                        return path;
079                }
080                throw new IllegalStateException("operand has not been set: " + path);
081        }
082        /**
083         * Returns the {@code <path>} (variables are resolved): the file to use as input; wildcards * and ? are supported; relative 
084                        paths are resolved on the basis of the current working directory.
085         * 
086         * @param context the execution context used to resolve variables
087         * @return the {@code <path>} operand value after resolving variables
088         * @throws IllegalStateException if this operand has never been set
089         * @see #getPath()
090         */
091        public String getPath(ExecutionContext context) {
092                final String value = getPath();
093                if (Arg.isVariable(value)) {
094                        final Object resolved = resolveVariable(context.getVariableContext(), value);
095                        final String converted = convert(context, "path", String.class, resolved);
096                        return converted;
097                }
098                return value;
099        }
100
101        /**
102         * Returns true if the {@code <path>} operand has been set. 
103         * <p>
104         * Note that this method returns true even if {@code null} was passed to the
105         * {@link #setPath(String)} method.
106         * 
107         * @return      true if the setter for the {@code <path>} operand has 
108         *                      been called at least once
109         */
110        public boolean isPathSet() {
111                return pathIsSet;
112        }
113        /**
114         * Sets {@code <path>}: the file to use as input; wildcards * and ? are supported; relative 
115                        paths are resolved on the basis of the current working directory.
116         * 
117         * @param path the value for the {@code <path>} operand
118         */
119        public void setPath(String path) {
120                this.path = path;
121                this.pathIsSet = true;
122        }
123        /**
124         * Returns the {@code <input>} operand value: the input object to read from
125         * 
126         * @return the {@code <input>} operand value (variables are not resolved)
127         * @throws IllegalStateException if this operand has never been set
128         * 
129         */
130        public org.unix4j.io.Input getInput() {
131                if (inputIsSet) {
132                        return input;
133                }
134                throw new IllegalStateException("operand has not been set: " + input);
135        }
136
137        /**
138         * Returns true if the {@code <input>} operand has been set. 
139         * <p>
140         * Note that this method returns true even if {@code null} was passed to the
141         * {@link #setInput(org.unix4j.io.Input)} method.
142         * 
143         * @return      true if the setter for the {@code <input>} operand has 
144         *                      been called at least once
145         */
146        public boolean isInputSet() {
147                return inputIsSet;
148        }
149        /**
150         * Sets {@code <input>}: the input object to read from
151         * 
152         * @param input the value for the {@code <input>} operand
153         */
154        public void setInput(org.unix4j.io.Input input) {
155                this.input = input;
156                this.inputIsSet = true;
157        }
158        
159
160        @Override
161        public String toString() {
162                // ok, we have options or arguments or both
163                final StringBuilder sb = new StringBuilder();
164
165{
166                        // operand: <path>
167                        if (pathIsSet) {
168                                if (sb.length() > 0) sb.append(' ');
169                                sb.append("--").append("path");
170                                sb.append(" ").append(toString(getPath()));
171                        }
172                        // operand: <input>
173                        if (inputIsSet) {
174                                if (sb.length() > 0) sb.append(' ');
175                                sb.append("--").append("input");
176                                sb.append(" ").append(toString(getInput()));
177                        }
178                }
179                
180                return sb.toString();
181        }
182        private static String toString(Object value) {
183                if (value != null && value.getClass().isArray()) {
184                        return ArrayUtil.toString(value);
185                }
186                return String.valueOf(value);
187        }
188}