{-# LANGUAGE OverloadedStrings, DeriveGeneric #-}
-- |
-- Module: NetSpider.RPL.Combined
-- Description: Snapshot graph combining DIO and DAO graphs
-- Maintainer: Toshio Ito <debug.ito@gmail.com>
--
-- This module defines functions and data models that combine DIO
-- (defined in "NetSpider.RPL.DIO") and DAO (defined in
-- "NetSpider.RPL.DAO") graphs.
module NetSpider.RPL.Combined
  ( -- * Functions
    combineGraphs,
    combineNodes,
    combineLinks,
    -- * Types
    SnapshotGraphCombined,
    CombinedNode(..),
    CombinedLink(..),
    combinedLinkType
  ) where

import Data.Aeson (FromJSON(..), ToJSON(..))
import qualified Data.Aeson as Aeson
import Data.Bifunctor (bimap, second)
import Data.List (sortOn, reverse)
import Data.Semigroup (Semigroup(..))
import Data.Maybe (isJust)
import Data.Monoid (Monoid(..), First(..))
import GHC.Exts (groupWith)
import GHC.Generics (Generic)
import qualified NetSpider.GraphML.Writer as GraphML
import NetSpider.Snapshot
  ( SnapshotNode, SnapshotLink, SnapshotGraph,
    nodeId, nodeAttributes, nodeTimestamp
  )

import NetSpider.RPL.FindingID (FindingID(..), FindingType(..), IPv6ID, ipv6Only)
import NetSpider.RPL.DIO (DIONode, MergedDIOLink, SnapshotGraphDIO)
import NetSpider.RPL.DAO (DAONode, DAOLink, SnapshotGraphDAO)
import NetSpider.RPL.JSONUtil (optCombinedNode, optCombinedLink)

-- | Node attributes combining 'DIONode' and 'DAONode'.
data CombinedNode =
  CombinedNode
  { CombinedNode -> Maybe DIONode
attrsDIO :: Maybe DIONode,
    CombinedNode -> Maybe DAONode
attrsDAO :: Maybe DAONode
  }
  deriving (Int -> CombinedNode -> ShowS
[CombinedNode] -> ShowS
CombinedNode -> String
(Int -> CombinedNode -> ShowS)
-> (CombinedNode -> String)
-> ([CombinedNode] -> ShowS)
-> Show CombinedNode
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CombinedNode] -> ShowS
$cshowList :: [CombinedNode] -> ShowS
show :: CombinedNode -> String
$cshow :: CombinedNode -> String
showsPrec :: Int -> CombinedNode -> ShowS
$cshowsPrec :: Int -> CombinedNode -> ShowS
Show,CombinedNode -> CombinedNode -> Bool
(CombinedNode -> CombinedNode -> Bool)
-> (CombinedNode -> CombinedNode -> Bool) -> Eq CombinedNode
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CombinedNode -> CombinedNode -> Bool
$c/= :: CombinedNode -> CombinedNode -> Bool
== :: CombinedNode -> CombinedNode -> Bool
$c== :: CombinedNode -> CombinedNode -> Bool
Eq,Eq CombinedNode
Eq CombinedNode
-> (CombinedNode -> CombinedNode -> Ordering)
-> (CombinedNode -> CombinedNode -> Bool)
-> (CombinedNode -> CombinedNode -> Bool)
-> (CombinedNode -> CombinedNode -> Bool)
-> (CombinedNode -> CombinedNode -> Bool)
-> (CombinedNode -> CombinedNode -> CombinedNode)
-> (CombinedNode -> CombinedNode -> CombinedNode)
-> Ord CombinedNode
CombinedNode -> CombinedNode -> Bool
CombinedNode -> CombinedNode -> Ordering
CombinedNode -> CombinedNode -> CombinedNode
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: CombinedNode -> CombinedNode -> CombinedNode
$cmin :: CombinedNode -> CombinedNode -> CombinedNode
max :: CombinedNode -> CombinedNode -> CombinedNode
$cmax :: CombinedNode -> CombinedNode -> CombinedNode
>= :: CombinedNode -> CombinedNode -> Bool
$c>= :: CombinedNode -> CombinedNode -> Bool
> :: CombinedNode -> CombinedNode -> Bool
$c> :: CombinedNode -> CombinedNode -> Bool
<= :: CombinedNode -> CombinedNode -> Bool
$c<= :: CombinedNode -> CombinedNode -> Bool
< :: CombinedNode -> CombinedNode -> Bool
$c< :: CombinedNode -> CombinedNode -> Bool
compare :: CombinedNode -> CombinedNode -> Ordering
$ccompare :: CombinedNode -> CombinedNode -> Ordering
$cp1Ord :: Eq CombinedNode
Ord,(forall x. CombinedNode -> Rep CombinedNode x)
-> (forall x. Rep CombinedNode x -> CombinedNode)
-> Generic CombinedNode
forall x. Rep CombinedNode x -> CombinedNode
forall x. CombinedNode -> Rep CombinedNode x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep CombinedNode x -> CombinedNode
$cfrom :: forall x. CombinedNode -> Rep CombinedNode x
Generic)

-- | Based on instance of 'First'.
instance Semigroup CombinedNode where
  CombinedNode
a <> :: CombinedNode -> CombinedNode -> CombinedNode
<> CombinedNode
b = Maybe DIONode -> Maybe DAONode -> CombinedNode
CombinedNode Maybe DIONode
dio Maybe DAONode
dao
    where
      dio :: Maybe DIONode
dio = First DIONode -> Maybe DIONode
forall a. First a -> Maybe a
getFirst (First DIONode -> Maybe DIONode) -> First DIONode -> Maybe DIONode
forall a b. (a -> b) -> a -> b
$ (Maybe DIONode -> First DIONode
forall a. Maybe a -> First a
First (Maybe DIONode -> First DIONode) -> Maybe DIONode -> First DIONode
forall a b. (a -> b) -> a -> b
$ CombinedNode -> Maybe DIONode
attrsDIO CombinedNode
a) First DIONode -> First DIONode -> First DIONode
forall a. Semigroup a => a -> a -> a
<> (Maybe DIONode -> First DIONode
forall a. Maybe a -> First a
First (Maybe DIONode -> First DIONode) -> Maybe DIONode -> First DIONode
forall a b. (a -> b) -> a -> b
$ CombinedNode -> Maybe DIONode
attrsDIO CombinedNode
b)
      dao :: Maybe DAONode
dao = First DAONode -> Maybe DAONode
forall a. First a -> Maybe a
getFirst (First DAONode -> Maybe DAONode) -> First DAONode -> Maybe DAONode
forall a b. (a -> b) -> a -> b
$ (Maybe DAONode -> First DAONode
forall a. Maybe a -> First a
First (Maybe DAONode -> First DAONode) -> Maybe DAONode -> First DAONode
forall a b. (a -> b) -> a -> b
$ CombinedNode -> Maybe DAONode
attrsDAO CombinedNode
a) First DAONode -> First DAONode -> First DAONode
forall a. Semigroup a => a -> a -> a
<> (Maybe DAONode -> First DAONode
forall a. Maybe a -> First a
First (Maybe DAONode -> First DAONode) -> Maybe DAONode -> First DAONode
forall a b. (a -> b) -> a -> b
$ CombinedNode -> Maybe DAONode
attrsDAO CombinedNode
b)

-- | Based on instance of 'First'.
instance Monoid CombinedNode where
  mappend :: CombinedNode -> CombinedNode -> CombinedNode
mappend CombinedNode
a CombinedNode
b = CombinedNode
a CombinedNode -> CombinedNode -> CombinedNode
forall a. Semigroup a => a -> a -> a
<> CombinedNode
b
  mempty :: CombinedNode
mempty = Maybe DIONode -> Maybe DAONode -> CombinedNode
CombinedNode Maybe DIONode
forall a. Maybe a
Nothing Maybe DAONode
forall a. Maybe a
Nothing

instance GraphML.ToAttributes CombinedNode where
  toAttributes :: CombinedNode -> [(AttributeKey, AttributeValue)]
toAttributes CombinedNode
cn = (Maybe DIONode -> [(AttributeKey, AttributeValue)]
forall a. ToAttributes a => a -> [(AttributeKey, AttributeValue)]
GraphML.toAttributes (Maybe DIONode -> [(AttributeKey, AttributeValue)])
-> Maybe DIONode -> [(AttributeKey, AttributeValue)]
forall a b. (a -> b) -> a -> b
$ CombinedNode -> Maybe DIONode
attrsDIO CombinedNode
cn)
                    [(AttributeKey, AttributeValue)]
-> [(AttributeKey, AttributeValue)]
-> [(AttributeKey, AttributeValue)]
forall a. [a] -> [a] -> [a]
++ (Maybe DAONode -> [(AttributeKey, AttributeValue)]
forall a. ToAttributes a => a -> [(AttributeKey, AttributeValue)]
GraphML.toAttributes (Maybe DAONode -> [(AttributeKey, AttributeValue)])
-> Maybe DAONode -> [(AttributeKey, AttributeValue)]
forall a b. (a -> b) -> a -> b
$ CombinedNode -> Maybe DAONode
attrsDAO CombinedNode
cn)

-- | @since 0.4.1.0
instance FromJSON CombinedNode where
  parseJSON :: Value -> Parser CombinedNode
parseJSON = Options -> Value -> Parser CombinedNode
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON Options
optCombinedNode

-- | @since 0.4.1.0
instance ToJSON CombinedNode where
  toJSON :: CombinedNode -> Value
toJSON = Options -> CombinedNode -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON Options
optCombinedNode
  toEncoding :: CombinedNode -> Encoding
toEncoding = Options -> CombinedNode -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
Aeson.genericToEncoding Options
optCombinedNode

-- | Link attribute combining 'MergedDIOLink' and 'DAOLink'.
data CombinedLink = CombinedDIOLink MergedDIOLink
                  | CombinedDAOLink DAOLink
                  deriving (Int -> CombinedLink -> ShowS
[CombinedLink] -> ShowS
CombinedLink -> String
(Int -> CombinedLink -> ShowS)
-> (CombinedLink -> String)
-> ([CombinedLink] -> ShowS)
-> Show CombinedLink
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [CombinedLink] -> ShowS
$cshowList :: [CombinedLink] -> ShowS
show :: CombinedLink -> String
$cshow :: CombinedLink -> String
showsPrec :: Int -> CombinedLink -> ShowS
$cshowsPrec :: Int -> CombinedLink -> ShowS
Show,CombinedLink -> CombinedLink -> Bool
(CombinedLink -> CombinedLink -> Bool)
-> (CombinedLink -> CombinedLink -> Bool) -> Eq CombinedLink
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CombinedLink -> CombinedLink -> Bool
$c/= :: CombinedLink -> CombinedLink -> Bool
== :: CombinedLink -> CombinedLink -> Bool
$c== :: CombinedLink -> CombinedLink -> Bool
Eq,Eq CombinedLink
Eq CombinedLink
-> (CombinedLink -> CombinedLink -> Ordering)
-> (CombinedLink -> CombinedLink -> Bool)
-> (CombinedLink -> CombinedLink -> Bool)
-> (CombinedLink -> CombinedLink -> Bool)
-> (CombinedLink -> CombinedLink -> Bool)
-> (CombinedLink -> CombinedLink -> CombinedLink)
-> (CombinedLink -> CombinedLink -> CombinedLink)
-> Ord CombinedLink
CombinedLink -> CombinedLink -> Bool
CombinedLink -> CombinedLink -> Ordering
CombinedLink -> CombinedLink -> CombinedLink
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: CombinedLink -> CombinedLink -> CombinedLink
$cmin :: CombinedLink -> CombinedLink -> CombinedLink
max :: CombinedLink -> CombinedLink -> CombinedLink
$cmax :: CombinedLink -> CombinedLink -> CombinedLink
>= :: CombinedLink -> CombinedLink -> Bool
$c>= :: CombinedLink -> CombinedLink -> Bool
> :: CombinedLink -> CombinedLink -> Bool
$c> :: CombinedLink -> CombinedLink -> Bool
<= :: CombinedLink -> CombinedLink -> Bool
$c<= :: CombinedLink -> CombinedLink -> Bool
< :: CombinedLink -> CombinedLink -> Bool
$c< :: CombinedLink -> CombinedLink -> Bool
compare :: CombinedLink -> CombinedLink -> Ordering
$ccompare :: CombinedLink -> CombinedLink -> Ordering
$cp1Ord :: Eq CombinedLink
Ord,(forall x. CombinedLink -> Rep CombinedLink x)
-> (forall x. Rep CombinedLink x -> CombinedLink)
-> Generic CombinedLink
forall x. Rep CombinedLink x -> CombinedLink
forall x. CombinedLink -> Rep CombinedLink x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep CombinedLink x -> CombinedLink
$cfrom :: forall x. CombinedLink -> Rep CombinedLink x
Generic)

instance GraphML.ToAttributes CombinedLink where
  toAttributes :: CombinedLink -> [(AttributeKey, AttributeValue)]
toAttributes (CombinedDIOLink MergedDIOLink
ll) =
    (AttributeKey
"link_type", AttributeKey -> AttributeValue
GraphML.AttrString AttributeKey
"dio") (AttributeKey, AttributeValue)
-> [(AttributeKey, AttributeValue)]
-> [(AttributeKey, AttributeValue)]
forall a. a -> [a] -> [a]
: MergedDIOLink -> [(AttributeKey, AttributeValue)]
forall a. ToAttributes a => a -> [(AttributeKey, AttributeValue)]
GraphML.toAttributes MergedDIOLink
ll
  toAttributes (CombinedDAOLink DAOLink
ll) =
    (AttributeKey
"link_type", AttributeKey -> AttributeValue
GraphML.AttrString AttributeKey
"dao") (AttributeKey, AttributeValue)
-> [(AttributeKey, AttributeValue)]
-> [(AttributeKey, AttributeValue)]
forall a. a -> [a] -> [a]
: DAOLink -> [(AttributeKey, AttributeValue)]
forall a. ToAttributes a => a -> [(AttributeKey, AttributeValue)]
GraphML.toAttributes DAOLink
ll

-- | @since 0.4.1.0
instance FromJSON CombinedLink where
  parseJSON :: Value -> Parser CombinedLink
parseJSON = Options -> Value -> Parser CombinedLink
forall a.
(Generic a, GFromJSON Zero (Rep a)) =>
Options -> Value -> Parser a
Aeson.genericParseJSON Options
optCombinedLink

-- | @since 0.4.1.0
instance ToJSON CombinedLink where
  toJSON :: CombinedLink -> Value
toJSON = Options -> CombinedLink -> Value
forall a.
(Generic a, GToJSON' Value Zero (Rep a)) =>
Options -> a -> Value
Aeson.genericToJSON Options
optCombinedLink
  toEncoding :: CombinedLink -> Encoding
toEncoding = Options -> CombinedLink -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
Aeson.genericToEncoding Options
optCombinedLink

combinedLinkType :: CombinedLink -> FindingType
combinedLinkType :: CombinedLink -> FindingType
combinedLinkType (CombinedDIOLink MergedDIOLink
_) = FindingType
FindingDIO
combinedLinkType (CombinedDAOLink DAOLink
_) = FindingType
FindingDAO

-- | Combine DIO and DAO 'SnapshotNode's. Attributes from 'DIONode'
-- and 'DAONode' for the same 'IPv6ID' are combined into one
-- 'CombinedNode'. Timestamp of a combined 'SnapshotNode' is the
-- latest timestamp of input nodes for that 'IPv6ID'.
combineNodes :: [SnapshotNode FindingID DIONode]
             -> [SnapshotNode FindingID DAONode]
             -> [SnapshotNode IPv6ID CombinedNode]
combineNodes :: [SnapshotNode FindingID DIONode]
-> [SnapshotNode FindingID DAONode]
-> [SnapshotNode IPv6ID CombinedNode]
combineNodes [SnapshotNode FindingID DIONode]
dio_ns [SnapshotNode FindingID DAONode]
dao_ns = [SnapshotNode IPv6ID CombinedNode]
-> [SnapshotNode IPv6ID CombinedNode]
forall b n.
(Semigroup b, Ord n) =>
[SnapshotNode n b] -> [SnapshotNode n b]
concatNodes ([SnapshotNode IPv6ID CombinedNode]
 -> [SnapshotNode IPv6ID CombinedNode])
-> [SnapshotNode IPv6ID CombinedNode]
-> [SnapshotNode IPv6ID CombinedNode]
forall a b. (a -> b) -> a -> b
$ (SnapshotNode FindingID DIONode
 -> SnapshotNode IPv6ID CombinedNode)
-> [SnapshotNode FindingID DIONode]
-> [SnapshotNode IPv6ID CombinedNode]
forall a b. (a -> b) -> [a] -> [b]
map SnapshotNode FindingID DIONode -> SnapshotNode IPv6ID CombinedNode
fromDIO [SnapshotNode FindingID DIONode]
dio_ns [SnapshotNode IPv6ID CombinedNode]
-> [SnapshotNode IPv6ID CombinedNode]
-> [SnapshotNode IPv6ID CombinedNode]
forall a. [a] -> [a] -> [a]
++ (SnapshotNode FindingID DAONode
 -> SnapshotNode IPv6ID CombinedNode)
-> [SnapshotNode FindingID DAONode]
-> [SnapshotNode IPv6ID CombinedNode]
forall a b. (a -> b) -> [a] -> [b]
map SnapshotNode FindingID DAONode -> SnapshotNode IPv6ID CombinedNode
fromDAO [SnapshotNode FindingID DAONode]
dao_ns
  where
    fromDIO :: SnapshotNode FindingID DIONode -> SnapshotNode IPv6ID CombinedNode
fromDIO = (FindingID -> IPv6ID)
-> (DIONode -> CombinedNode)
-> SnapshotNode FindingID DIONode
-> SnapshotNode IPv6ID CombinedNode
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap FindingID -> IPv6ID
ipv6Only (\DIONode
ln -> Maybe DIONode -> Maybe DAONode -> CombinedNode
CombinedNode (DIONode -> Maybe DIONode
forall a. a -> Maybe a
Just DIONode
ln) Maybe DAONode
forall a. Maybe a
Nothing)
    fromDAO :: SnapshotNode FindingID DAONode -> SnapshotNode IPv6ID CombinedNode
fromDAO = (FindingID -> IPv6ID)
-> (DAONode -> CombinedNode)
-> SnapshotNode FindingID DAONode
-> SnapshotNode IPv6ID CombinedNode
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap FindingID -> IPv6ID
ipv6Only (\DAONode
sn -> Maybe DIONode -> Maybe DAONode -> CombinedNode
CombinedNode Maybe DIONode
forall a. Maybe a
Nothing (DAONode -> Maybe DAONode
forall a. a -> Maybe a
Just DAONode
sn))
    concatNodes :: [SnapshotNode n b] -> [SnapshotNode n b]
concatNodes [SnapshotNode n b]
nodes = ([SnapshotNode n b] -> SnapshotNode n b)
-> [[SnapshotNode n b]] -> [SnapshotNode n b]
forall a b. (a -> b) -> [a] -> [b]
map ([SnapshotNode n b] -> SnapshotNode n b
forall b n. Semigroup b => [SnapshotNode n b] -> SnapshotNode n b
merge ([SnapshotNode n b] -> SnapshotNode n b)
-> ([SnapshotNode n b] -> [SnapshotNode n b])
-> [SnapshotNode n b]
-> SnapshotNode n b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [SnapshotNode n b] -> [SnapshotNode n b]
forall n na. [SnapshotNode n na] -> [SnapshotNode n na]
sortByTimestamp) ([[SnapshotNode n b]] -> [SnapshotNode n b])
-> [[SnapshotNode n b]] -> [SnapshotNode n b]
forall a b. (a -> b) -> a -> b
$ (SnapshotNode n b -> n)
-> [SnapshotNode n b] -> [[SnapshotNode n b]]
forall b a. Ord b => (a -> b) -> [a] -> [[a]]
groupWith SnapshotNode n b -> n
forall n na. SnapshotNode n na -> n
nodeId [SnapshotNode n b]
nodes
      where
        sortByTimestamp :: [SnapshotNode n na] -> [SnapshotNode n na]
sortByTimestamp = [SnapshotNode n na] -> [SnapshotNode n na]
forall a. [a] -> [a]
reverse ([SnapshotNode n na] -> [SnapshotNode n na])
-> ([SnapshotNode n na] -> [SnapshotNode n na])
-> [SnapshotNode n na]
-> [SnapshotNode n na]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SnapshotNode n na -> Maybe Timestamp)
-> [SnapshotNode n na] -> [SnapshotNode n na]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn SnapshotNode n na -> Maybe Timestamp
forall n na. SnapshotNode n na -> Maybe Timestamp
nodeTimestamp
        merge :: [SnapshotNode n b] -> SnapshotNode n b
merge [] = String -> SnapshotNode n b
forall a. HasCallStack => String -> a
error String
"Empty group should not happen."
        merge group_nodes :: [SnapshotNode n b]
group_nodes@(SnapshotNode n b
head_node : [SnapshotNode n b]
_) =
          case Maybe b
mmerged_attr of
            Maybe b
Nothing ->
              -- No node has NodeAttribute. There is no need to merge.
              SnapshotNode n b
head_node
            Just b
merged_attr ->
              case (SnapshotNode n b -> Bool)
-> [SnapshotNode n b] -> [SnapshotNode n b]
forall a. (a -> Bool) -> [a] -> [a]
filter SnapshotNode n b -> Bool
forall n a. SnapshotNode n a -> Bool
hasNodeAttr [SnapshotNode n b]
group_nodes of
                [] -> String -> SnapshotNode n b
forall a. HasCallStack => String -> a
error String
"At least one node must have NodeAttributes"
                (SnapshotNode n b
representative_node : [SnapshotNode n b]
_) -> (b -> b) -> SnapshotNode n b -> SnapshotNode n b
forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (b -> b -> b
forall a b. a -> b -> a
const b
merged_attr) SnapshotNode n b
representative_node
          where
            mmerged_attr :: Maybe b
mmerged_attr = [Maybe b] -> Maybe b
forall a. Monoid a => [a] -> a
mconcat ([Maybe b] -> Maybe b) -> [Maybe b] -> Maybe b
forall a b. (a -> b) -> a -> b
$ (SnapshotNode n b -> Maybe b) -> [SnapshotNode n b] -> [Maybe b]
forall a b. (a -> b) -> [a] -> [b]
map SnapshotNode n b -> Maybe b
forall n na. SnapshotNode n na -> Maybe na
nodeAttributes [SnapshotNode n b]
group_nodes
            hasNodeAttr :: SnapshotNode n a -> Bool
hasNodeAttr SnapshotNode n a
n = Maybe a -> Bool
forall a. Maybe a -> Bool
isJust (Maybe a -> Bool) -> Maybe a -> Bool
forall a b. (a -> b) -> a -> b
$ SnapshotNode n a -> Maybe a
forall n na. SnapshotNode n na -> Maybe na
nodeAttributes SnapshotNode n a
n

-- | Convert DIO and DAO links into combined links. Despite its name,
-- this function does not combine input links. It just make one
-- combined link from each of the input links.
combineLinks :: [SnapshotLink FindingID MergedDIOLink]
             -> [SnapshotLink FindingID DAOLink]
             -> [SnapshotLink IPv6ID CombinedLink]
combineLinks :: [SnapshotLink FindingID MergedDIOLink]
-> [SnapshotLink FindingID DAOLink]
-> [SnapshotLink IPv6ID CombinedLink]
combineLinks [SnapshotLink FindingID MergedDIOLink]
dio_ls [SnapshotLink FindingID DAOLink]
dao_ls = (SnapshotLink FindingID MergedDIOLink
 -> SnapshotLink IPv6ID CombinedLink)
-> [SnapshotLink FindingID MergedDIOLink]
-> [SnapshotLink IPv6ID CombinedLink]
forall a b. (a -> b) -> [a] -> [b]
map SnapshotLink FindingID MergedDIOLink
-> SnapshotLink IPv6ID CombinedLink
fromDIO [SnapshotLink FindingID MergedDIOLink]
dio_ls [SnapshotLink IPv6ID CombinedLink]
-> [SnapshotLink IPv6ID CombinedLink]
-> [SnapshotLink IPv6ID CombinedLink]
forall a. [a] -> [a] -> [a]
++ (SnapshotLink FindingID DAOLink
 -> SnapshotLink IPv6ID CombinedLink)
-> [SnapshotLink FindingID DAOLink]
-> [SnapshotLink IPv6ID CombinedLink]
forall a b. (a -> b) -> [a] -> [b]
map SnapshotLink FindingID DAOLink -> SnapshotLink IPv6ID CombinedLink
fromDAO [SnapshotLink FindingID DAOLink]
dao_ls
  where
    fromDIO :: SnapshotLink FindingID MergedDIOLink
-> SnapshotLink IPv6ID CombinedLink
fromDIO = (FindingID -> IPv6ID)
-> (MergedDIOLink -> CombinedLink)
-> SnapshotLink FindingID MergedDIOLink
-> SnapshotLink IPv6ID CombinedLink
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap FindingID -> IPv6ID
ipv6Only (\MergedDIOLink
ll -> MergedDIOLink -> CombinedLink
CombinedDIOLink MergedDIOLink
ll)
    fromDAO :: SnapshotLink FindingID DAOLink -> SnapshotLink IPv6ID CombinedLink
fromDAO = (FindingID -> IPv6ID)
-> (DAOLink -> CombinedLink)
-> SnapshotLink FindingID DAOLink
-> SnapshotLink IPv6ID CombinedLink
forall (p :: * -> * -> *) a b c d.
Bifunctor p =>
(a -> b) -> (c -> d) -> p a c -> p b d
bimap FindingID -> IPv6ID
ipv6Only (\DAOLink
sl -> DAOLink -> CombinedLink
CombinedDAOLink DAOLink
sl)

-- | 'SnapshotGraph' combining DIO and DAO networks.
type SnapshotGraphCombined = SnapshotGraph IPv6ID CombinedNode CombinedLink

-- | Combine DIO and DAO graphs into the combined graph, using
-- 'combineNodes' and 'combineLinks'.
combineGraphs :: SnapshotGraphDIO
              -> SnapshotGraphDAO
              -> SnapshotGraphCombined
combineGraphs :: SnapshotGraphDIO -> SnapshotGraphDAO -> SnapshotGraphCombined
combineGraphs ([SnapshotNode FindingID DIONode]
dio_ns, [SnapshotLink FindingID MergedDIOLink]
dio_ls) ([SnapshotNode FindingID DAONode]
dao_ns, [SnapshotLink FindingID DAOLink]
dao_ls) =
  ([SnapshotNode FindingID DIONode]
-> [SnapshotNode FindingID DAONode]
-> [SnapshotNode IPv6ID CombinedNode]
combineNodes [SnapshotNode FindingID DIONode]
dio_ns [SnapshotNode FindingID DAONode]
dao_ns, [SnapshotLink FindingID MergedDIOLink]
-> [SnapshotLink FindingID DAOLink]
-> [SnapshotLink IPv6ID CombinedLink]
combineLinks [SnapshotLink FindingID MergedDIOLink]
dio_ls [SnapshotLink FindingID DAOLink]
dao_ls)