//----------------------------------------------------------------------------//
// //
// C h e c k //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.check;
import omr.constant.Constant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Class {@code Check} encapsulates the <b>definition</b> of a check,
* which can later be used on a whole population of objects.
*
* <p>The result of using a check on a given object is not recorded in this
* class, but into the checked entity itself. </p>
*
* <p>Checks can be gathered in check suites. </p>
*
* @param <C> precise type of the objects to be checked
*
* @author Hervé Bitteur
*/
public abstract class Check<C extends Checkable>
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(Check.class);
/**
* Indicates a negative result
*/
public static final int RED = -1;
/**
* Indicates a non-concluding result
*/
public static final int ORANGE = 0;
/**
* Indicates a positive result
*/
public static final int GREEN = 1;
//~ Instance fields --------------------------------------------------------
/**
* Specifies the FailureResult to be assigned to the Checkable object, if
* the result of the check end in the RED range.
*/
private final FailureResult redResult;
/** Longer description, meant for tips */
private final String description;
/** Short name for this test */
private final String name;
/**
* Specifies if values are RED,ORANGE,GREEN (higher is better, covariant =
* true) or GREEN,ORANGE,RED (lower is better, covariant = false)
*/
private final boolean covariant;
/**
* Lower bound for ORANGE range. Whatever the value of 'covariant', we must
* always have low <= high
*/
private Constant.Double low;
/**
* Higher bound for ORANGE range. Whatever the value of 'covariant', we must
* always have low <= high
*/
private Constant.Double high;
//~ Constructors -----------------------------------------------------------
//-------//
// Check //
//-------//
/**
* Creates a new Check object.
*
* @param name short name for this check
* @param description longer description
* @param low lower bound of orange zone
* @param high upper bound of orange zone
* @param covariant true if higher is better, false otherwise
* @param redResult result code to be assigned when result is RED
*/
protected Check (String name,
String description,
Constant.Double low,
Constant.Double high,
boolean covariant,
FailureResult redResult)
{
this.name = name;
this.description = description;
this.low = low;
this.high = high;
this.covariant = covariant;
this.redResult = redResult;
verifyRange();
}
//~ Methods ----------------------------------------------------------------
//----------------//
// getDescription //
//----------------//
/**
* Report the related description
*
* @return the description assigned to this check
*/
public String getDescription ()
{
return description;
}
//---------//
// getHigh //
//---------//
/**
* Report the higher bound value
*
* @return the high bound
*/
public double getHigh ()
{
return high.getValue();
}
//-----------------//
// getHighConstant //
//-----------------//
/**
* Report the higher bound constant
*
* @return the high bound constant
*/
public Constant.Double getHighConstant ()
{
return high;
}
//--------//
// getLow //
//--------//
/**
* Report the lower bound value
*
* @return the low bound
*/
public double getLow ()
{
return low.getValue();
}
//----------------//
// getLowConstant //
//----------------//
/**
* Report the lower bound constant
*
* @return the low bound constant
*/
public Constant.Double getLowConstant ()
{
return low;
}
//---------//
// getName //
//---------//
/**
* Report the related name
*
* @return the name assigned to this check
*/
public String getName ()
{
return name;
}
//-------------//
// isCovariant //
//-------------//
/**
* Report the covariant flag
*
* @return the value of covariant flag
*/
public boolean isCovariant ()
{
return covariant;
}
//------//
// pass //
//------//
/**
* Actually run the check on the provided object, and return the result. As
* a side-effect, a check that totally fails (RED result) assigns this
* failure into the candidate object.
*
* @param obj the checkable object to be checked
* @param result output for the result, or null
* @param update true if obj is to be updated with the result
*
* @return the result composed of the numerical value, plus a flag ({@link
* #RED}, {@link #ORANGE}, {@link #GREEN}) that characterizes the result of
* passing the check on this object
*/
public CheckResult pass (C obj,
CheckResult result,
boolean update)
{
if (result == null) {
result = new CheckResult();
}
result.value = getValue(obj);
if (covariant) {
if (result.value < low.getValue()) {
if (update) {
obj.setResult(redResult);
}
result.flag = RED;
} else if (result.value >= high.getValue()) {
result.flag = GREEN;
} else {
result.flag = ORANGE;
}
} else {
if (result.value <= low.getValue()) {
result.flag = GREEN;
} else if (result.value > high.getValue()) {
if (update) {
obj.setResult(redResult);
}
result.flag = RED;
} else {
result.flag = ORANGE;
}
}
return result;
}
//------------//
// setLowHigh //
//------------//
/**
* Allows to set the pair of low and high value. They are set in one shot to
* allow the sanity check of 'low' less than or equal to 'high'
*
* @param low the new low value
* @param high the new high value
*/
public void setLowHigh (Constant.Double low,
Constant.Double high)
{
this.low = low;
this.high = high;
verifyRange();
}
//----------//
// toString //
//----------//
/**
* report a readable description of this check
*/
@Override
public String toString ()
{
StringBuilder sb = new StringBuilder(128);
sb.append("{Check ")
.append(name);
sb.append(" Covariant:")
.append(covariant);
sb.append(" Low:")
.append(low);
sb.append(" High:")
.append(high);
sb.append("}");
return sb.toString();
}
//----------//
// getValue //
//----------//
/**
* Method to be provided by any concrete subclass, in order to retrieve the
* proper data value from the given object passed as a parameter.
*
* @param obj the object to be checked
*
* @return the data value relevant for the check
*/
protected abstract double getValue (C obj);
//-------------//
// verifyRange //
//-------------//
private void verifyRange ()
{
if (low.getValue() > high.getValue()) {
logger.error(
"Illegal low {} high {} range for {}",
low.getValue(), high.getValue(), this);
}
}
//~ Inner Classes ----------------------------------------------------------
//-------//
// Grade //
//-------//
/**
* A subclass of Constant.Double, meant to store a check result grade.
*/
public static class Grade
extends Constant.Double
{
//~ Constructors -------------------------------------------------------
/**
* Specific constructor, where 'unit' and 'name' are assigned later
*
* @param defaultValue the (double) default value
* @param description the semantic of the constant
*/
public Grade (double defaultValue,
java.lang.String description)
{
super("Grade", defaultValue, description);
}
}
}