packages feed

herms-1.8.1.2: src/UnitConversions.hs

module UnitConversions where

import Data.List
import Data.Ratio
import Data.Char (toLower)
import Types 

data Conversion = Metric | Imperial | None deriving (Show, Read, Eq)


--- NOTE: Here, "imperial" means "U.S. Customary". 
--- Conversion to British, Australian, Canadian, etc. imperial units is not yet implemented

convertRecipeUnits :: Conversion -> Recipe -> Recipe
convertRecipeUnits unit recp =
    case unit of
        None        -> recp
        Metric      -> recp{ingredients = map convertIngredientToMetric (ingredients recp)}
        Imperial    -> recp{ingredients = map convertIngredientToImperial (ingredients recp)}


getSynonym :: String -> Maybe String
getSynonym units
  | u `elem` tspSyns  = Just "tsp"
  | u `elem` tbspSyns = Just "Tbsp"
  | u `elem` cupSyns  = Just "cups"
  | u `elem` ozSyns   = Just "oz"
  | u `elem` flOzSyns = Just "fl oz"
  | u `elem` lbsSyns  = Just "lbs"
  | u `elem` pintSyns = Just "pint"
  | u `elem` quartSyns= Just "quart"
  | u `elem` galSyns  = Just "gallon"
  | otherwise = Nothing
  where u = map toLower units
        tspSyns  = [ "tsp",
                     "tsp.",
                     "teaspoon",
                     "teaspoons" ]

        tbspSyns = [ "tbsp",
                     "tbsp.",
                     "tablespoon",
                     "tablespoons" ]

        cupSyns  = [ "cup",
                     "cups",
                     "cp",
                     "cps",
                     "cp." ,
                     "cps." ]

        ozSyns   = [ "oz",
                     "oz.",
                     "ounce",
                     "ounces" ]

        flOzSyns = [ "fl oz",
                     "fl. oz.",
                     "fl oz.",
                     "fl. oz",
                     "fluid ounce",
                     "fluid ounces",
                     "fluid oz",
                     "fluid oz.",
                     "fl ounce",
                     "fl ounces",
                     "fl. ounce",
                     "fl. ounces" ]

        lbsSyns =  [ "lb.",
                     "lbs.",
                     "lb",
                     "lbs",
                     "pound",
                     "pounds" ]

        pintSyns = [ "pt",
                     "pt.",
                     "pts",
                     "pts.",
                     "pint",
                     "pints" ]

        quartSyns = ["qt",
                     "qt.",
                     "qts",
                     "qts.",
                     "quart",
                     "quarts" ]

        galSyns  = [ "gal",
                     "gal.",
                     "gals",
                     "gals.",
                     "gallon",
                     "gallons" ]


convertIngredientToMetric :: Ingredient -> Ingredient
convertIngredientToMetric ingr =
    case getSynonym units of
        Just "tsp"   -> ingr{quantity = qty * 5, unit = "mL"}
        Just "Tbsp"  -> ingr{quantity = qty * 15, unit = "mL"}
        Just "fl oz" -> ingr{quantity = qty * 30, unit = "mL"}
        Just "cups"  -> ingr{quantity = qty * 237, unit = "mL"}
        Just "oz"    -> ingr{quantity = qty * 28, unit = "g"}
        Just "lbs"   -> ingr{quantity = qty * 454, unit = "g"}
        Just "pint"  -> ingr{quantity = qty * 473, unit = "mL"}
        Just "quart" -> ingr{quantity = qty * 946, unit = "mL"}
        Just "gallon"-> ingr{quantity = qty * 3.785, unit = "L"}
        Nothing      -> ingr
    where
        units = unit ingr
        qty = quantity ingr

convertIngredientToImperial :: Ingredient -> Ingredient
convertIngredientToImperial ingr =
    case un of
        "mL" | qty < 15  -> ingr{quantity = qty / 5, unit = "tsp"}
             | qty < 250 -> ingr{quantity = qty / 15, unit = "Tbsp"}
             | otherwise ->  ingr{quantity = qty / 250, unit = "cup(s)"}

        "g"    -> ingr{quantity = qty / 28, unit = "oz"}
        _      -> ingr
    where
        un = unit ingr
        qty = quantity ingr