{-|
Module      : Network.MQTT.Topic.
Description : MQTT Topic types and utilities.
Copyright   : (c) Dustin Sallings, 2019
License     : BSD3
Maintainer  : dustin@spy.net
Stability   : experimental

Topic and topic related utiilities.
-}

{-# LANGUAGE OverloadedStrings #-}

module Network.MQTT.Topic (
  Filter, Topic, match
) where

import           Data.Text (Text, isPrefixOf, splitOn)

-- | An MQTT topic.
type Topic = Text

-- | An MQTT topic filter.
type Filter = Text

-- | match returns true iff the given pattern can be matched by the
-- specified Topic as defined in the
-- <http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718107 MQTT 3.1.1 specification>.
match :: Filter -> Topic -> Bool
match :: Filter -> Filter -> Bool
match Filter
pat Filter
top = [Filter] -> [Filter] -> Bool
cmp (Filter -> Filter -> [Filter]
splitOn Filter
"/" Filter
pat) (Filter -> Filter -> [Filter]
splitOn Filter
"/" Filter
top)

  where
    cmp :: [Filter] -> [Filter] -> Bool
cmp [] []   = Bool
True
    cmp [] [Filter]
_    = Bool
False
    cmp [Filter]
_ []    = Bool
False
    cmp [Filter
"#"] (Filter
t:[Filter]
_) = Bool -> Bool
not (Bool -> Bool) -> Bool -> Bool
forall a b. (a -> b) -> a -> b
$ Filter
"$" Filter -> Filter -> Bool
`isPrefixOf` Filter
t
    cmp (Filter
p:[Filter]
ps) (Filter
t:[Filter]
ts)
      | Filter
p Filter -> Filter -> Bool
forall a. Eq a => a -> a -> Bool
== Filter
t = [Filter] -> [Filter] -> Bool
cmp [Filter]
ps [Filter]
ts
      | Filter
p Filter -> Filter -> Bool
forall a. Eq a => a -> a -> Bool
== Filter
"+" Bool -> Bool -> Bool
&& Bool -> Bool
not (Filter
"$" Filter -> Filter -> Bool
`isPrefixOf` Filter
t) = [Filter] -> [Filter] -> Bool
cmp [Filter]
ps [Filter]
ts
      | Bool
otherwise = Bool
False