package com.lexicalscope.jewel.cli; import static java.util.Arrays.asList; import java.util.List; import com.lexicalscope.fluentreflection.FluentMethod; import com.lexicalscope.jewel.cli.specification.OptionSpecification; import com.lexicalscope.jewel.cli.specification.SpecificationMultiplicity; /* * Copyright 2012 Tim Wood * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ abstract class AbstractOptionSpecification implements OptionSpecification, Comparable<OptionSpecification> { protected final OptionAdapter annotation; private final List<String> defaultValue; public AbstractOptionSpecification(final OptionAdapter annotation) { this.annotation = annotation; if (annotation.defaultToNull() && annotation.hasDefaultValue()) { throw new InvalidOptionSpecificationException("option cannot have null default and non-null default value: " + annotation.method()); } else if (annotation.defaultToNull()) { if (annotation.isMultiValued()) { defaultValue = null; } else { defaultValue = asList((String) null); } } else if (annotation.hasDefaultValue()) { defaultValue = asList(annotation.defaultValue()); } else { defaultValue = null; } if(hasExactCount() && exactly() < minimum() || exactly() > maximum()) { throw new InvalidOptionSpecificationException("option has maximum and minimum and exact count which can never be satisfied: " + annotation.method()); } else if(minimum() > maximum()) { throw new InvalidOptionSpecificationException("minimum cannot be greater than maximum: " + annotation.method()); } else if(maximum() < 0) { throw new InvalidOptionSpecificationException("maximum must not be less than zero: " + annotation.method()); } } @Override public final List<String> getDefaultValue() { return defaultValue; } @Override public final boolean hasDefaultValue() { return getDefaultValue() != null || annotation.defaultToNull(); } @Override public final String getDescription() { return annotation.description(); } @Override public final Class<?> getType() { return annotation.getValueType().classUnderReflection(); } @Override public final boolean isMultiValued() { return annotation.isMultiValued(); } @Override public final boolean isOptional() { return getOptionalityMethod() != null || isBoolean() || hasDefaultValue(); } public abstract boolean isBoolean(); @Override public final String getCanonicalIdentifier() { return getMethod().property(); } @Override public final FluentMethod getMethod() { return annotation.method(); } @Override public final FluentMethod getOptionalityMethod() { return annotation.correspondingOptionalityMethod(); } @Override public final int compareTo(final OptionSpecification other) { return getCanonicalIdentifier().compareTo(other.getCanonicalIdentifier()); } @Override public final boolean isHidden() { return annotation.isHidden(); } @Override public boolean allowedThisManyValues(final int count) { if(count == 0 && !hasValue()) { return true; } else if(count == 1 && hasValue() && !isMultiValued()) { return true; } else if(isMultiValued() && hasExactCount()) { return count == exactly(); } else if(isMultiValued()) { return minimum() <= count && count <= maximum(); } return false; } @Override public final int maximum() { return annotation.maximum(); } @Override public final int minimum() { return annotation.minimum(); } @Override public final int exactly() { return annotation.exactly(); } @Override public final boolean hasExactCount() { return annotation.exactly() >= 0; } @Override public <T> T compareCountToSpecification( final int valueCount, final SpecificationMultiplicity<T> specificationMultiplicity) { if(!hasValue() && valueCount > 0) { return specificationMultiplicity.expectedNoneGotSome(); } else if(!isMultiValued() && hasValue() && valueCount == 0) { return specificationMultiplicity.expectedOneGotNone(); } else if(!isMultiValued() && valueCount > 1) { return specificationMultiplicity.expectedOneGotSome(); } else if(isMultiValued()) { if(hasExactCount() && valueCount != exactly()) { if(valueCount < exactly()) { return specificationMultiplicity.expectedExactGotTooFew(exactly(), valueCount); } else { return specificationMultiplicity.expectedExactGotTooMany(exactly(), valueCount); } } else if(valueCount < minimum()) { return specificationMultiplicity.expectedMinimumGotTooFew(minimum(), valueCount); } else if(valueCount > maximum()) { return specificationMultiplicity.expectedMaximumGotTooMany(maximum(), valueCount); } } return specificationMultiplicity.allowed(); } @Override public int maximumArgumentConsumption() { if(isMultiValued()) { if(hasExactCount()) { return exactly(); } else { return maximum(); } } else if (hasValue()) { return 1; } return 0; } }