module Penny.Lincoln.Bits.Price (
  From ( From, unFrom ),
  To ( To, unTo ),
  CountPerUnit ( CountPerUnit, unCountPerUnit ),
  Price ( from, to, countPerUnit ),
  convert,
  newPrice) where

import qualified Penny.Lincoln.Bits.Open as O
import Penny.Lincoln.Bits.Qty (Qty, mult)

newtype From = From { unFrom :: O.Commodity }
               deriving (Eq, Ord, Show)

newtype To = To { unTo :: O.Commodity }
             deriving (Eq, Ord, Show)

newtype CountPerUnit = CountPerUnit { unCountPerUnit :: Qty }
                       deriving (Eq, Ord, Show)

data Price = Price { from :: From
                   , to :: To
                   , countPerUnit :: CountPerUnit }
             deriving (Eq, Ord, Show)

-- | Convert an amount from the From price to the To price. Fails if
-- the From commodity in the Price is not the same as the commodity in
-- the Amount.
convert :: Price -> O.Amount -> Maybe O.Amount
convert p (O.Amount q c sd sb) =
  if (unFrom . from $ p) /= c
  then Nothing
  else let q' = q `mult` (unCountPerUnit . countPerUnit $ p)
       in Just (O.Amount q' (unTo . to $ p) sd sb)

-- | Succeeds only if From and To are different commodities.
newPrice :: From -> To -> CountPerUnit -> Maybe Price
newPrice f t cpu =
  if unFrom f == unTo t
  then Nothing
  else Just $ Price f t cpu