module Dingo.Internal.WidgetTypes
       ( Widget(..)
       , WidgetType -- Don't export constructor
       , getWidgetType
       ) where

import Data.Aeson.Types (FromJSON, ToJSON)
import Data.Monoid (mempty)
import Data.Text (Text)
import Data.Typeable (Typeable(..))
import Dingo.Internal.Base (WidgetId)
import Dingo.ResourceBundle (ResourceBundle)
import Text.Blaze (Html)
import Text.Julius (JavascriptUrl)

-- Type class for widgets. Widgets have an associated state type.
class (Typeable c, Typeable s, Show c, FromJSON s, ToJSON s) => Widget c s | c -> s where
  -- | Get the widget ID.
  getWidgetId :: c -> WidgetId
  -- | Render widget to HTML.
  renderWidget :: c -> Html
  -- | Return a JavaScript function to encode state in client to JSON.
  -- The function returned MUST be a nullary function which is invoked
  -- with @this@ set to a jQuery query result containing the widget.
  encodeClientStateJs :: WidgetType c -> JavascriptUrl Text
  -- | Return a JavaScript function to decode state received from the server by
  -- the client. The function receives the encoded state and must
  -- update the client-side widget. The @this@ reference will be a jQuery
  -- query result containing the widget.
  decodeClientStateJs :: WidgetType c -> JavascriptUrl Text
  -- | Print for debugging.
  showWidget :: c -> s -> String
  -- | Supply content for head merge when a widget of type w is first
  -- added to the application.
  headMergeContent :: WidgetType c -> Html
  headMergeContent _ = mempty
  -- | Resources required by a widget of this type.
  widgetResources :: WidgetType c -> [ResourceBundle]
  widgetResources _ = []

-- A type tag for widgets used to make the WidgetMeta type class
-- safer. The phantom type wrapper prevents inappropriate access to
-- widget state.
data WidgetType w = WidgetType ()

-- Get the widget type of a widget.
getWidgetType :: (Widget w s) => w -> WidgetType w
getWidgetType _ = WidgetType ()