-- Dieses Modul definiert einen Algebraischen Datentyp der im Codegenerator zur Generierung des Zielcodes benötigt. Er enthält die % TODO : Referenz
-- Komponenten ID, sowie benannte Ein- und Ausgangspins.


module System.ArrowVHDL.Circuit.PinTransit
where




-- Benötigt werden Modul-Definitionen aus \hsSource{Circuit}.


import System.ArrowVHDL.Circuit.Descriptor


-- \subsection{Datenstruktur}
-- Zunächst werden Typaliasse angelegt, welche die verwendeten Datentypen nach ihrer Aufgabe benennen. 


type NamedPin  = (PinID, String)
type InNames   = [NamedPin]
type OutNames  = [NamedPin]

type NamedComp = (CompID, (InNames, OutNames))
 


-- \subsection{Funktionen}
-- Um die interne Datenstruktur des Algebraischen Datentypes bedienen zu können, werden folgende Funktionen definiert

--   generateNamedComps % \\ Eine Funktion die aus einem CircuitDescriptor die Benamte Komponentenliste erstellt
--   getInPinNames      % \\ Eine Funktion die eine In-PinID / Namen's Liste aus der NamedComp Liste erzeugt
--   getOutPinNames     % \\ Eine Funktion die eine Out-PinID / Namen's Liste aus der NamedComp Liste erzeugt
--   getInPinName       % \\ Eien weitere Funktion die ein InPinID/Namens Paar aus der NamedComp Liste und aus einer PinID erstellt
--   getOutPinName      % \\ Eien weitere Funktion die ein OutPinID/Namens Paar aus der NamedComp Liste und aus einer PinID erstellt

 
-- Die Funktion \hsSource{generateNamedComps} erzeugt die benannten Komponenten Liste. Hier werden nur die Pins benannt. Ein Pin kann immer von
-- zwei Seiten aus gesehen werden. Es gibt \begriff{externe} Pins, also Pins, die an die von außen ein Draht angeschlossen werden kann. Diese
-- werden unter dem namen \hsSource{generateSuperNames} zusammengefasst. Daneben existieren auch \begriff{interne} Pins, die man hinter dem
-- Namen \hsSource{generateSubNames} findet. Diese Unterscheidung muss getroffen werden, da externe Pins mit den Präfixen \hsSource{nameExI}
-- und \hsSource{nameExO} versehen werden. Interne Pins werden mit \hsSource{nameInI} sowie \hsSource{NameInO} benamt.
-- \hsSource{generateSuperNames} wird auf den übergebenen \hsSource{CircuitDescriptor} angewandt, die Funktion \hsSource{generateSubNames}
-- hingegen auf alle dem \hsSource{CircuitDescriptor} untergeordneten \hsSource{CircuitDescriptor}en. 


generateNamedComps :: CircuitDescriptor -> [NamedComp]
generateNamedComps g = generateSuperNames g : (map generateSubNames $ nodes g)
      where generateSuperNames g = ( (nodeId.nodeDesc) g
                                   , ( namePins (sinks.nodeDesc)   nameExI g
                                     , namePins (sources.nodeDesc) nameExO g
                                     )
                                   )
            generateSubNames g   = ( (nodeId.nodeDesc) g
                                   , ( namePins (sinks.nodeDesc)   nameInI g
                                     , namePins (sources.nodeDesc) nameInO g
                                     )
                                   )




-- Die beiden Funktionen \hsSource{getNamedInPins} sowie \hsSource{getInPinNames} holen jeweils aus einer Liste von \hsSource{NamedComp} und
-- einer \hsSource{CompID} den passenden Datensatz heraus. Hierbei unterscheiden sie sich lediglich im Rückgabetyp voneinander. So liefert
-- \hsSource{getNamedInPins} die \hsSource{InNames}, also eine Liste benannter Pins, zurück. \hsSource{getInPinNames} liefert nur eine Liste
-- der Namen.


    -- TODO: is fst the right function to get the in-names ???

getNamedInPins :: [NamedComp] -> CompID -> InNames
getNamedInPins = getPinNames fst

getInPinNames :: [NamedComp] -> CompID -> [String]
getInPinNames cname cid = map snd $ getNamedInPins cname cid



 
-- Die beiden nächsten Funktionen, \hsSource{getNamedOutPins} sowie \hsSource{getOutPinNames} verhalten sich analog zu den beiden
-- \begriff{InPin} varianten, mit dem Unterschied, dass diese beiden Funktionen sich auf die Ausgabepins beziehen.


    -- TODO: is snd the right function to get the out-names ???

getNamedOutPins :: [NamedComp] -> CompID -> OutNames
getNamedOutPins = getPinNames snd

getOutPinNames :: [NamedComp] -> CompID -> [String]
getOutPinNames cname cid = map snd $ getNamedOutPins cname cid



 
-- Mit der Funktion \hsSource{getPinNames} wird die eigentliche Logik beschrieben, die für das herausfiltern der Pin-Namen notwendig ist. Aus
-- der übergebenen Liste der benannten Komponenten werden all die Komponenten heraus gefiltert, die der ebenfalls übergebenen Komponenten ID
-- entsprechen. Im nächsten Schritt (\hsSource{map snd}) wird die Komponenten ID verworfen. Die übergeben Funktion \hsSource{f} definiert nun,
-- ob das Ergebnis eingehende oder ausgehende Pins sind. Der letzte Schritt entfernt überflüssige Listen-Verschachtelungen.


getPinNames :: (([NamedPin], [NamedPin]) -> [NamedPin]) -> [NamedComp] -> CompID -> [(PinID, String)]
getPinNames f cname cid
    = concat
    $ map f
    $ map snd
    $ filter (\(x, _) -> x == cid)
    $ cname




-- Die folgenden fünf Funktionen arbeiten analog zu den vorhergehenden fünf. Sie unterscheiden sich darin, dass sie einen weiteren Parameter
-- erwarten, ein \hsSource{PinID}. Dieser Parameter schränkt die Ergebnismenge auf exakt ein Ergebnis ein, sie liefern also einen benannten
-- Pin.

getNamedInPin :: [NamedComp] -> CompID -> PinID -> NamedPin
getNamedInPin = getPinName getNamedInPins

getNamedOutPin :: [NamedComp] -> CompID -> PinID -> NamedPin
getNamedOutPin = getPinName getNamedOutPins

getInPinName :: [NamedComp] -> CompID -> PinID -> String
getInPinName cname cid pid = snd $ getNamedInPin cname cid pid

getOutPinName :: [NamedComp] -> CompID -> PinID -> String
getOutPinName cname cid pid = snd $ getNamedOutPin cname cid pid

getPinName :: ([NamedComp] -> CompID -> [NamedPin]) -> [NamedComp] -> CompID -> PinID -> NamedPin
getPinName f cname cid pid
    = head
    $ filter (\(x, _) -> x == pid)
    $ f cname cid




-- Die letzte Funktion in diesem Modul erzeugt aus einem \hsSource{CircuitDescriptor} und einem Präfix eine Liste benannter Pins. Diese
-- Funktion wird in \hsSource{generateNamedComps} verwendet, um interne und externe Pins mit Namen zu versehen. Je nach übergebenen
-- \hsSource{f} produziert \hsSource{namePins} benannte interne oder benannte externe Pinlisten.

namePins :: (CircuitDescriptor -> Pins) -> String -> CircuitDescriptor -> [NamedPin]
namePins f pre g
    = map (\x -> (x, pre ++ (show x))) $ f g
 
