module Dingo.Internal.JavaScript
       ( renderCommandsToJs
       ) where

import           Blaze.ByteString.Builder (toLazyByteString)
import           Data.Aeson (Value)
import           Data.Aeson.Encode (fromValue)
import           Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as LBS
import           Data.Monoid (mconcat)
import           Data.Text (Text)
import qualified Data.Text as TS
import           Data.Text.Lazy.Encoding (encodeUtf8, decodeUtf8)
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TLB
import           Dingo.Internal.Base (Command(..))
import           Dingo.Selector (fromSelector)
import           Text.Blaze (Html, toHtml)
import           Text.Blaze.Renderer.Text (renderHtml)
import           Text.Julius (JavascriptUrl, ToJavascript(..), renderJavascriptUrl, julius)

-- Convert a JSON value to Javascript.
instance ToJavascript Value where
  toJavascript json =
    toJavascript $ decodeUtf8 $ toLazyByteString $ fromValue json

jsHtml :: Html -> TL.Text
jsHtml html = TLB.toLazyText $
  mconcat [ TLB.fromText "'"
          , TLB.fromLazyText $ renderHtml html     -- FIXME: Proper quoting
          , TLB.fromText "'"
          ]

-- Render julius for embedding into julius.
unJulius :: JavascriptUrl Text -> TL.Text
unJulius = renderJavascriptUrl (\_ _ -> TS.empty)

-- Render a command to Javascript.
renderCommandToJs :: Command -> JavascriptUrl Text
renderCommandToJs (CallbackBySelector ev selector callbackId) =
  [julius| $("#{TLB.toLazyText $ fromSelector selector}").#{ev}(function () {
                                               Dingo.callback(#{callbackId});
             }); |]
renderCommandToJs (SetWidgetValue widgetId value) =
  [julius| Dingo.setWidgetValue(#{widgetId}, #{value}); |]
renderCommandToJs (SetTitle title) =
  [julius| document.title = #{jsHtml $ toHtml title}; |]
renderCommandToJs (AppendToWidgetChildren widgetId html) =
  [julius| $("#i#{widgetId}").append(#{jsHtml html}); |]
renderCommandToJs (ReplaceWidgetChildren widgetId html) =
  [julius| $("#i#{widgetId}").html(#{jsHtml html}); |]
renderCommandToJs (HeadMerge html) =
  [julius| $("head").append(#{jsHtml html}); |]
renderCommandToJs (AddEncoderDecoderFunctions widgetId e d) =
  [julius| Dingo.addEncoder(#{widgetId}, #{unJulius e});
            Dingo.addDecoder(#{widgetId}, #{unJulius d}); |]
renderCommandToJs (TriggerEvent widgetId e) =
  [julius| $("#i#{widgetId}").trigger('#{e}'); |]
renderCommandToJs (RawJavascript js) =
  js

-- Render a list of commands to JavaScript
renderCommandsToJs :: [Command] -> ByteString
renderCommandsToJs cs =
  mconcat $ LBS.toChunks $ encodeUtf8 $ unJulius $ mconcat $ map renderCommandToJs cs