Skip to content

Commit

Permalink
(#21): Pathway Views - implementing Food Quant. Meth.
Browse files Browse the repository at this point in the history
  • Loading branch information
andi-huber committed Mar 8, 2024
1 parent c4966e8 commit da10871
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package dita.globodiet.manager.editing.food;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import jakarta.inject.Inject;

Expand All @@ -32,7 +34,7 @@
import dita.commons.services.lookup.ForeignKeyLookupService;
import dita.globodiet.dom.params.food_list.Food;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFoodGroup;
import dita.globodiet.manager.services.food.FoodFacetHelperService;
import dita.globodiet.manager.services.food.FoodQuantificationHelperService;

/**
* With {@link QuantificationMethodPathwayForFoodGroup} a set of quantification methods is defined
Expand All @@ -43,24 +45,39 @@
@CollectionLayout(
hidden = Where.ALL_TABLES,
sequence = "0.2",
describedAs = "Quantification Methods in effect associated with this individual food.\n\n"
describedAs = "Quantification Method Pathways in effect associated with this individual food.\n\n"
+ "With QuantificationMethodForFoodGroup (table QM_GROUP) a set of methods is defined "
+ "for a specific food classification.\n\n"
+ "Optionally, for an individual food, only a subset of those facets can be selected "
+ "Optionally, for an individual food, only a subset of those methods can be selected "
+ "using QuantificationMethodPathwayForFood (table QM_FOODS).")
@RequiredArgsConstructor
public class Food_effectiveQuantificationMethods {
public class Food_effectiveQuantificationMethodPathways {

@Inject private ForeignKeyLookupService foreignKeyLookupService;
@Inject private FoodFacetHelperService foodFacetHelperService;
@Inject private FoodQuantificationHelperService foodQuantificationHelperService;

protected final Food mixee;

@MemberSupport
public List<QuantificationMethodPathwayForFoodGroup> coll() {
//TODO flesh out
return List.of();
}

var grouping = foodQuantificationHelperService.effectiveGroupingUsedForQuantificationPathway(mixee);

var quantificationMethodPathwayAsDefinedByFoodClassification = foodQuantificationHelperService
.effectiveQuantificationMethodPathwayForFoodClassification(grouping);

// filter by selected at food level (Dependent Quantification Method Pathway For Food mapped by Food)
var quantificationMethodPathwayForFood = foodQuantificationHelperService.listQuantificationMethodPathwayForFood(mixee);
if(quantificationMethodPathwayForFood.isEmpty()) {
return quantificationMethodPathwayAsDefinedByFoodClassification;
}
final Set<QuantificationMethodPathwayKey> selectedKeys = quantificationMethodPathwayForFood.stream()
.map(QuantificationMethodPathwayKey::valueOf)
.collect(Collectors.toSet());
return quantificationMethodPathwayAsDefinedByFoodClassification.stream()
.filter(qmp->selectedKeys.contains(QuantificationMethodPathwayKey.valueOf(qmp)))
//TODO ordering?
.toList();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,38 @@
package dita.globodiet.manager.editing.food;

import java.util.HashSet;
import java.util.Objects;

import jakarta.inject.Inject;

import org.springframework.lang.Nullable;

import org.apache.causeway.applib.annotation.Action;
import org.apache.causeway.applib.annotation.ActionLayout;
import org.apache.causeway.applib.annotation.ActionLayout.Position;
import org.apache.causeway.applib.annotation.LabelPosition;
import org.apache.causeway.applib.annotation.MemberSupport;
import org.apache.causeway.applib.annotation.ObjectSupport;
import org.apache.causeway.applib.annotation.Optionality;
import org.apache.causeway.applib.annotation.Parameter;
import org.apache.causeway.applib.annotation.ParameterLayout;
import org.apache.causeway.applib.annotation.PropertyLayout;
import org.apache.causeway.applib.services.factory.FactoryService;
import org.apache.causeway.commons.collections.Can;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.valuetypes.asciidoc.applib.value.AsciiDoc;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;

import dita.commons.services.lookup.ForeignKeyLookupService;
import dita.globodiet.dom.params.food_descript.FoodDescriptor;
import dita.globodiet.dom.params.food_descript.FoodFacet;
import dita.globodiet.dom.params.food_list.Food;
import dita.globodiet.dom.params.food_list.FoodGroup;
import dita.globodiet.dom.params.food_list.FoodSubgroup;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFoodGroup;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFoodGroup.RawOrCookedAsConsumed;
import dita.globodiet.manager.editing.recipe.Recipe_addStandardUnit;
import dita.globodiet.manager.util.AsciiDocUtils;
import dita.globodiet.manager.util.GroupingUtils;
Expand All @@ -60,14 +72,45 @@ public class Food_inspectPathway {
@Inject private FactoryService factoryService;
@Inject private ForeignKeyLookupService foreignKeyLookupService;

private final static String PHYSICAL_STATE_FACET_CODE = "02"; //TODO convert to configuration option

protected final Food mixee;

@MemberSupport
public PathwayView act() {
public PathwayView act(
@Parameter(optionality = Optionality.OPTIONAL)
@ParameterLayout(describedAs = "The quantification method pathway "
+ "is potentially bound to a chosen physical-state facet/descriptor.\n\n"
+ "Choices provided are those that are effective for the current food.")
final FoodDescriptor physicalState,
@Parameter
@ParameterLayout(describedAs = "The quantification method pathway "
+ "is potentially bound to whether the food was cooked or not.")
final RawOrCookedAsConsumed rawOrCookedAsConsumed
) {

var physicalState4DigitKey = physicalState!=null
? physicalState.secondaryKey().facetCode() + physicalState.secondaryKey().code()
: null;

var constraints = String.format("Constraints: physicalState=%s, consumed=%s",
physicalState!=null
? physicalState.getName()
: "none",
rawOrCookedAsConsumed);

return new PathwayView(
"Pathway View for Food - " + mixee.title(),
AsciiDocUtils.yamlBlock("Facet/Descriptor Pathway", "YAML format", facetDescriptorPathwayAsYaml()),
AsciiDocUtils.yamlBlock("Quantification Pathway", "YAML format", quantificationPathwayAsYaml()));
AsciiDocUtils.yamlBlock("Facet/Descriptor Pathway", "Constraints: none", facetDescriptorPathwayAsYaml()),
AsciiDocUtils.yamlBlock("Quantification Pathway", constraints, quantificationPathwayAsYaml(
physicalState4DigitKey,
rawOrCookedAsConsumed)));
}

@MemberSupport
private Can<FoodDescriptor> choicesPhysicalState() {
var effectiveFoodDescriptors = Can.ofCollection(factoryService.mixin(Food_effectiveFoodDescriptors.class, mixee).coll());
return effectiveFoodDescriptors.filter(fd->PHYSICAL_STATE_FACET_CODE.equals(fd.getFacetCode()));
}

public static record PathwayView(
Expand Down Expand Up @@ -107,7 +150,9 @@ private String facetDescriptorPathwayAsYaml() {
return yaml.toString();
}

private String quantificationPathwayAsYaml() {
private String quantificationPathwayAsYaml(
@Nullable final String physicalState4DigitKey,
final RawOrCookedAsConsumed rawOrCookedAsConsumed) {
var yaml = new StringBuilder();
yaml.append("Food: " + mixee.title()).append("\n");

Expand All @@ -121,10 +166,43 @@ private String quantificationPathwayAsYaml() {
.fold(FoodGroup::title, FoodSubgroup::title))
.append("\n");


var effectiveQuantificationMethodPathways = factoryService.mixin(Food_effectiveQuantificationMethodPathways.class, mixee).coll();
effectiveQuantificationMethodPathways.stream()
.filter(qmPathway->matches(rawOrCookedAsConsumed, qmPathway))
.filter(qmPathway->matches(physicalState4DigitKey, qmPathway))
.forEach(qmPathway->{
yaml.append(" -quantificationMethod: ").append(qmPathway.getQuantificationMethod()).append("\n");
yaml.append(" comment: ").append(qmPathway.getComment()).append("\n");
yaml.append(" physicalStateFacetDescriptor: ").append(qmPathway.getPhysicalStateFacetDescriptorLookupKey()).append("\n");
yaml.append(" rawOrCookedAsConsumed: ").append(qmPathway.getRawOrCookedAsConsumed()).append("\n");
var qmpKey = QuantificationMethodPathwayKey.valueOf(qmPathway);
if(qmpKey.quantificationMethod().isPhotoOrShape()) {
yaml.append(" photoOrShape: ").append(qmPathway.getPhotoOrShapeCode()).append("\n");
}
});

return yaml.toString();
}

private boolean matches(
final @NonNull RawOrCookedAsConsumed rawOrCookedAsConsumed,
final QuantificationMethodPathwayForFoodGroup qmPathway) {
var constraint = qmPathway.getRawOrCookedAsConsumed();
if(constraint==null) {
return true; // if no constraint is set, we always match
}
return Objects.equals(constraint, rawOrCookedAsConsumed);
}

private boolean matches(@Nullable final String physicalState4DigitKey, final QuantificationMethodPathwayForFoodGroup qmPathway) {
var physicalStateFacetDescriptorLookupKey = qmPathway.getPhysicalStateFacetDescriptorLookupKey();
if(_Strings.isEmpty(physicalStateFacetDescriptorLookupKey)) {
return true; // if no constraint is set, we always match
}
if(physicalState4DigitKey==null) {
return false; // can never satisfy non-empty constraint
}
return physicalStateFacetDescriptorLookupKey.contains(physicalState4DigitKey);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
package dita.globodiet.manager.editing.food;

import org.springframework.lang.Nullable;

import lombok.NonNull;

import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFood;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFoodGroup;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForRecipe;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForRecipeGroup;

public record QuantificationMethodPathwayKey(
@NonNull QuantificationMethod quantificationMethod,
@Nullable String photoOrShapeCode) {

public enum QuantificationMethod {
PHOTO,
HOUSEHOLD_MEASURE,
STANDARD_UNIT,
STANDARD_PORTION,
SHAPE;

public static QuantificationMethod valueOf(final QuantificationMethodPathwayForFoodGroup.QuantificationMethod qm) {
return QuantificationMethod.valueOf(qm.name());
}

public static QuantificationMethod valueOf(final QuantificationMethodPathwayForFood.QuantificationMethod qm) {
return QuantificationMethod.valueOf(qm.name());
}

public static QuantificationMethod valueOf(final QuantificationMethodPathwayForRecipeGroup.QuantificationMethod qm) {
return QuantificationMethod.valueOf(qm.name());
}

public static QuantificationMethod valueOf(final QuantificationMethodPathwayForRecipe.QuantificationMethod qm) {
return QuantificationMethod.valueOf(qm.name());
}

boolean isPhotoOrShape() {
return this == PHOTO
|| this == SHAPE;
}

}

public static QuantificationMethodPathwayKey valueOf(final QuantificationMethodPathwayForFood qmp) {
return new QuantificationMethodPathwayKey(
QuantificationMethod.valueOf(qmp.getQuantificationMethod()),
qmp.getPhotoOrShapeCode());
}

public static QuantificationMethodPathwayKey valueOf(final QuantificationMethodPathwayForFoodGroup qmp) {
return new QuantificationMethodPathwayKey(
QuantificationMethod.valueOf(qmp.getQuantificationMethod()),
qmp.getPhotoOrShapeCode());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@

import dita.globodiet.dom.params.classification.FoodGrouping;
import dita.globodiet.dom.params.food_list.Food;
import dita.globodiet.dom.params.food_list.FoodDeps.Food_dependentQuantificationMethodPathwayForFoodMappedByFood;
import dita.globodiet.dom.params.food_list.FoodGroup;
import dita.globodiet.dom.params.food_list.FoodGroupDeps.FoodGroup_dependentQuantificationMethodPathwayForFoodGroupMappedByFoodGroup;
import dita.globodiet.dom.params.food_list.FoodSubgroup;
import dita.globodiet.dom.params.food_list.FoodSubgroupDeps.FoodSubgroup_dependentQuantificationMethodPathwayForFoodGroupMappedByFoodSubSubgroup;
import dita.globodiet.dom.params.food_list.FoodSubgroupDeps.FoodSubgroup_dependentQuantificationMethodPathwayForFoodGroupMappedByFoodSubgroup;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFood;
import dita.globodiet.dom.params.pathway.QuantificationMethodPathwayForFoodGroup;
import dita.globodiet.manager.services.grouping.GroupingHelperService;
import dita.globodiet.manager.util.GroupingUtils;
Expand Down Expand Up @@ -101,6 +103,11 @@ public FoodGrouping effectiveGroupingUsedForQuantificationPathway(final Food foo
return foodGrouping;
}

public List<QuantificationMethodPathwayForFood> listQuantificationMethodPathwayForFood(final @NonNull Food food) {
var mixin = factoryService.mixin(Food_dependentQuantificationMethodPathwayForFoodMappedByFood.class, food);
return mixin.coll();
}

// -- HELPER

private List<QuantificationMethodPathwayForFoodGroup> listQuantificationMethodPathwayForFoodGroup(
Expand Down

0 comments on commit da10871

Please sign in to comment.