{-# LANGUAGE NoImplicitPrelude #-}

module Data.Aviation.Casa.AbbreviationsAndAcronyms.Render.Spacing(
  Spacing
, HasSpacing(..)
, nameHeader
, meaningHeader
, sourceHeader
, scoreHeader
, standardSpacing
, mkSpacing
, (<->)
, exactWidthSpacing
) where

import Control.Category((.), id)
import Control.Lens(Lens', set, (^.))
import Data.Aviation.Casa.AbbreviationsAndAcronyms.Acronym(HasAcronym(name, meaning, source))
import Data.Aviation.Casa.AbbreviationsAndAcronyms.Render.Score(HasShowScore(showScore))
import Data.Eq(Eq)
import Data.Foldable(length, foldMap)
import Data.Function(($))
import Data.Functor(fmap)
import Data.Int(Int)
import Data.Monoid(Monoid(mappend, mempty))
import Data.Ord(Ord, max, min)
import Data.Semigroup(Semigroup((<>)))
import Data.String(String)
import Prelude(Show)

data Spacing =
  Spacing
    Int -- separator
    Int -- name
    Int -- meaning
    Int -- source
    Int -- score
  deriving (Spacing -> Spacing -> Bool
(Spacing -> Spacing -> Bool)
-> (Spacing -> Spacing -> Bool) -> Eq Spacing
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Spacing -> Spacing -> Bool
$c/= :: Spacing -> Spacing -> Bool
== :: Spacing -> Spacing -> Bool
$c== :: Spacing -> Spacing -> Bool
Eq, Eq Spacing
Eq Spacing
-> (Spacing -> Spacing -> Ordering)
-> (Spacing -> Spacing -> Bool)
-> (Spacing -> Spacing -> Bool)
-> (Spacing -> Spacing -> Bool)
-> (Spacing -> Spacing -> Bool)
-> (Spacing -> Spacing -> Spacing)
-> (Spacing -> Spacing -> Spacing)
-> Ord Spacing
Spacing -> Spacing -> Bool
Spacing -> Spacing -> Ordering
Spacing -> Spacing -> Spacing
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: Spacing -> Spacing -> Spacing
$cmin :: Spacing -> Spacing -> Spacing
max :: Spacing -> Spacing -> Spacing
$cmax :: Spacing -> Spacing -> Spacing
>= :: Spacing -> Spacing -> Bool
$c>= :: Spacing -> Spacing -> Bool
> :: Spacing -> Spacing -> Bool
$c> :: Spacing -> Spacing -> Bool
<= :: Spacing -> Spacing -> Bool
$c<= :: Spacing -> Spacing -> Bool
< :: Spacing -> Spacing -> Bool
$c< :: Spacing -> Spacing -> Bool
compare :: Spacing -> Spacing -> Ordering
$ccompare :: Spacing -> Spacing -> Ordering
$cp1Ord :: Eq Spacing
Ord, Int -> Spacing -> ShowS
[Spacing] -> ShowS
Spacing -> String
(Int -> Spacing -> ShowS)
-> (Spacing -> String) -> ([Spacing] -> ShowS) -> Show Spacing
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Spacing] -> ShowS
$cshowList :: [Spacing] -> ShowS
show :: Spacing -> String
$cshow :: Spacing -> String
showsPrec :: Int -> Spacing -> ShowS
$cshowsPrec :: Int -> Spacing -> ShowS
Show)

mkSpacing ::
  Int
  -> Int
  -> Int
  -> Int
  -> Int
  -> Spacing
mkSpacing :: Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
sep Int
n Int
m Int
s Int
r =
  let b :: Int -> Int
b = Int -> Int -> Int
forall a. Ord a => a -> a -> a
max Int
1
  in  Int -> Int -> Int -> Int -> Int -> Spacing
Spacing (Int -> Int
b Int
sep) (Int -> Int
b Int
n) (Int -> Int
b Int
m) (Int -> Int
b Int
s) (Int -> Int
b Int
r)

instance Semigroup Spacing where
  Spacing Int
a1 Int
b1 Int
c1 Int
d1 Int
e1 <> :: Spacing -> Spacing -> Spacing
<> Spacing Int
a2 Int
b2 Int
c2 Int
d2 Int
e2 =
    Int -> Int -> Int -> Int -> Int -> Spacing
Spacing (Int
a1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
a2) (Int
b1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
b2) (Int
c1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
c2) (Int
d1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
d2) (Int
e1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`max` Int
e2)
    
instance Monoid Spacing where
  mappend :: Spacing -> Spacing -> Spacing
mappend =
    Spacing -> Spacing -> Spacing
forall a. Semigroup a => a -> a -> a
(<>)
  mempty :: Spacing
mempty =
    Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
1 Int
1 Int
1 Int
1 Int
1

class HasSpacing a where
  spacing ::
    Lens'
      a
      Spacing
  separatorSpacing ::
    Lens'
      a
      Int
  {-# INLINE separatorSpacing #-}
  separatorSpacing =
    (Spacing -> f Spacing) -> a -> f a
forall a. HasSpacing a => Lens' a Spacing
spacing ((Spacing -> f Spacing) -> a -> f a)
-> ((Int -> f Int) -> Spacing -> f Spacing)
-> (Int -> f Int)
-> a
-> f a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Int -> f Int) -> Spacing -> f Spacing
forall a. HasSpacing a => Lens' a Int
separatorSpacing
  nameSpacing ::
    Lens'
      a
      Int
  {-# INLINE nameSpacing #-}
  nameSpacing =
    (Spacing -> f Spacing) -> a -> f a
forall a. HasSpacing a => Lens' a Spacing
spacing ((Spacing -> f Spacing) -> a -> f a)
-> ((Int -> f Int) -> Spacing -> f Spacing)
-> (Int -> f Int)
-> a
-> f a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Int -> f Int) -> Spacing -> f Spacing
forall a. HasSpacing a => Lens' a Int
nameSpacing
  meaningSpacing ::
    Lens'
      a
      Int
  {-# INLINE meaningSpacing #-}
  meaningSpacing =
    (Spacing -> f Spacing) -> a -> f a
forall a. HasSpacing a => Lens' a Spacing
spacing ((Spacing -> f Spacing) -> a -> f a)
-> ((Int -> f Int) -> Spacing -> f Spacing)
-> (Int -> f Int)
-> a
-> f a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Int -> f Int) -> Spacing -> f Spacing
forall a. HasSpacing a => Lens' a Int
meaningSpacing
  sourceSpacing ::
    Lens'
      a
      Int
  {-# INLINE sourceSpacing #-}
  sourceSpacing =
    (Spacing -> f Spacing) -> a -> f a
forall a. HasSpacing a => Lens' a Spacing
spacing ((Spacing -> f Spacing) -> a -> f a)
-> ((Int -> f Int) -> Spacing -> f Spacing)
-> (Int -> f Int)
-> a
-> f a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Int -> f Int) -> Spacing -> f Spacing
forall a. HasSpacing a => Lens' a Int
sourceSpacing
  scoreSpacing ::
    Lens'
      a
      Int
  {-# INLINE scoreSpacing #-}
  scoreSpacing =
    (Spacing -> f Spacing) -> a -> f a
forall a. HasSpacing a => Lens' a Spacing
spacing ((Spacing -> f Spacing) -> a -> f a)
-> ((Int -> f Int) -> Spacing -> f Spacing)
-> (Int -> f Int)
-> a
-> f a
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. (Int -> f Int) -> Spacing -> f Spacing
forall a. HasSpacing a => Lens' a Int
scoreSpacing
  
instance HasSpacing Spacing where
  spacing :: (Spacing -> f Spacing) -> Spacing -> f Spacing
spacing =
    (Spacing -> f Spacing) -> Spacing -> f Spacing
forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
id
  separatorSpacing :: (Int -> f Int) -> Spacing -> f Spacing
separatorSpacing
    Int -> f Int
f (Spacing Int
a Int
b Int
c Int
d Int
e) =
      (Int -> Spacing) -> f Int -> f Spacing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
x Int
b Int
c Int
d Int
e) (Int -> f Int
f Int
a)
  nameSpacing :: (Int -> f Int) -> Spacing -> f Spacing
nameSpacing
    Int -> f Int
f (Spacing Int
a Int
b Int
c Int
d Int
e) =
      (Int -> Spacing) -> f Int -> f Spacing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
a Int
x Int
c Int
d Int
e) (Int -> f Int
f Int
b)
  meaningSpacing :: (Int -> f Int) -> Spacing -> f Spacing
meaningSpacing
    Int -> f Int
f (Spacing Int
a Int
b Int
c Int
d Int
e) =
      (Int -> Spacing) -> f Int -> f Spacing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
a Int
b Int
x Int
d Int
e) (Int -> f Int
f Int
c)
  sourceSpacing :: (Int -> f Int) -> Spacing -> f Spacing
sourceSpacing
    Int -> f Int
f (Spacing Int
a Int
b Int
c Int
d Int
e) =
      (Int -> Spacing) -> f Int -> f Spacing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
a Int
b Int
c Int
x Int
e) (Int -> f Int
f Int
d)
  scoreSpacing :: (Int -> f Int) -> Spacing -> f Spacing
scoreSpacing
    Int -> f Int
f (Spacing Int
a Int
b Int
c Int
d Int
e) =
      (Int -> Spacing) -> f Int -> f Spacing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Int
x -> Int -> Int -> Int -> Int -> Int -> Spacing
mkSpacing Int
a Int
b Int
c Int
d Int
x) (Int -> f Int
f Int
e)

nameHeader ::
  String
nameHeader :: String
nameHeader =
  String
"NAME"

meaningHeader ::
  String
meaningHeader :: String
meaningHeader =
  String
"MEANING"

sourceHeader ::
  String
sourceHeader :: String
sourceHeader =
  String
"SOURCE"

scoreHeader ::
  String
scoreHeader :: String
scoreHeader =
  String
"SCORE"

standardSpacing ::
  Spacing
standardSpacing :: Spacing
standardSpacing =
  Int -> Int -> Int -> Int -> Int -> Spacing
Spacing
    Int
1
    (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
nameHeader)
    (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
meaningHeader)
    (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
sourceHeader)
    (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
scoreHeader)

exactWidthSpacing ::
  (HasShowScore a, HasAcronym a) =>
  [a]
  -> Spacing
exactWidthSpacing :: [a] -> Spacing
exactWidthSpacing [a]
x =
  Spacing
standardSpacing Spacing -> Spacing -> Spacing
forall a. Semigroup a => a -> a -> a
<>
  (a -> Spacing) -> [a] -> Spacing
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap
    (
      \a
a -> 
        ASetter Spacing Spacing Int Int -> Int -> Spacing -> Spacing
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter Spacing Spacing Int Int
forall a. HasSpacing a => Lens' a Int
nameSpacing (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (a
a a -> Getting String a String -> String
forall s a. s -> Getting a s a -> a
^. Getting String a String
forall c_a8nA. HasAcronym c_a8nA => Lens' c_a8nA String
name)) (Spacing -> Spacing) -> (Spacing -> Spacing) -> Spacing -> Spacing
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        ASetter Spacing Spacing Int Int -> Int -> Spacing -> Spacing
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter Spacing Spacing Int Int
forall a. HasSpacing a => Lens' a Int
meaningSpacing (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (a
a a -> Getting String a String -> String
forall s a. s -> Getting a s a -> a
^. Getting String a String
forall c_a8nA. HasAcronym c_a8nA => Lens' c_a8nA String
meaning)) (Spacing -> Spacing) -> (Spacing -> Spacing) -> Spacing -> Spacing
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        ASetter Spacing Spacing Int Int -> Int -> Spacing -> Spacing
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter Spacing Spacing Int Int
forall a. HasSpacing a => Lens' a Int
sourceSpacing (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (a
a a -> Getting String a String -> String
forall s a. s -> Getting a s a -> a
^. Getting String a String
forall c_a8nA. HasAcronym c_a8nA => Lens' c_a8nA String
source)) (Spacing -> Spacing) -> (Spacing -> Spacing) -> Spacing -> Spacing
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
.
        ASetter Spacing Spacing Int Int -> Int -> Spacing -> Spacing
forall s t a b. ASetter s t a b -> b -> s -> t
set ASetter Spacing Spacing Int Int
forall a. HasSpacing a => Lens' a Int
scoreSpacing (String -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (a
a a -> Getting String a String -> String
forall s a. s -> Getting a s a -> a
^. Getting String a String
forall a. HasShowScore a => Getter a String
showScore))
        (Spacing -> Spacing) -> Spacing -> Spacing
forall a b. (a -> b) -> a -> b
$ Spacing
forall a. Monoid a => a
mempty
    ) [a]
x

(<->) ::
  Spacing
  -> Spacing
  -> Spacing
Spacing Int
a1 Int
b1 Int
c1 Int
d1 Int
e1 <-> :: Spacing -> Spacing -> Spacing
<-> Spacing Int
a2 Int
b2 Int
c2 Int
d2 Int
e2 =
  Int -> Int -> Int -> Int -> Int -> Spacing
Spacing (Int
a1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
a2) (Int
b1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
b2) (Int
c1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
c2) (Int
d1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
d2) (Int
e1 Int -> Int -> Int
forall a. Ord a => a -> a -> a
`min` Int
e2)