/
ProductNutriments.kt
156 lines (128 loc) 路 5.2 KB
/
ProductNutriments.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package openfoodfacts.github.scrachx.openfood.models
import com.fasterxml.jackson.annotation.JsonAnyGetter
import com.fasterxml.jackson.annotation.JsonAnySetter
import com.fasterxml.jackson.annotation.JsonInclude
import openfoodfacts.github.scrachx.openfood.models.MeasurementUnit.UNIT_GRAM
import openfoodfacts.github.scrachx.openfood.network.ApiFields.Suffix
import openfoodfacts.github.scrachx.openfood.utils.*
import java.io.Serializable
import java.util.*
/**
* JSON representation of the product nutriments entry
*
* @see [JSON Structure](http://en.wiki.openfoodfacts.org/API.JSON_interface)
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
class ProductNutriments : Serializable {
companion object {
private const val serialVersionUID = 1L
}
@get:JsonAnyGetter
val additionalProperties = HashMap<String, Any?>()
fun getEnergyKcalValue(perServing: Boolean) =
if (perServing) getValuePerServing(Nutriment.ENERGY_KCAL)
else getValuePer100g(Nutriment.ENERGY_KCAL)
fun getEnergyKjValue(isDataPerServing: Boolean) =
if (isDataPerServing) getValuePerServing(Nutriment.ENERGY_KJ)
else getValuePer100g(Nutriment.ENERGY_KJ)
@JsonAnySetter
fun setAdditionalProperty(name: String, value: Any?) {
additionalProperties[name] = value
if (VITAMINS_MAP.any { it.key.key == name }) {
hasVitamins = true
} else if (MINERALS_MAP.any { it.key.key == name }) {
hasMinerals = true
}
}
operator fun get(nutriment: Nutriment): ProductNutriment? {
val name = getName(nutriment)
return if (name == null) null
else ProductNutriment(
nutriment,
name,
getValuePer100g(nutriment)!!,
getValuePerServing(nutriment),
getUnit(nutriment),
getModifier(nutriment)
)
}
private fun getName(nutriment: Nutriment) = getAdditionalProperty(nutriment)
private fun getValuePerServing(nutriment: Nutriment) =
getAdditionalProperty(nutriment, Suffix.SERVING)
?.takeIf { it.isNotEmpty() }
?.toFloat()
?.let { measure(it, UNIT_GRAM) }
/**
* @return null if the product is missing a value for the specified nutriment.
*/
private fun getValuePer100g(nutriment: Nutriment) =
getAdditionalProperty(nutriment, Suffix.VALUE_100G)
?.toFloat()
?.let { measure(it, UNIT_GRAM) }
private fun getUnit(nutriment: Nutriment) = getAdditionalProperty(nutriment, Suffix.UNIT)
?.let { MeasurementUnit.findBySymbol(it) } ?: DEFAULT_UNIT
private fun getModifier(nutriment: Nutriment) = getAdditionalProperty(nutriment, Suffix.MODIFIER)
?.let { Modifier.findBySymbol(it) } ?: DEFAULT_MODIFIER
private fun getAdditionalProperty(nutrient: Nutriment, suffix: String = "") =
additionalProperties[nutrient.key + suffix]?.toString()
operator fun contains(nutrimentName: String) = additionalProperties.containsKey(nutrimentName)
operator fun contains(nutriment: Nutriment) = additionalProperties.containsKey(nutriment.key)
var hasMinerals = false
private set
var hasVitamins = false
private set
/**
* @param perServingInG can be null if the product serving size is not specified
*/
class ProductNutriment internal constructor(
val nutriment: Nutriment,
val name: String,
val per100gInG: Measurement,
val perServingInG: Measurement?,
unit: MeasurementUnit,
val modifier: Modifier
) {
val unit = unit.getRealUnit()
fun isEnergy() = unit in ENERGY_UNITS
fun getPer100gDisplayString() = buildString {
modifier.ifNotDefault {
append(it.sym)
append(" ")
}
append(per100gInUnit.displayString())
}
/**
* Returns the amount of nutriment per 100g
* of product in the units stored in [ProductNutriment.unit]
*/
val per100gInUnit: Measurement
get() {
return if (isEnergy()) per100gInG
else per100gInG.convertTo(unit)
}
/**
* Returns the amount of nutriment per serving
* of product in the units stored in [ProductNutriment.unit].
*
* Can be null if [perServingInG] is null.
*/
val perServingInUnit: Measurement?
get() {
return if (isEnergy()) perServingInG
else perServingInG?.convertTo(unit)
}
/**
* Calculates the nutriment value for a given amount of this product. For example,
* calling getForAnyValue(1, "kg") will give you the amount of this nutriment
* given 1 kg of the product.
*
* @param portion amount of this product used to calculate nutriment value
* @param portionUnit units in either "g", "kg", or "mg" to define userSetServing
* @return nutriment value for a given amount of this product
*/
fun getForPortion(portion: Measurement) = Measurement(
value = per100gInUnit.value / 100 * portion.grams.value,
unit = per100gInUnit.unit
)
}
}