{-|
Module      : Dep.Bricks.Gate
Description : A module to render different types of gates for the /bricks/ UI.
Maintainer  : hapytexeu+gh@gmail.com
Stability   : experimental
Portability : POSIX

This module has functions to create gates with an arbitrary number of inputs.
-}

module Dep.Bricks.Gate (
    -- * Create generic gates
    gateH, gateV, gate, genericGate
    -- * A collection of /and/ gates
  , andGate, andGateH, andGateH2, andGateH3, andGateV, andGateV2, andGateV3
    -- * A collection of /or/ gates
  , orGate,  orGateH,  orGateH2,  orGateH3,  orGateV,  orGateV2,  orGateV3
  ) where

import Dep.Bricks.Box(boxh, boxhu, boxhd, boxlt, boxrt, boxlb, boxrb, boxv, boxvl, boxvr)
import Dep.Bricks.Layout(CircuitLayout(Horizontal, Vertical))
import Dep.Bricks.Negation(negationH, negationV, negationHList, negationVList)

import Graphics.Vty.Attributes(Attr)
import Graphics.Vty.Image(Image, (<->), (<|>), char, emptyImage, string)

vstring :: Attr -> String -> Image
vstring :: Attr -> String -> Image
vstring Attr
atr = (Char -> Image -> Image) -> Image -> String -> Image
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr (Image -> Image -> Image
(<->) (Image -> Image -> Image)
-> (Char -> Image) -> Char -> Image -> Image
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Attr -> Char -> Image
char Attr
atr) Image
emptyImage

gateLineH :: Char -> Char -> Char -> Int -> Attr -> Image
gateLineH :: Char -> Char -> Char -> Int -> Attr -> Image
gateLineH Char
c0 Char
ci Char
cn Int
n = (Attr -> String -> Image
`string` (Char
c0 Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n Char
ci String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
cn]))

gateLineV :: Char -> Char -> Char -> Int -> Attr -> Image
gateLineV :: Char -> Char -> Char -> Int -> Attr -> Image
gateLineV Char
c0 Char
ci Char
cn Int
n = (Attr -> String -> Image
`vstring` (Char
c0 Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n Char
ci String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
cn]))

-- | Create a gate in the horizontal direction with the given 'Char' that specifies what type of gate it is, and the number of input wires.
gateH
  :: Char  -- ^ The 'Char' that will be printed (repeatedly) on the gate to specify the type of gate.
  -> Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
gateH :: Char -> Int -> Attr -> Image
gateH Char
ci Int
n Attr
attr = Char -> Char -> Char -> Int -> Attr -> Image
gateLineH Char
boxlt Char
boxhu Char
boxrt Int
n Attr
attr Image -> Image -> Image
<-> Char -> Char -> Char -> Int -> Attr -> Image
gateLineH Char
boxv Char
ci Char
boxv Int
n Attr
attr Image -> Image -> Image
<-> Attr -> String -> Image
string Attr
attr (Char
boxlb Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n2 Char
boxh String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char
boxhd Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
n2Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Char
boxh String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
boxrb])
    where n2 :: Int
n2 = Int -> Int -> Int
forall a. Integral a => a -> a -> a
div Int
n Int
2

-- | Create a gate in the vertical direction with the given 'Char' that specifies what type of gate it is, and the number of input wires.
gateV
  :: Char  -- ^ The 'Char' that will be printed (repeatedly) on the gate to specify the type of gate.
  -> Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
gateV :: Char -> Int -> Attr -> Image
gateV Char
ci Int
n Attr
attr = Char -> Char -> Char -> Int -> Attr -> Image
gateLineV Char
boxlt Char
boxvl Char
boxlb Int
n Attr
attr Image -> Image -> Image
<|> Char -> Char -> Char -> Int -> Attr -> Image
gateLineV Char
boxh Char
ci Char
boxh Int
n Attr
attr Image -> Image -> Image
<|> Attr -> String -> Image
vstring Attr
attr (Char
boxrt Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> Char -> String
forall a. Int -> a -> [a]
replicate Int
n2 Char
boxv String -> String -> String
forall a. [a] -> [a] -> [a]
++ Char
boxvr Char -> String -> String
forall a. a -> [a] -> [a]
: Int -> Char -> String
forall a. Int -> a -> [a]
replicate (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
-Int
n2Int -> Int -> Int
forall a. Num a => a -> a -> a
-Int
1) Char
boxv String -> String -> String
forall a. [a] -> [a] -> [a]
++ [Char
boxrb])
    where n2 :: Int
n2 = Int -> Int -> Int
forall a. Integral a => a -> a -> a
div Int
n Int
2


-- | Create a gate in the given 'CircuitLayout' with the given 'Char' that specifies what type of gate it is, and the number of input wires.
gate
  :: Char  -- ^ The 'Char' that will be printed (repeatedly) on the gate to specify the type of gate.
  -> CircuitLayout -- ^ The given 'CircuitLayout' that specifies in what direction the gate is written.
  -> Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
gate :: Char -> CircuitLayout -> Int -> Attr -> Image
gate = (CircuitLayout -> Char -> Int -> Attr -> Image)
-> Char -> CircuitLayout -> Int -> Attr -> Image
forall a b c. (a -> b -> c) -> b -> a -> c
flip CircuitLayout -> Char -> Int -> Attr -> Image
go
  where go :: CircuitLayout -> Char -> Int -> Attr -> Image
go CircuitLayout
Horizontal = Char -> Int -> Attr -> Image
gateH
        go CircuitLayout
Vertical = Char -> Int -> Attr -> Image
gateV

negationOut :: Int -> (Image -> Image -> Image) -> (Bool -> Attr -> Image) -> Bool -> Attr -> Image
negationOut :: Int
-> (Image -> Image -> Image)
-> (Bool -> Attr -> Image)
-> Bool
-> Attr
-> Image
negationOut Int
n Image -> Image -> Image
mgr Bool -> Attr -> Image
wr Bool
bl Attr
atr = (Image -> Image -> Image) -> Image -> [Image] -> Image
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr ((Image -> Image -> Image) -> Image -> Image -> Image
forall a b c. (a -> b -> c) -> b -> a -> c
flip Image -> Image -> Image
mgr) Image
emptyImage (Bool -> Attr -> Image
wr Bool
bl Attr
atr Image -> [Image] -> [Image]
forall a. a -> [a] -> [a]
: Int -> Image -> [Image]
forall a. Int -> a -> [a]
replicate (Int
nInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1) (Attr -> Char -> Image
char Attr
atr Char
' '))

-- | A function to create a gate with negators and the input and output.
genericGate
  :: Char  -- ^ The 'Char' that specifies /what/ type of gate it is. This 'Char'acter will be printed (repeatedly) on the gate.
  -> CircuitLayout  -- ^ The 'CircuitLayout' that specifies in what direction the gate is written.
  -> [Bool]  -- ^ Specifies what wires have negators at the input side.
  -> Bool  -- ^ Specifies if the output side has a negator.
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
genericGate :: Char -> CircuitLayout -> [Bool] -> Bool -> Attr -> Image
genericGate Char
ci CircuitLayout
ly [Bool]
ngi Bool
ng Attr
atr = CircuitLayout -> Image
go CircuitLayout
ly
  where go :: CircuitLayout -> Image
go CircuitLayout
Horizontal = (Attr -> Char -> Image
char Attr
atr Char
' ' Image -> Image -> Image
<|> [Bool] -> Attr -> Image
negationHList [Bool]
ngi Attr
atr) Image -> Image -> Image
<-> Char -> Int -> Attr -> Image
gateH Char
ci Int
n Attr
atr Image -> Image -> Image
<-> Int
-> (Image -> Image -> Image)
-> (Bool -> Attr -> Image)
-> Bool
-> Attr
-> Image
negationOut Int
n2 Image -> Image -> Image
(<|>) Bool -> Attr -> Image
negationH Bool
ng Attr
atr
        go CircuitLayout
Vertical = (Attr -> Char -> Image
char Attr
atr Char
' ' Image -> Image -> Image
<-> [Bool] -> Attr -> Image
negationVList [Bool]
ngi Attr
atr) Image -> Image -> Image
<|> Char -> Int -> Attr -> Image
gateV Char
ci Int
n Attr
atr Image -> Image -> Image
<|> Int
-> (Image -> Image -> Image)
-> (Bool -> Attr -> Image)
-> Bool
-> Attr
-> Image
negationOut Int
n2 Image -> Image -> Image
(<->) Bool -> Attr -> Image
negationV Bool
ng Attr
atr
        n :: Int
n = [Bool] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [Bool]
ngi
        n2 :: Int
n2 = Int -> Int -> Int
forall a. Integral a => a -> a -> a
div Int
n Int
2

-- | A helper function to create /and/ gates in a more effective way.
andGate
  :: CircuitLayout -- ^ The given 'CircuitLayout' that specifies in what direction the gate is written.
  -> Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGate :: CircuitLayout -> Int -> Attr -> Image
andGate = Char -> CircuitLayout -> Int -> Attr -> Image
gate Char
'&'

-- | A helper function to create /horizontal/ and gates in a more effective way.
andGateH
  :: Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGateH :: Int -> Attr -> Image
andGateH = Char -> Int -> Attr -> Image
gateH Char
'&'

-- | A helper function to create a horizontal and gate with /two/ input wires.
andGateH2
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGateH2 :: Attr -> Image
andGateH2 = Int -> Attr -> Image
andGateH Int
2

-- | A helper function to create a horizontal and gate with /three/ input wires.
andGateH3
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGateH3 :: Attr -> Image
andGateH3 = Int -> Attr -> Image
andGateH Int
3

-- | A helper function to create /vertical/ and gates in a more effective way.
andGateV
  :: Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGateV :: Int -> Attr -> Image
andGateV = Char -> Int -> Attr -> Image
gateV Char
'&'

-- | A helper function to create a vertical and gate with /two/ input wires.
andGateV2
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGateV2 :: Attr -> Image
andGateV2 = Int -> Attr -> Image
andGateV Int
2

-- | A helper function to create a vertical and gate with /three/ input wires.
andGateV3
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
andGateV3 :: Attr -> Image
andGateV3 = Int -> Attr -> Image
andGateV Int
3


-- | A helper function to create /or/ gates in a more effective way.
orGate
  :: CircuitLayout -- ^ The given 'CircuitLayout' that specifies in what direction the gate is written.
  -> Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGate :: CircuitLayout -> Int -> Attr -> Image
orGate = Char -> CircuitLayout -> Int -> Attr -> Image
gate Char
'|'

-- | A helper function to create /horizontal/ or gates in a more effective way.
orGateH
  :: Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGateH :: Int -> Attr -> Image
orGateH = CircuitLayout -> Int -> Attr -> Image
orGate CircuitLayout
Horizontal

-- | A helper function to create a horizontal or gate with /two/ input wires.
orGateH2
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGateH2 :: Attr -> Image
orGateH2 = Int -> Attr -> Image
orGateH Int
2

-- | A helper function to create a horizontal or gate with /three/ input wires.
orGateH3
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGateH3 :: Attr -> Image
orGateH3 = Int -> Attr -> Image
orGateH Int
3

-- | A helper function to create /vertical/ or gates in a more effective way.
orGateV
  :: Int  -- ^ The number of input wires (/fan-in/).
  -> Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGateV :: Int -> Attr -> Image
orGateV = CircuitLayout -> Int -> Attr -> Image
orGate CircuitLayout
Vertical

-- | A helper function to create a vertical or gate with /two/ input wires.
orGateV2
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGateV2 :: Attr -> Image
orGateV2 = Int -> Attr -> Image
orGateV Int
2

-- | A helper function to create a vertical or gate with /three/ input wires.
orGateV3
  :: Attr  -- ^ The 'Attr' that specifies the style of the gate.
  -> Image  -- ^ The corresponding 'Image'.
orGateV3 :: Attr -> Image
orGateV3 = Int -> Attr -> Image
orGateV Int
3