{-# LANGUAGE DoRec #-}
module Hbro.Gui (
    getObject,
    initGUI,
    showWebInspector,
    toggleVisibility
) where

-- {{{ Imports
import Hbro.Core
import Hbro.Util
import qualified Hbro.Prompt as Prompt
import Hbro.Types

import Control.Monad hiding(forM_, mapM_)

--import Data.Foldable
import Data.IORef

import Graphics.Rendering.Pango.Enums
import Graphics.UI.Gtk.Abstract.Container
import Graphics.UI.Gtk.Abstract.Box
import Graphics.UI.Gtk.Abstract.Widget
import Graphics.UI.Gtk.Builder
import Graphics.UI.Gtk.Display.Label
import qualified Graphics.UI.Gtk.General.General as GTK
import Graphics.UI.Gtk.Layout.HBox
import Graphics.UI.Gtk.Layout.VBox
import Graphics.UI.Gtk.Scrolling.ScrolledWindow
import Graphics.UI.Gtk.WebKit.WebInspector
import Graphics.UI.Gtk.WebKit.WebSettings
import Graphics.UI.Gtk.WebKit.WebView hiding(webViewLoadUri)
import Graphics.UI.Gtk.Windows.Window

import Prelude hiding(mapM_)

import System.Console.CmdArgs (whenNormal)
import System.Glib.Attributes
import System.Glib.Signals
import System.Glib.Types
-- }}}

-- Util
-- | Return the casted GObject corresponding to the given name (set in the builder's XML file)
getObject :: GObjectClass a => (GObject -> a) -> String -> K a        
getObject cast name = with (mBuilder . mGUI) $ \builder -> builderGetObject builder cast name

initGUI :: (RefDirs -> FilePath) -> [AttrOp WebSettings] -> IO GUI
initGUI xmlPath settings = do
    void GTK.initGUI
-- Load XML
    xmlPath' <- resolve xmlPath
    whenNormal . putStr . ("Loading GUI from " ++) . (++ "... ") $ xmlPath'
    builder <- builderNew
    builderAddFromFile builder xmlPath'
-- Initialize components
    (webView, sWindow) <- initWebView         builder settings
    (window, wBox)     <- initWindow          builder webView
    promptBar          <- Prompt.init         builder
    statusBar          <- initStatusBar       builder
    notificationBar    <- initNotificationBar builder
    inspectorWindow    <- initWebInspector webView wBox
-- Show window
    widgetShowAll window
    widgetHide (mBox promptBar)
    
    whenNormal $ putStrLn "Done."
    return $ GUI { 
        mWindow          = window, 
        mInspectorWindow = inspectorWindow, 
        mScrollWindow    = sWindow, 
        mWebView         = webView, 
        mPromptBar       = promptBar, 
        mStatusBar       = statusBar, 
        mNotificationBar = notificationBar, 
        mBuilder         = builder
    }

initWebView :: Builder -> [AttrOp WebSettings] -> IO (WebView, ScrolledWindow)
initWebView builder settings = do
-- Initialize ScrolledWindows
    window <- builderGetObject builder castToScrolledWindow "webViewParent"
    scrolledWindowSetPolicy window PolicyNever PolicyNever
-- Initialize WebSettings
    webSettings <- webSettingsNew
    set webSettings settings
-- Initialize WebView
    webView     <- webViewNew
    set webView [ widgetCanDefault := True ]
    webViewSetWebSettings webView webSettings
    containerAdd window webView    
-- 
    _ <- on webView closeWebView $ GTK.mainQuit >> return False
    
    return (webView, window)

initWindow :: Builder -> WebView -> IO (Window, VBox)
initWindow builder webView = do
    window <- builderGetObject builder castToWindow "mainWindow"
    windowSetDefault window $ Just webView
    windowSetDefaultSize window 800 600
    widgetModifyBg window StateNormal (Color 0 0 10000)
    _ <- onDestroy window GTK.mainQuit
    
    box <- builderGetObject builder castToVBox "windowBox"
    
    return (window, box)
    
initStatusBar :: Builder -> IO HBox
initStatusBar builder = builderGetObject builder castToHBox "statusBox"

initNotificationBar :: Builder -> IO NotificationBar
initNotificationBar builder = do
    label <- builderGetObject builder castToLabel "notificationLabel"
    timer <- newIORef Nothing
    return $ NotificationBar label timer

-- {{{ Web inspector
initWebInspector :: WebView -> VBox -> IO (Window)
initWebInspector webView windowBox = do 
    inspector       <- webViewGetInspector webView
    inspectorWindow <- windowNew
    set inspectorWindow [ windowTitle := "hbro | Web inspector" ]

    _ <- on inspector inspectWebView $ \_ -> do
        view <- webViewNew
        containerAdd inspectorWindow view
        return view
    
    _ <- on inspector showWindow $ do
        widgetShowAll inspectorWindow
        return True

-- TODO: when does this signal happen ?!
    --_ <- on inspector finished $ return ()

-- Attach inspector to browser's main window
    _ <- on inspector attachWindow $ do
        getWebView <- webInspectorGetWebView inspector
        case getWebView of
            Just view -> do 
                widgetHide inspectorWindow
                containerRemove inspectorWindow view
                widgetSetSizeRequest view (-1) 250
                boxPackEnd windowBox view PackNatural 0
                widgetShow view
                return True
            _ -> return False

-- Detach inspector in a distinct window
    _ <- on inspector detachWindow $ do
        getWebView <- webInspectorGetWebView inspector
        _ <- case getWebView of
            Just view -> do
                containerRemove windowBox view
                containerAdd inspectorWindow view
                widgetShowAll inspectorWindow
                return True
            _ -> return False
        
        widgetShowAll inspectorWindow
        return True

    return inspectorWindow

-- | Show web inspector for current webpage.
showWebInspector :: K ()
showWebInspector = do
    inspector <- with (mWebView . mGUI) webViewGetInspector
    io $ webInspectorInspectCoordinates inspector 0 0
-- }}}


-- {{{ Util
-- | Toggle a widget's visibility (provided for convenience).
toggleVisibility :: WidgetClass a => a -> IO ()
toggleVisibility widget = do
    visibility <- get widget widgetVisible
    case visibility of
        False -> widgetShow widget
        _     -> widgetHide widget
-- }}}