module Rattletrap.Type.RemoteId.PsyNet where

import qualified Control.Applicative as Applicative
import qualified Rattletrap.BitGet as BitGet
import qualified Rattletrap.BitPut as BitPut
import qualified Rattletrap.Schema as Schema
import qualified Rattletrap.Type.U64 as U64
import qualified Rattletrap.Type.Version as Version
import qualified Rattletrap.Utility.Json as Json

data PsyNet
  = New U64.U64
  | Old U64.U64 U64.U64 U64.U64 U64.U64
  deriving (PsyNet -> PsyNet -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: PsyNet -> PsyNet -> Bool
$c/= :: PsyNet -> PsyNet -> Bool
== :: PsyNet -> PsyNet -> Bool
$c== :: PsyNet -> PsyNet -> Bool
Eq, Int -> PsyNet -> ShowS
[PsyNet] -> ShowS
PsyNet -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [PsyNet] -> ShowS
$cshowList :: [PsyNet] -> ShowS
show :: PsyNet -> String
$cshow :: PsyNet -> String
showsPrec :: Int -> PsyNet -> ShowS
$cshowsPrec :: Int -> PsyNet -> ShowS
Show)

instance Json.FromJSON PsyNet where
  parseJSON :: Value -> Parser PsyNet
parseJSON = forall a. String -> (Object -> Parser a) -> Value -> Parser a
Json.withObject String
"PsyNet" forall a b. (a -> b) -> a -> b
$ \Object
object -> do
    let new :: Parser PsyNet
new = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap U64 -> PsyNet
New forall a b. (a -> b) -> a -> b
$ forall value. FromJSON value => Object -> String -> Parser value
Json.required Object
object String
"Left"
        old :: Parser PsyNet
old = do
          (U64
a, U64
b, U64
c, U64
d) <- forall value. FromJSON value => Object -> String -> Parser value
Json.required Object
object String
"Right"
          forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ U64 -> U64 -> U64 -> U64 -> PsyNet
Old U64
a U64
b U64
c U64
d
    Parser PsyNet
new forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
Applicative.<|> Parser PsyNet
old

instance Json.ToJSON PsyNet where
  toJSON :: PsyNet -> Value
toJSON PsyNet
x = case PsyNet
x of
    New U64
a -> [(Key, Value)] -> Value
Json.object [forall value pair.
(ToJSON value, KeyValue pair) =>
String -> value -> pair
Json.pair String
"Left" U64
a]
    Old U64
a U64
b U64
c U64
d -> [(Key, Value)] -> Value
Json.object [forall value pair.
(ToJSON value, KeyValue pair) =>
String -> value -> pair
Json.pair String
"Right" (U64
a, U64
b, U64
c, U64
d)]

schema :: Schema.Schema
schema :: Schema
schema =
  String -> Value -> Schema
Schema.named String
"remote-id-psy-net" forall a b. (a -> b) -> a -> b
$
    [Value] -> Value
Schema.oneOf
      [ [((Key, Value), Bool)] -> Value
Schema.object [(forall value pair.
(ToJSON value, KeyValue pair) =>
String -> value -> pair
Json.pair String
"Left" forall a b. (a -> b) -> a -> b
$ Schema -> Value
Schema.ref Schema
U64.schema, Bool
True)],
        [((Key, Value), Bool)] -> Value
Schema.object
          [ ( forall value pair.
(ToJSON value, KeyValue pair) =>
String -> value -> pair
Json.pair String
"Right" forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Value] -> Value
Schema.tuple forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Int -> a -> [a]
replicate Int
4 forall a b. (a -> b) -> a -> b
$ Schema -> Value
Schema.ref Schema
U64.schema,
              Bool
True
            )
          ]
      ]

bitPut :: PsyNet -> BitPut.BitPut
bitPut :: PsyNet -> BitPut
bitPut PsyNet
x = case PsyNet
x of
  New U64
l -> U64 -> BitPut
U64.bitPut U64
l
  Old U64
a U64
b U64
c U64
d -> U64 -> BitPut
U64.bitPut U64
a forall a. Semigroup a => a -> a -> a
<> U64 -> BitPut
U64.bitPut U64
b forall a. Semigroup a => a -> a -> a
<> U64 -> BitPut
U64.bitPut U64
c forall a. Semigroup a => a -> a -> a
<> U64 -> BitPut
U64.bitPut U64
d

bitGet :: Version.Version -> BitGet.BitGet PsyNet
bitGet :: Version -> BitGet PsyNet
bitGet Version
version =
  forall a. String -> BitGet a -> BitGet a
BitGet.label String
"PsyNet" forall a b. (a -> b) -> a -> b
$
    if Int -> Int -> Int -> Version -> Bool
Version.atLeast Int
868 Int
24 Int
10 Version
version
      then forall a. String -> BitGet a -> BitGet a
BitGet.label String
"New" forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap U64 -> PsyNet
New BitGet U64
U64.bitGet
      else forall a. String -> BitGet a -> BitGet a
BitGet.label String
"Old" forall a b. (a -> b) -> a -> b
$ do
        U64
a <- BitGet U64
U64.bitGet
        U64
b <- BitGet U64
U64.bitGet
        U64
c <- BitGet U64
U64.bitGet
        U64
d <- BitGet U64
U64.bitGet
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ U64 -> U64 -> U64 -> U64 -> PsyNet
Old U64
a U64
b U64
c U64
d