packages feed

cpsa-3.4.0: src/CPSA/Graph/Preskeleton.hs

-- Draws preskeletons

-- Copyright (c) 2009 The MITRE Corporation
--
-- This program is free software: you can redistribute it and/or
-- modify it under the terms of the BSD License as published by the
-- University of California.

module CPSA.Graph.Preskeleton (skel) where

import CPSA.Lib.SExpr (SExpr)
import CPSA.Lib.Notation (printMsg, printEnv)
import CPSA.Graph.XMLOutput
import CPSA.Graph.Config
import CPSA.Graph.SVG
import CPSA.Graph.Loader
import CPSA.Graph.Layout
import qualified Data.List as L

showMsg :: Config -> SExpr a -> String
showMsg conf x =
    case notation conf of
      Prefix -> show x
      Infix -> printMsg margin indent x

showEnv :: Config -> SExpr a -> String
showEnv conf x =
    case notation conf of
      Prefix -> show x
      Infix -> printEnv margin indent x

margin :: Int
margin = 1024

indent :: Int
indent = 0

-- Compute a node's position.
npos :: Config -> Rank -> Node -> (Float, Float)
npos conf rank (s, p) =
    (xpos, ypos)
    where
      -- Node x coordinate is determined by its strand
      xpos = mx conf + dx conf * fromIntegral s
      -- Node y coordinate is determined by its rank
      ypos = my conf + dy conf * fromIntegral (rank (s, p) + 1)

-- Dimension of the diagram
dim :: Config -> Int -> Int -> (Float, Float)
dim conf strands maxRank =
    (w, h)
    where
      w = 2 * mx conf + dx conf * fromIntegral (strands - 1)
      h = 2 * my conf + dy conf * fromIntegral (maxRank + 1)

-- Add a cross strand arrow
addEdge :: Config -> Rank -> Vertex -> Float -> Float ->
           String -> [Element] -> Vertex -> [Element]
addEdge conf rank src x1 y1 color elements n =
    let (x2, y2) = npos conf rank (vnode n) in
    arrow conf (sameMsg src n) x1 y1 x2 y2 color : elements

sameMsg :: Vertex -> Vertex -> Bool
sameMsg src dest =
  case (dir src, dir dest) of
    (OutDir, InDir) -> msg src == msg dest
    (SyncDir, SyncDir) -> True
    _ -> False

-- Add a strand node
addNode :: Config -> Preskel -> Rank -> [Element] -> Vertex -> [Element]
addNode conf k rank elements node =
    let (x, y) = npos conf rank (vnode node)
        bullet = circ conf (nodeColor k node) x y
        es = tooltip (showMsg conf $ msg node) [bullet] : elements
        es' = foldl (addEdge conf rank node x y "black") es (succs node L.\\ leadstosuccs node)
        es'' = foldl (addEdge conf rank node x y "blue") es' (leadstosuccs node) in
    maybe es'' (addNode conf k rank es'') (next node)

nodeColor :: Preskel -> Vertex -> Maybe String
nodeColor k node =
  case dir node of
    OutDir -> Nothing           -- Transmission nodes are black
    SyncDir
      | elem node (maybe [] id (unrealized k)) -> Just "orange"
      | otherwise -> Just "gray" -- Realized nodes are gray
    InDir
      | elem node (maybe [] id (unrealized k)) -> Just "red"
      | otherwise -> Just "blue" -- Realized nodes are blue

-- Add role above a strand
addRole :: Config -> [Element] -> Vertex -> [Element]
addRole conf es node =
    if null r then
        es
    else
        tooltip (showEnv conf e) [text conf x y r] : es
    where
      r = role node
      e = env node
      (x, y0) = npos conf snd (strand node, 0)
      (_, y1) = npos conf snd (strand node, (-1))
      y = (y0 + y1) / 2

-- Add strand lines
addStrand :: Config -> Rank -> [Element] -> Vertex -> [Element]
addStrand conf rank es n =
    line conf x1 y1 x2 y2 : es
    where
      (x1, y1) = npos conf rank (vnode n)
      (x2, y2) = npos conf rank (vnode (lastVertex n))

-- Add title of diagram
title :: Config -> Preskel -> [Element]
title conf k =
    foldl (addRole conf) [header] (initial k)
    where
      (w, _) = dim conf (strands k) 0
      (_, y) = npos conf snd (0, (-1))
      content = protocol k ++ " " ++ show (label k)
      header = text conf (w / 2) y (content ++ annotation)
      annotation =
          case unrealized k of
            Nothing -> ""
            Just [] -> " (realized)"
            _ -> ""

-- Draw a preskeleton
skel :: Config -> Preskel -> (Float, Float, [Element])
skel conf k =
    (w, h, lines)
    where
      (w, h) = dim conf (strands k) (maxRank k rank)
      circs = foldl (addNode conf k rank) (title conf k) (initial k)
      lines = foldl (addStrand conf rank) circs (initial k)
      rank = layout k