{-# LANGUAGE OverloadedStrings #-}
module Periodic.Types.WorkerCommand
  ( WorkerCommand (..)
  ) where

import           Data.Int                (Int64)
import           Periodic.Types.Internal
import           Periodic.Types.Job      (FuncName, JobHandle)

import           Data.Binary
import           Data.Binary.Get
import           Data.Binary.Put
import           Data.ByteString         (ByteString)
import qualified Data.ByteString.Char8   as B (length)
import           Data.ByteString.Lazy    (toStrict)

data WorkerCommand = GrabJob
    | SchedLater JobHandle Int64 Int
    | WorkDone JobHandle ByteString
    | WorkFail JobHandle
    | Sleep
    | Ping
    | CanDo FuncName
    | CantDo FuncName
    | Broadcast FuncName
    | Acquire LockName Int JobHandle
    | Release LockName JobHandle
    deriving (Int -> WorkerCommand -> ShowS
[WorkerCommand] -> ShowS
WorkerCommand -> String
(Int -> WorkerCommand -> ShowS)
-> (WorkerCommand -> String)
-> ([WorkerCommand] -> ShowS)
-> Show WorkerCommand
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [WorkerCommand] -> ShowS
$cshowList :: [WorkerCommand] -> ShowS
show :: WorkerCommand -> String
$cshow :: WorkerCommand -> String
showsPrec :: Int -> WorkerCommand -> ShowS
$cshowsPrec :: Int -> WorkerCommand -> ShowS
Show)

instance Binary WorkerCommand where
  get :: Get WorkerCommand
get = do
    Word8
tp <- Get Word8
getWord8
    case Word8
tp of
      1 -> WorkerCommand -> Get WorkerCommand
forall (f :: * -> *) a. Applicative f => a -> f a
pure WorkerCommand
GrabJob
      2 -> do
        JobHandle
jh <- Get JobHandle
forall t. Binary t => Get t
get
        Int64
later <- Get Int64
getInt64be
        Int
step <- Int16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int16 -> Int) -> Get Int16 -> Get Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Int16
getInt16be
        WorkerCommand -> Get WorkerCommand
forall (f :: * -> *) a. Applicative f => a -> f a
pure (JobHandle -> Int64 -> Int -> WorkerCommand
SchedLater JobHandle
jh Int64
later Int
step)
      3 -> do
        JobHandle
jh <- Get JobHandle
forall t. Binary t => Get t
get
        JobHandle -> ByteString -> WorkerCommand
WorkDone JobHandle
jh (ByteString -> WorkerCommand)
-> (ByteString -> ByteString) -> ByteString -> WorkerCommand
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
toStrict (ByteString -> WorkerCommand)
-> Get ByteString -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get ByteString
getRemainingLazyByteString
      4 -> JobHandle -> WorkerCommand
WorkFail (JobHandle -> WorkerCommand) -> Get JobHandle -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get JobHandle
forall t. Binary t => Get t
get
      11 -> WorkerCommand -> Get WorkerCommand
forall (f :: * -> *) a. Applicative f => a -> f a
pure WorkerCommand
Sleep
      9 -> WorkerCommand -> Get WorkerCommand
forall (f :: * -> *) a. Applicative f => a -> f a
pure WorkerCommand
Ping
      7 -> FuncName -> WorkerCommand
CanDo (FuncName -> WorkerCommand) -> Get FuncName -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get FuncName
forall t. Binary t => Get t
get
      8 -> FuncName -> WorkerCommand
CantDo (FuncName -> WorkerCommand) -> Get FuncName -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get FuncName
forall t. Binary t => Get t
get
      21 -> FuncName -> WorkerCommand
Broadcast (FuncName -> WorkerCommand) -> Get FuncName -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get FuncName
forall t. Binary t => Get t
get
      27 -> do
        LockName
n <- Get LockName
forall t. Binary t => Get t
get
        Int
c <- Int16 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int16 -> Int) -> Get Int16 -> Get Int
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get Int16
getInt16be
        LockName -> Int -> JobHandle -> WorkerCommand
Acquire LockName
n Int
c (JobHandle -> WorkerCommand) -> Get JobHandle -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get JobHandle
forall t. Binary t => Get t
get
      28 -> do
        LockName
n <- Get LockName
forall t. Binary t => Get t
get
        LockName -> JobHandle -> WorkerCommand
Release LockName
n (JobHandle -> WorkerCommand) -> Get JobHandle -> Get WorkerCommand
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Get JobHandle
forall t. Binary t => Get t
get
      _ -> String -> Get WorkerCommand
forall a. HasCallStack => String -> a
error (String -> Get WorkerCommand) -> String -> Get WorkerCommand
forall a b. (a -> b) -> a -> b
$ "Error WorkerCommand " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Word8 -> String
forall a. Show a => a -> String
show Word8
tp

  put :: WorkerCommand -> Put
put GrabJob = Word8 -> Put
putWord8 1
  put (SchedLater jh :: JobHandle
jh later :: Int64
later step :: Int
step) = do
    Word8 -> Put
putWord8 2
    JobHandle -> Put
forall t. Binary t => t -> Put
put JobHandle
jh
    Int64 -> Put
putInt64be Int64
later
    Int16 -> Put
putInt16be (Int16 -> Put) -> Int16 -> Put
forall a b. (a -> b) -> a -> b
$ Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
step
  put (WorkDone jh :: JobHandle
jh w :: ByteString
w) = do
    Word8 -> Put
putWord8 3
    JobHandle -> Put
forall t. Binary t => t -> Put
put JobHandle
jh
    ByteString -> Put
putByteString ByteString
w
  put (WorkFail jh :: JobHandle
jh) = do
    Word8 -> Put
putWord8 4
    JobHandle -> Put
forall t. Binary t => t -> Put
put JobHandle
jh
  put Sleep = Word8 -> Put
putWord8 11
  put Ping = Word8 -> Put
putWord8 9
  put (CanDo fn :: FuncName
fn) = do
    Word8 -> Put
putWord8 7
    FuncName -> Put
forall t. Binary t => t -> Put
put FuncName
fn
  put (CantDo fn :: FuncName
fn) = do
    Word8 -> Put
putWord8 8
    FuncName -> Put
forall t. Binary t => t -> Put
put FuncName
fn
  put (Broadcast fn :: FuncName
fn) = do
    Word8 -> Put
putWord8 21
    FuncName -> Put
forall t. Binary t => t -> Put
put FuncName
fn
  put (Acquire n :: LockName
n c :: Int
c jh :: JobHandle
jh) = do
    Word8 -> Put
putWord8 27
    LockName -> Put
forall t. Binary t => t -> Put
put LockName
n
    Int16 -> Put
putInt16be (Int16 -> Put) -> Int16 -> Put
forall a b. (a -> b) -> a -> b
$ Int -> Int16
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
c
    JobHandle -> Put
forall t. Binary t => t -> Put
put JobHandle
jh
  put (Release n :: LockName
n jh :: JobHandle
jh)    = do
    Word8 -> Put
putWord8 28
    LockName -> Put
forall t. Binary t => t -> Put
put LockName
n
    JobHandle -> Put
forall t. Binary t => t -> Put
put JobHandle
jh

instance Validatable WorkerCommand where
  validate :: WorkerCommand -> Either String ()
validate (SchedLater jh :: JobHandle
jh _ step :: Int
step) = do
    JobHandle -> Either String ()
forall a. Validatable a => a -> Either String ()
validate JobHandle
jh
    String -> Int -> Int -> Int -> Either String ()
forall a. Ord a => String -> a -> a -> a -> Either String ()
validateNum "Step" 0 0xFFFF Int
step
  validate (WorkDone jh :: JobHandle
jh w :: ByteString
w) = do
    JobHandle -> Either String ()
forall a. Validatable a => a -> Either String ()
validate JobHandle
jh
    String -> Int32 -> Int32 -> Int -> Either String ()
validateLength "WorkData" 0 Int32
forall a. Bounded a => a
maxBound (Int -> Either String ()) -> Int -> Either String ()
forall a b. (a -> b) -> a -> b
$ ByteString -> Int
B.length ByteString
w
  validate (WorkFail jh :: JobHandle
jh) = JobHandle -> Either String ()
forall a. Validatable a => a -> Either String ()
validate JobHandle
jh
  validate (CanDo fn :: FuncName
fn) = FuncName -> Either String ()
forall a. Validatable a => a -> Either String ()
validate FuncName
fn
  validate (CantDo fn :: FuncName
fn) = FuncName -> Either String ()
forall a. Validatable a => a -> Either String ()
validate FuncName
fn
  validate (Broadcast fn :: FuncName
fn) = FuncName -> Either String ()
forall a. Validatable a => a -> Either String ()
validate FuncName
fn
  validate (Acquire n :: LockName
n c :: Int
c jh :: JobHandle
jh) = do
    LockName -> Either String ()
forall a. Validatable a => a -> Either String ()
validate LockName
n
    String -> Int -> Int -> Int -> Either String ()
forall a. Ord a => String -> a -> a -> a -> Either String ()
validateNum "LockCount" 1 0xFFFF Int
c
    JobHandle -> Either String ()
forall a. Validatable a => a -> Either String ()
validate JobHandle
jh
  validate (Release n :: LockName
n jh :: JobHandle
jh)    = do
    LockName -> Either String ()
forall a. Validatable a => a -> Either String ()
validate LockName
n
    JobHandle -> Either String ()
forall a. Validatable a => a -> Either String ()
validate JobHandle
jh
  validate _               = () -> Either String ()
forall a b. b -> Either a b
Right ()