{-# LANGUAGE OverloadedStrings, FlexibleInstances, DataKinds,
    ConstraintKinds #-}
-- TODO(joel) rename to React.DOM?
module React.Elements
    (
    -- * Class creation
      classParent
    , classLeaf

    -- * JS Interop
    , exportClassLeaf
    -- , exportNode
    , importLeafClass
    , importParentClass

    , ExportedNode
    , ExportedClass
    ) where

import Control.Applicative
import Data.Aeson as Aeson
import qualified Data.HashMap.Strict as H
import Data.IORef
import Data.Monoid
import Data.String
import Data.Void
import System.IO.Unsafe

import React.Class
import React.GHCJS
import React.Imports
import React.Interpret
import React.Registry
import React.Types


classParent' :: ReactClass props state insig exsig ctx
             -> ReactNode insig
             -> props
             -> ReactNode exsig
classParent' cls children props = ComponentElement
    (ReactComponentElement cls children Nothing Nothing props)


classLeaf' :: ReactClass props state insig exsig ctx
           -> props
           -> ReactNode exsig
classLeaf' cls props = ComponentElement
    (ReactComponentElement cls mempty Nothing Nothing props)


classParent :: ClassCtx ctx
            => ClassConfig props state insig exsig ctx
            -> ReactNode insig
            -> props
            -> ReactNode exsig
classParent = classParent' . createClass


-- TODO refine this type to reflect that it can send back signals
classLeaf :: ClassCtx ctx
          => ClassConfig props state insig exsig ctx
          -> props
          -> ReactNode exsig
classLeaf = classLeaf' . createClass


data ExportedClass_
type ExportedClass = JSRef ExportedClass_

newtype ExportedNode sig = ExportedNode (IO JSAny)

instance ToJSRef (ExportedNode sig) where
    toJSRef (ExportedNode n) = castRef <$> n


-- XXX
-- Must make sure to get componentId to this class! Currently it's in props,
-- but maybe should move...
exportClassLeaf :: ClassCtx ctx
                => ClassConfig props state insig exsig ctx
                -> ExportedClass
exportClassLeaf conf =
    castRef $ classForeign $ createClass conf


-- XXX
-- Must make sure to update state in JS when it changes in HS!
-- exportNode :: (sig -> IO ()) -> ReactNode sig -> ExportedNode sig
-- exportNode handler = ExportedNode . reactNodeToJSAny handler undefined



-- Note: state here reflects the state managed by react-haskell, not the state
-- of the component.
-- TODO - figure out how to handle callbacks (change Void -> a)


importLeafClass :: ToJSRef props
                => ImportedClass props sig
                -> props
                -> ReactNode sig
importLeafClass elem props = ForeignClass elem props mempty



importParentClass :: ToJSRef props
                  => ImportedClass props sig
                  -> props
                  -> ReactNode sig
                  -> ReactNode sig
importParentClass elem props children = ForeignClass elem props children