001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.cli2.option;
018
019import java.util.Iterator;
020import java.util.ListIterator;
021import java.util.Set;
022
023import org.apache.commons.cli2.DisplaySetting;
024import org.apache.commons.cli2.Option;
025import org.apache.commons.cli2.WriteableCommandLine;
026import org.apache.commons.cli2.resource.ResourceConstants;
027import org.apache.commons.cli2.resource.ResourceHelper;
028
029/**
030 * A base implementation of Option providing limited ground work for further
031 * Option implementations.
032 */
033public abstract class OptionImpl implements Option {
034    private final int id;
035    private final boolean required;
036    private Option parent;
037
038    /**
039     * Creates an OptionImpl with the specified id
040     * @param id the unique id of this Option
041     * @param required true iff this Option must be present
042     */
043    public OptionImpl(final int id,
044                      final boolean required) {
045        this.id = id;
046        this.required = required;
047    }
048
049    public boolean canProcess(final WriteableCommandLine commandLine,
050                              final ListIterator arguments) {
051        if (arguments.hasNext()) {
052            final String argument = (String) arguments.next();
053            arguments.previous();
054
055            return canProcess(commandLine, argument);
056        } else {
057            return false;
058        }
059    }
060
061    public String toString() {
062        final StringBuffer buffer = new StringBuffer();
063        appendUsage(buffer, DisplaySetting.ALL, null);
064
065        return buffer.toString();
066    }
067
068    public int getId() {
069        return id;
070    }
071
072    public boolean equals(final Object thatObj) {
073        if (thatObj instanceof OptionImpl) {
074            final OptionImpl that = (OptionImpl) thatObj;
075
076            return (getId() == that.getId()) &&
077                   equals(getPreferredName(), that.getPreferredName()) &&
078                   equals(getDescription(), that.getDescription()) &&
079                   equals(getPrefixes(), that.getPrefixes()) &&
080                   equals(getTriggers(), that.getTriggers());
081        } else {
082            return false;
083        }
084    }
085
086    private boolean equals(Object left,
087                           Object right) {
088        if ((left == null) && (right == null)) {
089            return true;
090        } else if ((left == null) || (right == null)) {
091            return false;
092        } else {
093            return left.equals(right);
094        }
095    }
096
097    public int hashCode() {
098        int hashCode = getId();
099        if (getPreferredName() != null) {
100            hashCode = (hashCode * 37) + getPreferredName().hashCode();
101        }
102
103        if (getDescription() != null) {
104            hashCode = (hashCode * 37) + getDescription().hashCode();
105        }
106
107        hashCode = (hashCode * 37) + getPrefixes().hashCode();
108        hashCode = (hashCode * 37) + getTriggers().hashCode();
109
110        return hashCode;
111    }
112
113    public Option findOption(String trigger) {
114        if (getTriggers().contains(trigger)) {
115            return this;
116        } else {
117            return null;
118        }
119    }
120
121    public boolean isRequired() {
122        return required;
123    }
124
125    public void defaults(final WriteableCommandLine commandLine) {
126        // nothing to do normally
127    }
128
129    public Option getParent() {
130        return parent;
131    }
132
133    public void setParent(Option parent) {
134        this.parent = parent;
135    }
136
137    protected void checkPrefixes(final Set prefixes) {
138        // nothing to do if empty prefix list
139        if (prefixes.isEmpty()) {
140            return;
141        }
142
143        // check preferred name
144        checkPrefix(prefixes, getPreferredName());
145
146        // check triggers
147        this.getTriggers();
148
149        for (final Iterator i = getTriggers().iterator(); i.hasNext();) {
150            checkPrefix(prefixes, (String) i.next());
151        }
152    }
153
154    private void checkPrefix(final Set prefixes,
155                             final String trigger) {
156        for (final Iterator i = prefixes.iterator(); i.hasNext();) {
157            String prefix = (String) i.next();
158
159            if (trigger.startsWith(prefix)) {
160                return;
161            }
162        }
163
164        final ResourceHelper helper = ResourceHelper.getResourceHelper();
165        final String message =
166            helper.getMessage(ResourceConstants.OPTION_TRIGGER_NEEDS_PREFIX, trigger,
167                              prefixes.toString());
168        throw new IllegalArgumentException(message);
169    }
170}