packages feed

lifx-lan-0.7: src/Lifx/Internal/ProductInfoMap.hs

module Lifx.Internal.ProductInfoMap where

import Control.Applicative
import Data.Functor
import Data.Maybe
import Data.Tuple.Extra
import Data.Word

import Data.Map (Map, (!?))
import Data.Map.Strict qualified as Map
import Data.Text (Text)
import GHC.Generics (Generic)

import Lifx.Internal.Product
import Lifx.Internal.ProductInfo

productInfoMap :: Map Word32 (Features, Map Word32 ProductInfo)
productInfoMap =
    Map.fromList $
        productInfo <&> \VendorInfo{..} ->
            ( vid
            ,
              ( defaults
              , Map.fromList $ ((.pid) &&& id) <$> products
              )
            )

-- | Information about a particular LIFX product.
data Product = Product
    { name :: Text
    , id :: Word32
    , features :: Features
    }
    deriving (Eq, Ord, Show, Generic)

data ProductLookupError
    = UnknownVendorId Word32
    | UnknownProductId Word32
    deriving (Eq, Ord, Show, Generic)

productLookup :: Word32 -> Word32 -> Word16 -> Word16 -> Either ProductLookupError Product
productLookup vendor prod versionMinor versionMajor =
    case productInfoMap !? vendor of
        Nothing -> Left $ UnknownVendorId vendor
        Just (defaults, products) -> case products !? prod of
            Nothing -> Left $ UnknownProductId prod
            Just ProductInfo{features = originalFeatures, ..} ->
                pure
                    Product
                        { name
                        , id = prod
                        , features =
                            completeFeatures defaults $
                                foldl
                                    ( \old Upgrade{..} ->
                                        if (versionMajor, versionMinor) >= (major, minor)
                                            then addFeatures features old
                                            else old
                                    )
                                    originalFeatures
                                    upgrades
                        }
  where
    completeFeatures f pf =
        Features
            { hev = fromMaybe f.hev pf.hev
            , color = fromMaybe f.color pf.color
            , chain = fromMaybe f.chain pf.chain
            , matrix = fromMaybe f.matrix pf.matrix
            , relays = fromMaybe f.relays pf.relays
            , buttons = fromMaybe f.buttons pf.buttons
            , infrared = fromMaybe f.infrared pf.infrared
            , multizone = fromMaybe f.multizone pf.multizone
            , temperatureRange = pf.temperatureRange <|> f.temperatureRange
            , extendedMultizone = fromMaybe f.extendedMultizone pf.extendedMultizone
            }
    -- left-biased
    addFeatures new old =
        PartialFeatures
            { hev = new.hev <|> old.hev
            , color = new.color <|> old.color
            , chain = new.chain <|> old.chain
            , matrix = new.matrix <|> old.matrix
            , relays = new.relays <|> old.relays
            , buttons = new.buttons <|> old.buttons
            , infrared = new.infrared <|> old.infrared
            , multizone = new.multizone <|> old.multizone
            , temperatureRange = new.temperatureRange <|> old.temperatureRange
            , extendedMultizone = new.extendedMultizone <|> old.extendedMultizone
            }