ampersand-3.0.3: src/Database/Design/Ampersand/FSpec/FPA.hs
module Database.Design.Ampersand.FSpec.FPA (FPA(..), FP(..), FPType(..), ShowLang(..), fpAnalyze, fpVal, fpaPlugInfo, fpaInterface) where
-- fpaPlugInfo and fpaInterface are exported for legacy modules Statistics and FSpec2Excel
import Database.Design.Ampersand.Misc (Lang(..))
import Database.Design.Ampersand.ADL1
import Database.Design.Ampersand.Classes
import Database.Design.Ampersand.FSpec.FSpec
import Database.Design.Ampersand.Basics
import Data.Maybe
--fatal :: Int -> String -> a
--fatal = fatalMsg "FSpec.FPA"
data FPA = FPA { dataModelFPA :: ([FP], Int), userTransactionFPA :: ([FP],Int) } deriving Show
-- NOTE: FPA constructors are in Dutch (so 'output function' is not OF, but UF)
data Complexity = Eenvoudig | Gemiddeld | Moeilijk deriving (Show, Eq, Ord)
data FPType
= ILGV -- ^ bevat permanente, voor de gebruiker relevante gegevens. De gegevens worden door het systeem gebruikt en onderhouden. Onder "onderhouden" verstaat FPA het toevoegen, wijzigen of verwijderen van gegevens.
| KGV -- ^ bevat permanente, voor de gebruiker relevante gegevens. Deze gegevens worden door het systeem gebruikt, maar worden door een ander systeem onderhouden (voor dat andere systeem is het dus een ILGV).
| IF -- ^ verwerkt gegevens in een ILGV van het systeem. (dus create, update en delete functies)
| UF -- ^ presenteert gegevens uit het systeem. Voorbeelden: het afdrukken van alle debiteuren; het aanmaken van facturen; het aanmaken van een diskette met betalingsopdrachten; het medium is hierbij niet van belang: papier, scherm, magneetband, datacom, enzovoorts.
| OF -- ^ is een speciaal (eenvoudig) soort uitvoerfunctie. Een opvraagfunctie presenteert gegevens uit het systeem op basis van een uniek identificerend zoekgegeven, waarbij geen aanvullende bewerkingen (zoals berekeningen of het bijwerken van een gegevensverzameling) plaats hebben. Voorbeeld: Het tonen van de gegevens van de klant met klantnummer 123456789.
deriving Show
data FP = FP { fpType :: FPType, fpName :: String, fpComplexity :: Complexity } deriving Show
-- | Valuing of function points according to par. 3.9 (UK) or par. 2.9 (NL), see http://www.nesma.nl/sectie/fpa/hoefpa.asp
fpVal :: FP -> Int
fpVal FP{fpType=ILGV, fpComplexity=Eenvoudig} = 7
fpVal FP{fpType=ILGV, fpComplexity=Gemiddeld} = 10
fpVal FP{fpType=ILGV, fpComplexity=Moeilijk} = 15
fpVal FP{fpType=KGV, fpComplexity=Eenvoudig} = 5
fpVal FP{fpType=KGV, fpComplexity=Gemiddeld} = 7
fpVal FP{fpType=KGV, fpComplexity=Moeilijk} = 10
fpVal FP{fpType=IF, fpComplexity=Eenvoudig} = 3
fpVal FP{fpType=IF, fpComplexity=Gemiddeld} = 4
fpVal FP{fpType=IF, fpComplexity=Moeilijk} = 6
fpVal FP{fpType=UF, fpComplexity=Eenvoudig} = 4
fpVal FP{fpType=UF, fpComplexity=Gemiddeld} = 5
fpVal FP{fpType=UF, fpComplexity=Moeilijk} = 7
fpVal FP{fpType=OF, fpComplexity=Eenvoudig} = 3
fpVal FP{fpType=OF, fpComplexity=Gemiddeld} = 4
fpVal FP{fpType=OF, fpComplexity=Moeilijk} = 6
fpAnalyze :: FSpec -> FPA
fpAnalyze fSpec = FPA (countFPs $ fpaDataModel fSpec) (countFPs $ fpaUserTransactions fSpec)
where countFPs :: [FP] -> ([FP], Int)
countFPs fps = (fps, sum $ map fpVal fps)
-- Na overleg met Frank Vogelenzang zijn de volgende criteria voor functiepuntentelling toegepast
fpaDataModel :: FSpec -> [FP]
fpaDataModel fSpec = mapMaybe fpaPlugInfo $ plugInfos fSpec
fpaPlugInfo :: PlugInfo -> Maybe FP
fpaPlugInfo p@(InternalPlug (TblSQL{fields=flds})) | Just cmplxty <- ilgvComplexity $ length flds =
Just $ FP ILGV (name p) cmplxty
where ilgvComplexity :: Int -> Maybe Complexity
ilgvComplexity n | n <= 2 = Nothing
| n <= 15 = Just Eenvoudig
| n <= 40 = Just Gemiddeld
| otherwise = Just Moeilijk
fpaPlugInfo _ = Nothing
fpaUserTransactions :: FSpec -> [FP]
fpaUserTransactions fSpec = map fpaInterface $ interfaceS fSpec
fpaInterface :: Interface -> FP
fpaInterface ifc =
let nm = name ifc
cmplxty = depth2Cmplxty $ getDepth $ ifcObj ifc
tp = case ifc of
Ifc{ifcClass=Just "IF"} -> IF
Ifc{ifcClass=Just "UF"} -> UF
Ifc{ifcClass=Just "OF"} -> OF
-- code for interfaces without CLASS comes from old FPA.hs
_ | (not.null.ifcParams) ifc -> IF -- In case there are editable relations, this must be an import function.
| (isUni.objctx.ifcObj) ifc -> OF -- If there is max one atom, this is a simple function.
| otherwise -> UF -- Otherwise, it is a UF
in FP tp nm cmplxty
where depth2Cmplxty :: Int -> Complexity
depth2Cmplxty d | d <= 1 = Eenvoudig
| d == 2 = Gemiddeld
| otherwise = Moeilijk
getDepth Obj{objmsub=Nothing} = 0
getDepth Obj{objmsub=Just InterfaceRef{}} = 1 -- TODO: shouldn't we follow the ref? (this def. is from old FPA.hs)
getDepth Obj{objmsub=Just (Box _ _ objs)} = 1 + maximum (map getDepth objs)
class ShowLang a where
showLang :: Lang -> a -> String
instance ShowLang FP where
showLang lang fp = showLang lang (fpType fp) ++ " " ++ showLang lang (fpComplexity fp)
instance ShowLang FPType where
showLang Dutch ILGV = "ILGV"
showLang Dutch KGV = "KGV"
showLang Dutch IF = "IF"
showLang Dutch UF = "UF"
showLang Dutch OF = "OF"
showLang English ILGV = "ILF" -- Internal Logical File
showLang English KGV = "ELF" -- External Logical File
showLang English IF = "EI" -- External Input
showLang English UF = "EO" -- External Output
showLang English OF = "EQ" -- External inQuiry
instance ShowLang Complexity where
showLang Dutch Eenvoudig = "Eenvoudig"
showLang Dutch Gemiddeld = "Gemiddeld"
showLang Dutch Moeilijk = "Moeilijk"
showLang English Eenvoudig = "Low"
showLang English Gemiddeld = "Average"
showLang English Moeilijk = "High"