{-# LANGUAGE NamedFieldPuns #-}
module Database.Design.Ampersand.Prototype.GenBericht (doGenBericht) where
import Prelude hiding (writeFile)
import Data.List
import Text.CSV
import System.FilePath
import System.Directory
import Control.Monad
import Database.Design.Ampersand
-- TODO: only show Rel and Flp Rel? give error otherwise?
-- what about Typ, Brk etc.?
fatal :: Int -> String -> a
fatal = fatalMsg "GenBericht"
-- an intermediate data type, so we can easily generate to several output formats
data Entity = Entity { entName :: String
, depth :: Int
, cardinality :: String
, definition :: String
, refType :: String
, properties :: [Entity]
} deriving Show
doGenBericht :: FSpec -> IO ()
doGenBericht fSpec =
do { verboseLn (getOpts fSpec) "Generating 'Berichtendefinities'..."
; createDirectoryIfMissing True $ combine (dirPrototype (getOpts fSpec)) "Berichten"
; let entities = genEntity_Interfaces $ interfaceS fSpec
; let berichtenCSV = allEntitiesToCSV entities
; when (development (getOpts fSpec)) $ verboseLn (getOpts fSpec) $ layout berichtenCSV
; genFile "Berichten/Berichten.csv" $ printSemicolonSeparated berichtenCSV
; genFile "Berichten/Gegevenswoordenboek.html" $ genGegevensWB entities
; genFile "Berichten/Berichtdefinitie.html" $ genBerichtDef entities
}
where
genFile filename contents =
do { writeFile (combine (dirPrototype (getOpts fSpec)) filename) contents
; verboseLn (getOpts fSpec) $ "\nGenerated file "++filename
}
genEntity_Interfaces :: [Interface] -> [Entity]
genEntity_Interfaces interfaces' = map genEntity_Interface interfaces'
where
genEntity_Interface :: Interface -> Entity
genEntity_Interface interface = genEntity_ObjDef 0 (ifcObj interface)
where
genEntity_ObjDef :: Int -> ObjectDef -> Entity
genEntity_ObjDef dpth objDef =
Entity { entName = name objDef
, depth = dpth
, cardinality = card $ objctx objDef
, definition = def $ objctx objDef
, refType = name (target $ objctx objDef)
, properties =
case objmsub objDef of
Nothing -> []
Just (Box _ _ objs) -> map (genEntity_ObjDef (dpth+1)) objs
Just (InterfaceRef nm) -> map (genEntity_ObjDef (dpth+1)) $ objsForInterfaceNamed nm
}
where card e = (if isTot e then "1" else "0")++".."++(if isUni e then "1" else "*")
def rel = case concDefs fSpec (target rel) of
Cd {cddef=def'} : _ | def' /= "" -> def'
_ -> "** NO DEFINITION **"
objsForInterfaceNamed :: String -> [ObjectDef]
objsForInterfaceNamed nm =
case objmsub $ ifcObj $ getInterfaceByName interfaces' nm of
Just (Box _ _ objs) -> objs
_ -> fatal 81 "Bericht interfaces have wrong format"
-- NOTE: We ignore the interface relation for interfaces refs
allEntitiesToCSV :: [Entity] -> CSV
allEntitiesToCSV entities = ["Naam", "Card.", "Definitie", "Type"] :
intercalate [["","","",""]] (map entityToCSV entities)
entityToCSV :: Entity -> CSV
entityToCSV (Entity nm dpth card def refTp props) =
[ concat (replicate dpth ". ") ++ nm, card, def, refTp] : concatMap entityToCSV props
-- Utils
layout :: [[String]] -> String
layout linez =
let columns = transpose linez
formatColumn col = let width = maximum . map length $ col
in map (fill width) col
in unlines . map unwords . transpose . map formatColumn $ columns
where fill i str = str ++ take (i - length str) (replicate i ' ')
-- Modified version of Text.CSV.printCSV
printSemicolonSeparated :: CSV -> String
printSemicolonSeparated records = unlines (printRecord `map` records)
where printRecord = intercalate ";" . map printField
printField f = "\"" ++ concatMap escape f ++ "\""
escape '"' = "\"\""
escape x = [x]
-- Html
genGegevensWB :: [Entity] -> String
genGegevensWB entities = gegevensWB_Header ++
gegevensWB_Toc ++
gegevensWB_Middle ++
concatMap gegevensWB_Element entities ++
gegevensWB_Footer
where
gegevensWB_Toc :: String
gegevensWB_Toc = unlines
[ "
" ++ mkLocalLink concept' concept' ++ ""
| Entity{ entName = concept' } <- entities
]
-- TODO: it's not the concept, but the interface name, yet refTp is a concept? or also an interface name?
gegevensWB_Element :: Entity -> String
gegevensWB_Element (Entity concept' _ _ _ _ props) =
wbElement_Header ++
concatMap (wbElement_Element concept') props ++
wbElement_Footer
where
wbElement_Header :: String
wbElement_Header =
" " ++ mkAnchor concept' ++
" \n" ++
"
"++concept'++"
\n" ++
"
"++concept'++"
\n" ++
"
\n" ++
" Property term | Cardinality | Representation term |
\n"
where
mkAnchor :: String -> String
mkAnchor entityName = " \n"
wbElement_Element :: String -> Entity -> String
wbElement_Element parentConcept (Entity _ _ card def refTp _) =
" \n" ++
" "++def++" | \n" ++
-- NOTE: don't want def twice here
" "++card++" | \n" ++
" " ++ mkLink entities refTp refTp ++ " | \n" ++
-- TODO: leave out if this is not a defined data type
"
\n"
wbElement_Footer :: String
wbElement_Footer =
"
\n" ++
"
\n"
gegevensWB_Header :: String
gegevensWB_Header =
"\n" ++
"\n" ++
"\n" ++
"\n" ++
"Rechtspraak 2011-11-25 20:14:20\n" ++
"\n" ++
"\n" ++
"\n" ++
"\n" ++
"\n" ++
"
\n" ++
"
Aggregate BIEs
\n" ++
"
\n"
gegevensWB_Middle :: String
gegevensWB_Middle =
"
\n" ++
"
\n" ++
"
\n" ++
"\n" ++
"
\n"
gegevensWB_Footer :: String
gegevensWB_Footer =
"
\n" ++
"
\n" ++
"\n" ++
"\n"
mkLocalLink :: String -> String -> String
mkLocalLink nm html = "" ++
html ++ ""
mkLink :: [Entity] -> String -> String -> String
mkLink entities nm html =
if isEntity entities nm
then "\n"++
html ++ ""
else html
isEntity :: [Entity] -> String -> Bool
isEntity entities nm = (not.null) (filter ((==nm) . entName) entities)
genBerichtDef :: [Entity] -> String
genBerichtDef entities =
berichtDef_Header ++
berichtDef_Toc ++
berichtDef_Middle ++
concatMap berichtDef_ElementLine entities ++
berichtDef_Footer
where
berichtDef_Toc :: String
berichtDef_Toc = unlines
[ " "++entNm++""
| Entity{ entName = entNm } <- entities
]
berichtDef_ElementLine :: Entity -> String
berichtDef_ElementLine (Entity entNm depth card def refTp props) =
" \n" ++
" \n" ++
" " ++ mkLink entities refTp entNm ++
" | \n" ++
" "++card++" | \n" ++
" "++def++" | \n" ++
"
\n" ++
concatMap berichtDef_ElementLine props
where padding = if depth > 0 then " style=\"padding-left:"++show (depth*25)++"px\"" else ""
-- Html-page strings
berichtDef_Header :: String
berichtDef_Header =
"\n" ++
"\n" ++
"\n" ++
"\n" ++
"Documentation for Aanlevering Zaakstuk\n" ++
"\n" ++
"\n" ++
"\n" ++
"\n" ++
"Business Document - AanleveringZaakstuk_BD-023011
\n" ++
"\n" ++
"
Document Information
\n" ++
"
\n" ++
" Aanlevering Zaakstuk |
\n" ++
" |
\n" ++
" 1.1.0.0 |
\n" ++
" BD-023011 |
\n" ++
" 1.1RC02 |
\n" ++
" 2011-11-25 |
\n" ++
" Gebruikt om stukken aan te leveren aan de Rechtsprekende Instantie. |
\n" ++
" 'Generiek' BD Aanlevering Zaakstuk.
1.1 heeft voorschot salaris toegevoegd - specifiek voor DDI |
\n" ++
" The XML schema for this business document includes the http://data.justid.nl/common/header-1 header(s). |
\n" ++
"
\n" ++
"
Document Properties
\n" ++
"
\n"
berichtDef_Middle :: String
berichtDef_Middle =
"
\n" ++
"
\n" ++
"
\n" ++
"
\n" ++
" Property term | Cardinality | Definition |
\n"
berichtDef_Footer :: String
berichtDef_Footer =
" \n" ++
"\n" ++
"\n" ++
"\n"