{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TemplateHaskell #-}

module Data.Aviation.WB.Weight(
  Weight
, HasWeight(..)
, HasWeights(..)
, SetWeight(..)
, HasWeight0(..)
, kilogramsW
, poundsW
) where

import Control.Category((.))
import Control.Lens(Iso', iso, Lens', Traversal', Setter', makeClassy, iso)
import Data.Aviation.Units(Kilograms(kilograms), Pounds(pounds))
import Data.Eq(Eq)
import Data.Maybe(Maybe)
import Data.Monoid(Monoid(mempty, mappend))
import Data.Ord(Ord)
import Data.Ratio((%))
import Data.Semigroup(Semigroup((<>)))
import Numeric.Lens(multiplying)
import Prelude(Show, Rational, (+))

newtype Weight =
  Weight
    Rational
  deriving (Weight -> Weight -> Bool
(Weight -> Weight -> Bool)
-> (Weight -> Weight -> Bool) -> Eq Weight
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Weight -> Weight -> Bool
$c/= :: Weight -> Weight -> Bool
== :: Weight -> Weight -> Bool
$c== :: Weight -> Weight -> Bool
Eq, Eq Weight
Eq Weight
-> (Weight -> Weight -> Ordering)
-> (Weight -> Weight -> Bool)
-> (Weight -> Weight -> Bool)
-> (Weight -> Weight -> Bool)
-> (Weight -> Weight -> Bool)
-> (Weight -> Weight -> Weight)
-> (Weight -> Weight -> Weight)
-> Ord Weight
Weight -> Weight -> Bool
Weight -> Weight -> Ordering
Weight -> Weight -> Weight
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 :: Weight -> Weight -> Weight
$cmin :: Weight -> Weight -> Weight
max :: Weight -> Weight -> Weight
$cmax :: Weight -> Weight -> Weight
>= :: Weight -> Weight -> Bool
$c>= :: Weight -> Weight -> Bool
> :: Weight -> Weight -> Bool
$c> :: Weight -> Weight -> Bool
<= :: Weight -> Weight -> Bool
$c<= :: Weight -> Weight -> Bool
< :: Weight -> Weight -> Bool
$c< :: Weight -> Weight -> Bool
compare :: Weight -> Weight -> Ordering
$ccompare :: Weight -> Weight -> Ordering
$cp1Ord :: Eq Weight
Ord, Int -> Weight -> ShowS
[Weight] -> ShowS
Weight -> String
(Int -> Weight -> ShowS)
-> (Weight -> String) -> ([Weight] -> ShowS) -> Show Weight
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Weight] -> ShowS
$cshowList :: [Weight] -> ShowS
show :: Weight -> String
$cshow :: Weight -> String
showsPrec :: Int -> Weight -> ShowS
$cshowsPrec :: Int -> Weight -> ShowS
Show)

makeClassy ''Weight

class HasWeights a where
  weights ::
    Traversal'
      a
      Weight

instance HasWeights Weight where
  weights :: (Weight -> f Weight) -> Weight -> f Weight
weights =
    (Weight -> f Weight) -> Weight -> f Weight
forall c. HasWeight c => Lens' c Weight
weight

class SetWeight a where
  setWeight ::
    Setter'
      a
      Weight

instance SetWeight Weight where
  setWeight :: (Weight -> f Weight) -> Weight -> f Weight
setWeight =
    (Weight -> f Weight) -> Weight -> f Weight
forall c. HasWeight c => Lens' c Weight
weight

class HasWeight0 a where
  weight0 ::
    Lens'
      a
      (Maybe Weight)

instance Semigroup Weight where
  <> :: Weight -> Weight -> Weight
(<>) =
    Weight -> Weight -> Weight
forall a. Monoid a => a -> a -> a
mappend

instance Monoid Weight where
  mempty :: Weight
mempty =
    Rational -> Weight
Weight Rational
0
  Weight Rational
w1 mappend :: Weight -> Weight -> Weight
`mappend` Weight Rational
w2 =
    Rational -> Weight
Weight (Rational
w1 Rational -> Rational -> Rational
forall a. Num a => a -> a -> a
+ Rational
w2)

instance Kilograms Weight where
  kilograms :: p Weight (f Weight) -> p Rational (f Rational)
kilograms =
    Rational -> Iso' Rational Rational
forall a. (Fractional a, Eq a) => a -> Iso' a a
multiplying (Integer
22046226218 Integer -> Integer -> Rational
forall a. Integral a => a -> a -> Ratio a
% Integer
10000000000) (p Rational (f Rational) -> p Rational (f Rational))
-> (p Weight (f Weight) -> p Rational (f Rational))
-> p Weight (f Weight)
-> p Rational (f Rational)
forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. p Weight (f Weight) -> p Rational (f Rational)
forall a. Pounds a => Iso' Rational a
pounds

instance Pounds Weight where
  pounds :: p Weight (f Weight) -> p Rational (f Rational)
pounds =
    (Rational -> Weight)
-> (Weight -> Rational) -> Iso' Rational Weight
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso
      Rational -> Weight
Weight
      (\(Weight Rational
x) -> Rational
x)

kilogramsW ::
  Iso'
    Rational
    Weight
kilogramsW :: p Weight (f Weight) -> p Rational (f Rational)
kilogramsW =
  p Weight (f Weight) -> p Rational (f Rational)
forall a. Kilograms a => Iso' Rational a
kilograms
  
poundsW ::
  Iso'
    Rational
    Weight
poundsW :: p Weight (f Weight) -> p Rational (f Rational)
poundsW =
  p Weight (f Weight) -> p Rational (f Rational)
forall a. Pounds a => Iso' Rational a
pounds