package org.molgenis.data.mapper.algorithmgenerator.categorymapper; import org.jscience.physics.amount.Amount; import org.molgenis.data.mapper.algorithmgenerator.bean.AmountWrapper; import org.molgenis.data.mapper.algorithmgenerator.bean.Category; import org.molgenis.data.mapper.algorithmgenerator.rules.CategoryMatchQuality; import org.molgenis.data.mapper.algorithmgenerator.rules.CategoryRule; import javax.measure.unit.NonSI; import javax.measure.unit.Unit; import java.util.List; public class FrequencyCategoryMapper extends CategoryMapper { private static final Unit<?> STANDARD_UNIT = NonSI.WEEK.inverse(); private static final double STANDARD_ERROR = 1; public FrequencyCategoryMapper(List<CategoryRule> rules) { super(rules); } public Category findBestCategoryMatch(Category sourceCategory, List<Category> targetCategories) { Category bestTargetCategory = null; double smallestFactor = -1; for (Category targetCategory : targetCategories) { Double convertFactor = convert(sourceCategory.getAmountWrapper(), targetCategory.getAmountWrapper()); if (convertFactor == null) continue; if (smallestFactor == -1) { smallestFactor = convertFactor; bestTargetCategory = targetCategory; } else if (smallestFactor > convertFactor) { smallestFactor = convertFactor; bestTargetCategory = targetCategory; } } return bestTargetCategory; } public CategoryMatchQuality<?> applyCustomRules(Category sourceCategory, Category targetCategory) { throw new UnsupportedOperationException(); } Double convert(AmountWrapper sourceAmountWrapper, AmountWrapper targetAmountWrapper) { if (sourceAmountWrapper != null && targetAmountWrapper != null) { Amount<?> sourceAmount = sourceAmountWrapper.getAmount().to(STANDARD_UNIT); Amount<?> targetAmount = targetAmountWrapper.getAmount().to(STANDARD_UNIT); if (unitsCompatible(sourceAmount, targetAmount)) { if (!sourceAmountWrapper.isDetermined() && !targetAmountWrapper.isDetermined()) { if (sourceAmountWrapper.getAmount().getUnit().equals(targetAmountWrapper.getAmount().getUnit())) { return (double) 0; } } if (!sourceAmountWrapper.isDetermined()) { sourceAmount = determineAmount(sourceAmount, targetAmount); } if (!targetAmountWrapper.isDetermined()) { targetAmount = determineAmount(targetAmount, sourceAmount); } return convertFactor(sourceAmount, targetAmount); } } return null; } Amount<?> determineAmount(Amount<?> amountToDetermine, Amount<?> determinedAmount) { Amount<?> convertedAmount = amountToDetermine.to(determinedAmount.getUnit()); double maxValue = convertedAmount.getMaximumValue(); double minValue = convertedAmount.getMinimumValue(); double determinedMaxValue = determinedAmount.getMaximumValue(); double determinedMinValue = determinedAmount.getMinimumValue(); if (determinedMaxValue > minValue && maxValue > determinedMaxValue) { maxValue = determinedMaxValue + STANDARD_ERROR; } if (determinedMinValue > minValue && determinedMinValue < maxValue) { minValue = determinedMinValue - STANDARD_ERROR; } return Amount.rangeOf(minValue, maxValue, convertedAmount.getUnit()); } boolean unitsCompatible(Amount<?> sourceAmount, Amount<?> targetAmount) { return sourceAmount.getUnit().isCompatible(STANDARD_UNIT) && targetAmount.getUnit().isCompatible(STANDARD_UNIT) && sourceAmount.getUnit().isCompatible(targetAmount.getUnit()); } Double convertFactor(Amount<?> convertedSourceAmount, Amount<?> targetAmount) { double lowerBoundDiff = Math.abs(targetAmount.getMinimumValue() - convertedSourceAmount.getMinimumValue()); double upperBoundDiff = Math.abs(targetAmount.getMaximumValue() - convertedSourceAmount.getMaximumValue()); return (upperBoundDiff + lowerBoundDiff) / 2; } boolean isMaxValueUndetermined(Amount<?> amount1) { return CategoryMapperUtil.isAmountRanged(amount1) && amount1.getMaximumValue() == Double.MAX_VALUE; } }