{-# LANGUAGE TemplateHaskell #-}
{-|
Module: IHP.ServerSideComponent.ControllerFunctions
Copyright: (c) digitally induced GmbH, 2021
-}
module IHP.ServerSideComponent.ControllerFunctions where

import IHP.Prelude
import IHP.ControllerPrelude
import IHP.ServerSideComponent.Types as SSC

import qualified Network.WebSockets as WebSocket
import qualified Text.Blaze.Html.Renderer.Text as Blaze

import qualified Data.Aeson as Aeson
import qualified Data.Aeson.TH as Aeson

import IHP.ServerSideComponent.HtmlParser
import IHP.ServerSideComponent.HtmlDiff

setState :: (?instanceRef :: IORef (ComponentInstance state), ?connection :: WebSocket.Connection, Component state action, ?context :: ControllerContext) => state -> IO ()
setState :: state -> IO ()
setState state
state = do
    state
oldState <- Proxy "state" -> ComponentInstance state -> state
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "state" (Proxy "state")
Proxy "state"
#state (ComponentInstance state -> state)
-> IO (ComponentInstance state) -> IO state
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef (ComponentInstance state) -> IO (ComponentInstance state)
forall a. IORef a -> IO a
readIORef ?instanceRef::IORef (ComponentInstance state)
IORef (ComponentInstance state)
?instanceRef
    let oldHtml :: Text
oldHtml = state
oldState
            state -> (state -> Html) -> Html
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> state -> Html
forall state action. Component state action => state -> Html
SSC.render
            Html -> (Html -> Text) -> Text
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Html -> Text
Blaze.renderHtml
            Text -> (Text -> Text) -> Text
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Text -> Text
forall a b. ConvertibleStrings a b => a -> b
cs
    let newHtml :: Text
newHtml = state
state
            state -> (state -> Html) -> Html
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> state -> Html
forall state action. Component state action => state -> Html
SSC.render
            Html -> (Html -> Text) -> Text
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Html -> Text
Blaze.renderHtml
            Text -> (Text -> Text) -> Text
forall t1 t2. t1 -> (t1 -> t2) -> t2
|> Text -> Text
forall a b. ConvertibleStrings a b => a -> b
cs

    IORef (ComponentInstance state)
-> (ComponentInstance state -> ComponentInstance state) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' ?instanceRef::IORef (ComponentInstance state)
IORef (ComponentInstance state)
?instanceRef (\ComponentInstance state
componentInstance -> ComponentInstance state
componentInstance { state
$sel:state:ComponentInstance :: state
state :: state
state })
    
    case Text -> Text -> Either (ParseErrorBundle Text Void) [NodeOperation]
diffHtml Text
oldHtml Text
newHtml of
        Left ParseErrorBundle Text Void
error -> Text -> IO ()
putStrLn (ParseErrorBundle Text Void -> Text
forall a. Show a => a -> Text
tshow ParseErrorBundle Text Void
error)
        Right [NodeOperation]
patches -> ByteString -> IO ()
forall text.
(?connection::Connection, WebSocketsData text) =>
text -> IO ()
sendTextData ([NodeOperation] -> ByteString
forall a. ToJSON a => a -> ByteString
Aeson.encode [NodeOperation]
patches)


getState :: _ => _
getState :: IO b
getState = Proxy "state" -> model -> b
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "state" (Proxy "state")
Proxy "state"
#state (model -> b) -> IO model -> IO b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> IORef model -> IO model
forall a. IORef a -> IO a
readIORef ?instanceRef::IORef model
IORef model
?instanceRef

deriveSSC :: Name -> Q [Dec]
deriveSSC = Options -> Name -> Q [Dec]
Aeson.deriveJSON Options
Aeson.defaultOptions { sumEncoding :: SumEncoding
sumEncoding = SumEncoding
defaultTaggedObject { tagFieldName :: String
tagFieldName = String
"action", contentsFieldName :: String
contentsFieldName = String
"payload" }}


$(Aeson.deriveJSON Aeson.defaultOptions { sumEncoding = defaultTaggedObject { tagFieldName = "type" }} ''Node)
$(Aeson.deriveJSON Aeson.defaultOptions { sumEncoding = defaultTaggedObject { tagFieldName = "type" }} ''Attribute)
$(Aeson.deriveJSON Aeson.defaultOptions { sumEncoding = defaultTaggedObject { tagFieldName = "type" }} ''NodeOperation)
$(Aeson.deriveJSON Aeson.defaultOptions { sumEncoding = defaultTaggedObject { tagFieldName = "type" }} ''AttributeOperation)