module Data.Nutrition.Macros
(
Macros ()
, newMacros

, prot
, carb
, fat

)
where

import Control.Category

type Percent = Float

type Protein = Percent
type Carb    = Percent
type Fat     = Percent

-- | The macro nutrients are @Protein@, @Carbohydrate@ and @Fat@. They
-- are stored within a triple that is called 'Macros'.
data Macros = Macros (Protein, Carb, Fat)

-- | 'prot', 'carb' and 'fat' are functions that return the percent of
-- that macro nutrient. They are basically getters of the 'Macros'
-- data.
prot, fat, carb :: Macros -> Percent
prot (Macros (p, _, _)) = p
carb (Macros (_, c, _)) = c
fat  (Macros (_, _, f)) = f

-- | 'newMacros' is a smart constructor to 'Macros'. It checks,
-- whether the sum of the percentages is equal or below
-- 100%. Otherwise it does not construct a 'Macros' value.
newMacros :: (Protein, Carb, Fat) -> Macros
newMacros (p, c, f)
| (p + c + f) <= 100 = Macros (p, c, f)
| otherwise         = error \$ "macro definition exeeds 100%"

-- instance Num Macros where
--     m1 + m2 = newMacros \$ percentualDo (+) (prot m1, carb m1, fat m1) (prot m2, carb m2, fat m2)
--     m1 - m2 = newMacros \$ percentualDo (-) (prot m1, carb m1, fat m1) (prot m2, carb m2, fat m2)
--     (*) = error "this operation isn't defined on macros"

-- percentualDo op (p1, c1, f1) (p2, c2, f2)
--     = (p, c, f)
--     where sum1 = p1 + c1 + f1
--           sum2 = p2 + c2 + f2
--           percentCalc op sum1 sum2 v1 v2
--               = (v1 * 100.0 / sum1) `op` (v2 * 100.0 / sum2) / 2
--           p = percentCalc op sum1 sum2 p1 p2
--           c = percentCalc op sum1 sum2 c1 c2
--           f = percentCalc op sum1 sum2 f1 f2