packages feed

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

module Lifx.Internal.ProductInfoMap where

import Control.Applicative
import Data.Either.Extra
import Data.Foldable hiding (product)
import Data.Function
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

--TODO RecordDotSyntax can make this and other hiding unnecessary (we could also use "id" instead of "productId"...)
import Prelude hiding (product)

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
    , productId :: 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 product versionMinor versionMajor =
    case productInfoMap !? vendor of
        Nothing -> Left $ UnknownVendorId vendor
        Just (defaults, products) -> case products !? product of
            Nothing -> Left $ UnknownProductId product
            Just ProductInfo{features = originalFeatures, ..} ->
                pure
                    Product
                        { name
                        , productId = product
                        , features =
                            completeFeatures defaults $
                                foldl
                                    ( \old Upgrade{..} ->
                                        if (versionMajor, versionMinor) >= (major, minor)
                                            then addFeatures features old
                                            else old
                                    )
                                    originalFeatures
                                    upgrades
                        }
  where
    --TODO RecordDotSyntax
    completeFeatures
        Features
            { ..
            }
        PartialFeatures
            { hev = maybe_hev
            , color = maybe_color
            , chain = maybe_chain
            , matrix = maybe_matrix
            , relays = maybe_relays
            , buttons = maybe_buttons
            , infrared = maybe_infrared
            , multizone = maybe_multizone
            , temperatureRange = maybe_temperatureRange
            , extendedMultizone = maybe_extendedMultizone
            } =
            Features
                { hev = fromMaybe hev maybe_hev
                , color = fromMaybe color maybe_color
                , chain = fromMaybe chain maybe_chain
                , matrix = fromMaybe matrix maybe_matrix
                , relays = fromMaybe relays maybe_relays
                , buttons = fromMaybe buttons maybe_buttons
                , infrared = fromMaybe infrared maybe_infrared
                , multizone = fromMaybe multizone maybe_multizone
                , temperatureRange = maybe_temperatureRange <|> temperatureRange
                , extendedMultizone = fromMaybe extendedMultizone maybe_extendedMultizone
                }
    -- left-biased
    addFeatures
        PartialFeatures
            { ..
            }
        PartialFeatures
            { hev = old_hev
            , color = old_color
            , chain = old_chain
            , matrix = old_matrix
            , relays = old_relays
            , buttons = old_buttons
            , infrared = old_infrared
            , multizone = old_multizone
            , temperatureRange = old_temperatureRange
            , extendedMultizone = old_extendedMultizone
            } =
            PartialFeatures
                { hev = hev <|> old_hev
                , color = color <|> old_color
                , chain = chain <|> old_chain
                , matrix = matrix <|> old_matrix
                , relays = relays <|> old_relays
                , buttons = buttons <|> old_buttons
                , infrared = infrared <|> old_infrared
                , multizone = multizone <|> old_multizone
                , temperatureRange = temperatureRange <|> old_temperatureRange
                , extendedMultizone = extendedMultizone <|> old_extendedMultizone
                }