module Data.Ron.Value.Internal
    where

import Control.Applicative ((<|>))
import Data.Foldable (msum)
import Data.Maybe (isNothing)
import Data.Ron.Class (ToRon (toRon))
import Data.Text (pack)

import qualified Data.Map.Strict as Map
import qualified Data.Vector as Vector

import Data.Ron.Value

(!==!) :: (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
a
a !==! :: forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! a
b = if a
a a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
b then Maybe (Value, Value)
forall a. Maybe a
Nothing else (Value, Value) -> Maybe (Value, Value)
forall a. a -> Maybe a
Just (a -> Value
forall a. ToRon a => a -> Value
toRon a
a, a -> Value
forall a. ToRon a => a -> Value
toRon a
b)

vshow :: Show a => a -> Value
vshow :: forall a. Show a => a -> Value
vshow = Text -> Value
String (Text -> Value) -> (a -> Text) -> a -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show

similar' :: Value -> Value -> Bool
similar' :: Value -> Value -> Bool
similar' Value
a Value
b = Maybe (Value, Value) -> Bool
forall a. Maybe a -> Bool
isNothing (Maybe (Value, Value) -> Bool) -> Maybe (Value, Value) -> Bool
forall a b. (a -> b) -> a -> b
$ Value -> Value -> Maybe (Value, Value)
similar Value
a Value
b

-- | Like '==' but not precise for floats
similar :: Value -> Value -> Maybe (Value, Value)
similar :: Value -> Value -> Maybe (Value, Value)
similar (Integral Integer
a) (Integral Integer
b) = Integer
a Integer -> Integer -> Maybe (Value, Value)
forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! Integer
b
similar (Floating Scientific
a) (Floating Scientific
b) = if Scientific -> Scientific
forall a. Num a => a -> a
abs (Scientific
a Scientific -> Scientific -> Scientific
forall a. Num a => a -> a -> a
- Scientific
b) Scientific -> Scientific -> Bool
forall a. Ord a => a -> a -> Bool
< Scientific
0.001 then Maybe (Value, Value)
forall a. Maybe a
Nothing else (Value, Value) -> Maybe (Value, Value)
forall a. a -> Maybe a
Just (Scientific -> Value
Floating Scientific
a, Scientific -> Value
Floating Scientific
b)
similar (Char Char
a)     (Char Char
b)     = Char
a Char -> Char -> Maybe (Value, Value)
forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! Char
b
similar (String Text
a)   (String Text
b)   = Text
a Text -> Text -> Maybe (Value, Value)
forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! Text
b
similar (List Vector Value
a)     (List Vector Value
b)     = Vector Value -> Vector Value -> Maybe (Value, Value)
vecSimilar Vector Value
a Vector Value
b
similar (Map Map Value Value
a)      (Map Map Value Value
b)      = Map Value Value -> Map Value Value -> Maybe (Value, Value)
forall k.
(Eq k, Show k) =>
Map k Value -> Map k Value -> Maybe (Value, Value)
mapSimilar Map Value Value
a Map Value Value
b
similar (Unit Text
n)     (Unit Text
m)     = Text
n Text -> Text -> Maybe (Value, Value)
forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! Text
m
similar (Tuple Text
n Vector Value
a)  (Tuple Text
m Vector Value
b)  = (Text
n Text -> Text -> Maybe (Value, Value)
forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! Text
m) Maybe (Value, Value)
-> Maybe (Value, Value) -> Maybe (Value, Value)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Vector Value -> Vector Value -> Maybe (Value, Value)
vecSimilar Vector Value
a Vector Value
b
similar (Record Text
n Map Text Value
a) (Record Text
m Map Text Value
b) = (Text
n Text -> Text -> Maybe (Value, Value)
forall a. (Eq a, ToRon a) => a -> a -> Maybe (Value, Value)
!==! Text
m) Maybe (Value, Value)
-> Maybe (Value, Value) -> Maybe (Value, Value)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Map Text Value -> Map Text Value -> Maybe (Value, Value)
forall k.
(Eq k, Show k) =>
Map k Value -> Map k Value -> Maybe (Value, Value)
mapSimilar Map Text Value
a Map Text Value
b
similar Value
_ Value
_ = (Value, Value) -> Maybe (Value, Value)
forall a. a -> Maybe a
Just (Text -> Value
String Text
"different types", Text -> Value
Unit Text
"")

vecSimilar :: Vector.Vector Value -> Vector.Vector Value -> Maybe (Value, Value)
vecSimilar :: Vector Value -> Vector Value -> Maybe (Value, Value)
vecSimilar Vector Value
a Vector Value
b = Vector (Maybe (Value, Value)) -> Maybe (Value, Value)
forall (t :: * -> *) (m :: * -> *) a.
(Foldable t, MonadPlus m) =>
t (m a) -> m a
msum (Vector (Maybe (Value, Value)) -> Maybe (Value, Value))
-> Vector (Maybe (Value, Value)) -> Maybe (Value, Value)
forall a b. (a -> b) -> a -> b
$ (Value -> Value -> Maybe (Value, Value))
-> Vector Value -> Vector Value -> Vector (Maybe (Value, Value))
forall a b c. (a -> b -> c) -> Vector a -> Vector b -> Vector c
Vector.zipWith Value -> Value -> Maybe (Value, Value)
similar Vector Value
a Vector Value
b

mapSimilar :: (Eq k, Show k) => Map.Map k Value -> Map.Map k Value -> Maybe (Value, Value)
mapSimilar :: forall k.
(Eq k, Show k) =>
Map k Value -> Map k Value -> Maybe (Value, Value)
mapSimilar Map k Value
a Map k Value
b = [(k, Value)] -> [(k, Value)] -> Maybe (Value, Value)
forall {a}.
(Eq a, Show a) =>
[(a, Value)] -> [(a, Value)] -> Maybe (Value, Value)
go (Map k Value -> [(k, Value)]
forall k a. Map k a -> [(k, a)]
Map.toAscList Map k Value
a) (Map k Value -> [(k, Value)]
forall k a. Map k a -> [(k, a)]
Map.toAscList Map k Value
b) where
    go :: [(a, Value)] -> [(a, Value)] -> Maybe (Value, Value)
go [] [] = Maybe (Value, Value)
forall a. Maybe a
Nothing
    go ((a
ak, Value
av):[(a, Value)]
as) ((a
bk, Value
bv):[(a, Value)]
bs) = (if a
ak a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
bk then Maybe (Value, Value)
forall a. Maybe a
Nothing else (Value, Value) -> Maybe (Value, Value)
forall a. a -> Maybe a
Just (a -> Value
forall a. Show a => a -> Value
vshow a
ak, a -> Value
forall a. Show a => a -> Value
vshow a
bk)) Maybe (Value, Value)
-> Maybe (Value, Value) -> Maybe (Value, Value)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> (Value
av Value -> Value -> Maybe (Value, Value)
`similar` Value
bv) Maybe (Value, Value)
-> Maybe (Value, Value) -> Maybe (Value, Value)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> [(a, Value)] -> [(a, Value)] -> Maybe (Value, Value)
go [(a, Value)]
as [(a, Value)]
bs
    go [(a, Value)]
x [(a, Value)]
y = (Value, Value) -> Maybe (Value, Value)
forall a. a -> Maybe a
Just (Int -> Value
forall a. ToRon a => a -> Value
toRon (Int -> Value) -> Int -> Value
forall a b. (a -> b) -> a -> b
$ [(a, Value)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(a, Value)]
x, Int -> Value
forall a. ToRon a => a -> Value
toRon (Int -> Value) -> Int -> Value
forall a b. (a -> b) -> a -> b
$ [(a, Value)] -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [(a, Value)]
y) -- different amount of values