content: module DataFlow.SequenceDiagram (asSequenceDiagram) where
  
  import qualified Data.Map as M
  import Data.List.Utils
  import Text.Printf
  
  import qualified DataFlow.Core as C
  import DataFlow.Attributes
  import DataFlow.PlantUML
  
  convertNewline :: String -> String
  convertNewline = replace "\n" "\\n"
  
  bold :: String -> String
  bold "" = ""
  bold s = printf "<b>%s</b>" s
  
  italic :: String -> String
  italic "" = ""
  italic s =
    -- each line (separated by \n) needs to be wrapped in its own <i></i>
    join "\\n" $ map italic' $ split "\\n" s
    where italic' = printf "<i>%s</i>"
  
  showValue :: C.Value -> String
  showValue (C.String s) = convertNewline s
  showValue (C.Array vs) = join "\\n" $ map showValue vs
  
  blank :: C.Value
  blank = C.String ""
  
  convertNode :: C.Node -> Stmt
  convertNode (C.InputOutput id' attrs) =
    Entity id' $ convertNewline $ getTitleOrBlank attrs
  convertNode (C.Function id' attrs) =
    Participant id' $ convertNewline $ getTitleOrBlank attrs
  convertNode (C.Database id' attrs) =
    Database id' $ convertNewline $ getTitleOrBlank attrs
  
  convertFlow :: C.Flow -> Stmt
  convertFlow (C.Flow i1 i2 attrs) =
    let p = (bold $ showValue $ M.findWithDefault blank "operation" attrs,
             italic $ showValue $ M.findWithDefault blank "data" attrs)
        s = case p of
              ("", "") -> ""
              ("", d) -> d
              (o, "") -> o
              (o, d) -> o ++ "\\n" ++ d
    in Edge i1 i2 s
  
  convertRootNode :: C.RootNode -> Stmt
  convertRootNode (C.TrustBoundary id' attrs nodes) =
    let title = showValue $ M.findWithDefault (C.String id') "title" attrs
    in Box title (map convertNode nodes)
  convertRootNode (C.Node n) = convertNode n
  
  defaultSkinParams :: [Stmt]
  defaultSkinParams = [
      SkinParam "BackgroundColor" "#white",
      SkinParam "Shadowing" "false",
      SkinParam "SequenceMessageAlign" "center",
      SkinParam "DefaultFontName" "Arial",
      SkinParam "DefaultFontStyle" "bold",
      SkinParam "DefaultFontColor" "#333333",
  
      SkinParam "NoteBackgroundColor" "#fbfb77",
      SkinParam "NoteBorderColor" "#cbcb47",
  
      SkinParam "NoteBackgroundColor" "#ffffcd",
      SkinParam "NoteBorderColor" "#a9a980",
      SkinParam "NoteFontColor" "#676735",
      SkinParam "NoteFontStyle" "italic",
  
      SkinParam "SequenceArrowColor" "#555555",
      SkinParam "SequenceArrowFontColor" "#555555",
      SkinParam "SequenceArrowFontStyle" "none",
  
      SkinParam "SequenceBoxBackgroundColor" "#fafafa",
      SkinParam "SequenceBoxBorderColor" "#eeeeee",
      SkinParam "SequenceBoxFontColor" "#666666",
      SkinParam "SequenceBoxFontSize" "12",
      SkinParam "SequenceBoxFontStyle" "italic",
  
      SkinParam "ParticipantBackgroundColor" "#dde5ff",
      SkinParam "ParticipantBorderColor" "#cccccc",
      SkinParam "ParticipantFontColor" "#333333",
      SkinParam "ParticipantFontStyle" "bold",
  
      SkinParam "DatabaseBackgroundColor" "#df4646",
      SkinParam "DatabaseFontColor" "#red",
      SkinParam "DatabaseFontStyle" "bold",
  
      SkinParam "EntityBackgroundColor" "#999999",
  
      SkinParam "SequenceLifeLineBorderColor" "#bbbbbb"
    ]
  
  asSequenceDiagram :: C.Diagram -> Diagram
  asSequenceDiagram (C.Diagram _ rootNodes flows) =
    SequenceDiagram $ defaultSkinParams
                      ++ map convertRootNode rootNodes
                      ++ map convertFlow flows
  