{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Glazier.React.Component.Internal
    ( ShimComponent(..) -- constructor exported
    , shimComponent
    , rerenderShim
    , ComponentRef(..) -- constructor exported
    ) where

import Control.DeepSeq
import Data.String
import qualified GHC.Generics as G
import qualified GHCJS.Marshal.Pure as J
import qualified GHCJS.Types as J
import qualified JavaScript.Extras as JE

-- | Returns a reference to the javascript *class* definition
-- of the shim wrapper around ReactPureComponent
newtype ShimComponent = ShimComponent JE.JSRep
    deriving (G.Generic, Show, J.IsJSVal, J.PToJSVal, JE.ToJS, IsString, NFData)

-- | This returns the javascript class definition of ShimComponent.
-- There is ever only one shim class, so it is purely available
shimComponent :: ShimComponent
shimComponent = ShimComponent js_shimComponent

-- | Rerenders an instance of a component created using ShimComponent.
rerenderShim :: ComponentRef -> IO ()
rerenderShim = js_rerenderShim

-- | This is used store the react "ref" to a javascript instance of a react Component.
newtype ComponentRef = ComponentRef JE.JSRep
    deriving (G.Generic, Show, J.IsJSVal, J.PToJSVal, JE.ToJS, IsString, NFData)

instance JE.FromJS ComponentRef where
    fromJS a | js_isReactComponent a = Just $ ComponentRef $ JE.JSRep a
    fromJS _ = Nothing

#ifdef __GHCJS__

foreign import javascript unsafe
  "$r = hgr$shimComponent();"
  js_shimComponent :: JE.JSRep

-- !!blah is javascript way of converting to bool
-- using undocumented api to check if something is react component
-- https://stackoverflow.com/questions/33199959/how-to-detect-a-react-component-vs-a-react-element
foreign import javascript unsafe
    "!(!($1 && !(!($1['isReactComponent']))))"
    js_isReactComponent :: J.JSVal -> Bool

foreign import javascript unsafe
  "if ($1 && $1['rerender']) { $1['rerender']() };"
  js_rerenderShim :: ComponentRef -> IO ()

#else

js_shimComponent :: JE.JSRep
js_shimComponent = JE.JSRep J.nullRef

js_isReactComponent :: J.JSVal -> Bool
js_isReactComponent _ = False

js_rerenderShim :: ComponentRef -> IO ()
js_rerenderShim _ = pure ()

#endif