/*
* Copyright 2013-2016 Skynav, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.skynav.ttv.verifier.util;
import java.util.List;
import java.util.Set;
import org.xml.sax.Locator;
import com.skynav.ttv.model.value.Length;
import com.skynav.ttv.model.value.Measure;
import com.skynav.ttv.model.value.impl.MeasureImpl;
import com.skynav.ttv.util.Location;
import com.skynav.ttv.util.Reporter;
import com.skynav.ttv.verifier.VerifierContext;
import com.skynav.ttv.verifier.util.MixedUnitsTreatment;
import com.skynav.ttv.verifier.util.NegativeTreatment;
public class Measures {
public static boolean isMeasure(String value, Location location, VerifierContext context, Object[] treatments, Measure[] outputMeasure) {
Measure m = null;
if (maybeMeasureKeyword(value)) {
if (isMeasureKeyword(value)) {
try {
m = new MeasureImpl(Measure.Type.valueOfShorthand(value), (Length) null);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(e.getMessage());
}
} else
return false;
} else {
Object[] treatmentsInner = new Object[] {NegativeTreatment.Error, findTreatment(treatments, MixedUnitsTreatment.class)};
Length[] length = new Length[1];
if (Lengths.isLength(value, location, context, treatmentsInner, length))
m = new MeasureImpl(Measure.Type.Length, length[0]);
}
if (m != null) {
if (outputMeasure != null)
outputMeasure[0] = m;
return true;
} else
return false;
}
public static void badMeasure(String value, Location location, VerifierContext context, Object[] treatments) {
if (maybeMeasureKeyword(value)) {
Reporter reporter = (context != null) ? context.getReporter() : null;
if (reporter != null) {
reporter.logInfo(reporter.message(location.getLocator(), "*KEY*",
"Unknown keyword ''{0}'' used in <measure> expression.", value));
}
} else {
Object[] treatmentsInner = new Object[] {NegativeTreatment.Error, findTreatment(treatments, MixedUnitsTreatment.class)};
Length[] length = new Length[1];
if (!Lengths.isLength(value, location, context, treatmentsInner, length))
Lengths.badLength(value, location, context, treatmentsInner);
}
}
private static boolean maybeMeasureKeyword(String s) {
return (s != null) && !s.isEmpty() && Character.isLetter(s.charAt(0));
}
private static boolean isMeasureKeyword(String s) {
if (s.equals("auto"))
return true;
else if (s.equals("available"))
return true;
else if (s.equals("fitContent"))
return true;
else if (s.equals("maxContent"))
return true;
else if (s.equals("minContent"))
return true;
else
return false;
}
private static Object findTreatment(Object[] treatments, Class<?> treatmentClass) {
if ((treatments != null) && (treatments.length > 0)) {
for (Object t : treatments) {
if (treatmentClass.isInstance(t))
return t;
}
}
return null;
}
public static boolean isMeasures(String value, Location location, VerifierContext context, Integer[] minMax, Object[] treatments, List<Measure> outputMeasures) {
Reporter reporter = (context != null) ? context.getReporter() : null;
Locator locator = location.getLocator();
List<Measure> measures = new java.util.ArrayList<Measure>();
String [] measureComponents = value.split("[ \t\r\n]+");
int numComponents = measureComponents.length;
for (String component : measureComponents) {
Measure[] measure = new Measure[1];
if (isMeasure(component, location, context, treatments, measure))
measures.add(measure[0]);
else
return false;
}
if (minMax != null) {
if (numComponents < minMax[0])
return false;
else if (numComponents > minMax[1])
return false;
}
if (treatments != null) {
List<Length> lengths = new java.util.ArrayList<Length>();
for (Measure m : measures) {
if (m.isLength())
lengths.add(m);
}
if (!Units.sameUnits(lengths)) {
assert treatments.length > 1;
MixedUnitsTreatment mixedUnitsTreatment = (MixedUnitsTreatment) treatments[1];
Set<Length.Unit> units = Units.units(lengths);
if (mixedUnitsTreatment == MixedUnitsTreatment.Error)
return false;
else if (reporter != null) {
if (mixedUnitsTreatment == MixedUnitsTreatment.Warning) {
if (reporter.logWarning(reporter.message(locator, "*KEY*",
"Mixed units {0} should not be used in <measure> expressions.", Length.Unit.shorthands(units)))) {
treatments[1] = MixedUnitsTreatment.Allow; // suppress second warning
return false;
}
} else if (mixedUnitsTreatment == MixedUnitsTreatment.Info) {
reporter.logInfo(reporter.message(locator, "*KEY*",
"Mixed units {0} used in <measure> expressions.", Length.Unit.shorthands(units)));
}
}
}
}
if (outputMeasures != null) {
outputMeasures.clear();
outputMeasures.addAll(measures);
}
return true;
}
public static void badMeasures(String value, Location location, VerifierContext context, Integer[] minMax, Object[] treatments) {
Reporter reporter = context.getReporter();
Locator locator = location.getLocator();
String [] measureComponents = value.split("[ \t\r\n]+");
int numComponents = measureComponents.length;
Object[] treatmentsInner = (treatments != null) ? new Object[] { treatments[0], treatments[1] } : null;
List<Length> lengths = new java.util.ArrayList<Length>();
for (String component : measureComponents) {
Measure[] measure = new Measure[1];
if (isMeasure(component, location, context, treatmentsInner, measure)) {
Measure m = measure[0];
if (m.isLength())
lengths.add(m);
} else
badMeasure(component, location, context, treatmentsInner);
}
if (numComponents < minMax[0]) {
reporter.logInfo(reporter.message(locator, "*KEY*",
"Missing <measure> expression, got {0}, but expected at least {1} <measure> expressions.", numComponents, minMax[0]));
} else if (numComponents > minMax[1]) {
reporter.logInfo(reporter.message(locator, "*KEY*",
"Extra <measure> expression, got {0}, but expected no more than {1} <measure> expressions.", numComponents, minMax[1]));
}
if (treatments != null) {
MixedUnitsTreatment mixedUnitsTreatment = (MixedUnitsTreatment) treatments[1];
if (!Units.sameUnits(lengths) && (mixedUnitsTreatment == MixedUnitsTreatment.Error)) {
reporter.logInfo(reporter.message(locator, "*KEY*", "Mixed units {0} not permitted.", Length.Unit.shorthands(Units.units(lengths))));
}
}
}
}